diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..926a6b63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/src/python/bf2/logs/*.log +/src/python/bf2/logs/snapshots/sent/*.json +/src/python/bf2/logs/snapshots/unsent/*.json diff --git a/src/python/bf2/.gitignore b/src/python/bf2/.gitignore new file mode 100644 index 00000000..83f5b9fc --- /dev/null +++ b/src/python/bf2/.gitignore @@ -0,0 +1 @@ +logs/*.log \ No newline at end of file diff --git a/src/python/bf2/BF2StatisticsConfig.py b/src/python/bf2/BF2StatisticsConfig.py new file mode 100644 index 00000000..62925d4a --- /dev/null +++ b/src/python/bf2/BF2StatisticsConfig.py @@ -0,0 +1,69 @@ +# ------------------------------------------------------------------------------ +# BF2Statistics 3.0.0 - Config File +# ------------------------------------------------------------------------------ +# Conventions: +# 0 -> Disable +# 1 -> Enable +# ------------------------------------------------------------------------------ + +# ------------------------------------------------------------------------------ +# Debug Logging +# ------------------------------------------------------------------------------ +debug_enable = 1 +debug_log_path = 'python/bf2/logs' # Relative from BF2 base folder +debug_fraglog_enable = 0 # Detailed 'Fragalyzer' Logs (requires existing folder "mods//logs/") + +# ------------------------------------------------------------------------------ +# Statistics Enabling +# ------------------------------------------------------------------------------ +# 0 = disable statistics, 1 = enable statistics (requires an ASP stats server) +# By disabling the stats, this server will be "non-ranked" +# +# An AuthID and AuthToken are required to post stats data to the ASP backend. +# Contact your local Stats Admin to recieve an AuthID and AuthToken. Both of +# which are NOT to be shared with anyone! +# ------------------------------------------------------------------------------ +stats_enable = 1 +stats_auth_id = 112960 # Required to post stats data at the end of round. +stats_auth_token = '2GS61JLR2WQq2n6N' # Required to post stats data at the end of round. + +# ------------------------------------------------------------------------------ +# ASP Stats Backend Web Server +# ------------------------------------------------------------------------------ +http_backend_addr = '127.0.0.1' +http_backend_port = 80 +http_backend_asp = '/ASP/bf2statistics.php' + +# ------------------------------------------------------------------------------ +# Snapshot Logging +# ------------------------------------------------------------------------------ +# Enables server to make snapshot backups. +# 0 = log only on error sending to backend +# 1 = all snapshots +# ------------------------------------------------------------------------------ +snapshot_logging = 0 +snapshot_log_path_sent = 'python/bf2/logs/snapshots/sent' # Relative from the BF2 base folder +snapshot_log_path_unsent = 'python/bf2/logs/snapshots/unsent' # Relative from the BF2 base folder + +# ------------------------------------------------------------------------------ +# Medals Processing +# ------------------------------------------------------------------------------ +# Suffix for your custom medals file(s). +# Example: A profile named "custom" = medal_data_custom.py +# ------------------------------------------------------------------------------ +medals_custom_data = 'custom' +# A list of mods that xpack (special forces) medals can be earned while playing +# Example: ['mods/xpack', 'mods/bf2', 'mods/ModName'] (all entries must be lower case!!) +medals_xpack_mods = ['mods/bf2sfsp','mods/xpack'] + +# ------------------------------------------------------------------------------ +# Player Manager +# ------------------------------------------------------------------------------ +# Local IP address for AI Bots +# ------------------------------------------------------------------------------ +pm_ai_player_addr = '127.0.0.1' # Not recommended to change + + +# ------------------------------------------------------------------------------ +# END CONFIGURATION +# ------------------------------------------------------------------------------ \ No newline at end of file diff --git a/src/python/bf2/GameLogic.py b/src/python/bf2/GameLogic.py new file mode 100644 index 00000000..d66136a0 --- /dev/null +++ b/src/python/bf2/GameLogic.py @@ -0,0 +1,72 @@ +# game logic + + +import host + +class GameLogic: + def __init__(self): + print "GameLogic created" + + def getModDir(self): return host.sgl_getModDirectory() + def getMapName(self): return host.sgl_getMapName() + def getWorldSize(self): return host.sgl_getWorldSize() + def getTeamName(self, team): return host.sgl_getParam('teamName', team, 0) + def isAIGame(self): return host.sgl_getIsAIGame() + + def sendClientCommand(self, playerId, command, args): return host.sgl_sendPythonEvent(playerId, command, args) + def sendGameEvent(self, player, event, data): return host.sgl_sendGameLogicEvent(player.index, event, data) + def sendMedalEvent(self, player, type, value): return host.sgl_sendMedalEvent(player.index, type, value) + def sendRankEvent(self, player, rank, score): return host.sgl_sendRankEvent(player.index, rank, score) + def sendHudEvent(self, player, event, data): return host.sgl_sendHudEvent(player.index, event, data) + + def sendServerMessage(self, playerId, message): return host.sgl_sendTextMessage(playerId, 10, 1, message) + + def getTicketState(self, team): return host.sgl_getParam('ticketState', team, 0) + def setTicketState(self, team, value): return host.sgl_setParam('ticketState', team, value, 0) + + def getTickets(self, team): return host.sgl_getParam('tickets', team, 0) + def setTickets(self, team, value): return host.sgl_setParam('tickets', team, value, 0) + + def getDefaultTickets(self, team): return host.sgl_getParam('startTickets', team, 0) + + def getTicketChangePerSecond(self, team): return host.sgl_getParam('ticketChangePerSecond', team, 0, 0) + def setTicketChangePerSecond(self, team, value): return host.sgl_setParam('ticketChangePerSecond', team, value, 0) + + def getTicketLimit(self, team, id): return host.sgl_getParam('ticketLimit', team, id) + def setTicketLimit(self, team, id, value): return host.sgl_setParam('ticketLimit', team, id, value) + + def getDefaultTicketLossPerMin(self, team): return host.sgl_getParam('defaultTicketLossPerMin', team, 0) + def getDefaultTicketLossAtEndPerMin(self): return host.sgl_getParam('defaultTicketLossAtEndPerMin', 0, 0) + + def getWinner(self): return host.sgl_getParam('winner', 0, 0) + def getVictoryType(self): return host.sgl_getParam('victoryType', 0, 0) + + def setHealPointLimit(self, value): return host.sgl_setParam('healScoreLimit', 0, value, 0) + def setRepairPointLimit(self, value): return host.sgl_setParam('repairScoreLimit', 0, value, 0) + def setGiveAmmoPointLimit(self, value): return host.sgl_setParam('giveAmmoScoreLimit', 0, value, 0) + def setTeamDamagePointLimit(self, value): return host.sgl_setParam('teamDamageScoreLimit', 0, value, 0) + def setTeamVehicleDamagePointLimit(self, value): return host.sgl_setParam('teamVehicleDamageScoreLimit', 0, value, 0) + + +class ServerSettings: + def __init__(self): + print "Serversettings created" + + def getTicketRatio(self): return host.ss_getParam('ticketRatio') + def getTeamRatioPercent(self): return host.ss_getParam('teamRatioPct') + def getMaxPlayers(self): return host.ss_getParam('maxPlayers') + def getGameMode(self): return host.ss_getParam('gameMode') + def getMapName(self): return host.ss_getParam('mapName') + def getTimeLimit(self): return host.ss_getParam('timeLimit') + def getScoreLimit(self): return host.ss_getParam('scoreLimit') + def getAutoBalanceTeam(self): return host.ss_getParam('autoBalance') + def getTKPunishEnabled(self): return host.ss_getParam('tkpEnabled') + def getTKNumPunishToKick(self): return host.ss_getParam('tkpNeeded') + def getTKPunishByDefault(self): return host.ss_getParam('tkpDefault') + + def getUseGlobalRank(self): return host.ss_getParam('globRank') + def getUseGlobalUnlocks(self): return host.ss_getParam('globUnlocks') + + def getServerConfig(self, variableName): + return host.rcon_invoke(variableName).strip() + diff --git a/src/python/bf2/ObjectManager.py b/src/python/bf2/ObjectManager.py new file mode 100644 index 00000000..8d116ef0 --- /dev/null +++ b/src/python/bf2/ObjectManager.py @@ -0,0 +1,20 @@ +import host + + +class ObjectManager: + def __init__(self): + print "ObjectManager created" + + def getObjectsOfType(self, type): + return host.omgr_getObjectsOfType(type) + + def getObjectsOfTemplate(self, templ): + return host.omgr_getObjectsOfTemplate(templ) + + def getRootParent(self, obj): + parent = obj.getParent() + + if parent == None: + return obj + + return self.getRootParent(parent) diff --git a/src/python/bf2/PlayerManager.py b/src/python/bf2/PlayerManager.py new file mode 100644 index 00000000..d09e6d87 --- /dev/null +++ b/src/python/bf2/PlayerManager.py @@ -0,0 +1,255 @@ + +import host +import string +from time import time +from bf2 import g_debug + + +# Import Config Data +from bf2.BF2StatisticsConfig import stats_enable, http_backend_addr, http_backend_port +# Use MiniClient +from bf2.stats.miniclient import miniclient, http_get + +# ingame scoremanager link +ingameScores = ( + 'deaths', + 'kills', + 'TKs', + 'score', + 'skillScore', + 'rplScore', + 'cmdScore', + 'fracScore', + 'rank', + 'firstPlace', + 'secondPlace', + 'thirdPlace', + 'bulletsFired', + 'bulletsGivingDamage', + 'bulletsFiredAndClear', + 'bulletsGivingDamageAndClear' +) + +class PlayerScore: + def __init__(self, index): + self.__dict__['index'] = index + self.reset() + + def reset(self): + # these scores are only tracked in script + self.__dict__['heals'] = 0 + self.__dict__['ammos'] = 0 + self.__dict__['repairs'] = 0 + self.__dict__['damageAssists'] = 0 + self.__dict__['passengerAssists'] = 0 + self.__dict__['driverAssists'] = 0 + self.__dict__['targetAssists'] = 0 + self.__dict__['driverSpecials'] = 0 + self.__dict__['revives'] = 0 + self.__dict__['teamDamages'] = 0 + self.__dict__['teamVehicleDamages'] = 0 + self.__dict__['cpCaptures'] = 0 + self.__dict__['cpDefends'] = 0 + self.__dict__['cpAssists'] = 0 + self.__dict__['suicides'] = 0 + self.__dict__['cpNeutralizes'] = 0 + self.__dict__['cpNeutralizeAssists'] = 0 + + def __getattr__(self, name): + if name in self.__dict__: return self.__dict__[name] + elif name == 'dkRatio': + kills = host.pmgr_getScore(self.index, 'kills') + if kills == 0: + # div by zero is undefined -> 0:0 = 1 1:0 = 2 1:1 = 1 + return 1.0 * host.pmgr_getScore(self.index, 'deaths') + 1 + else: + return 1.0 * host.pmgr_getScore(self.index, 'deaths') / kills + elif name in ingameScores: + return host.pmgr_getScore(self.index, name) + else: + raise AttributeError, name + + def __setattr__(self, name, value): + if name in self.__dict__: + self.__dict__[name] = value + return None + elif name in ingameScores: + return host.pmgr_setScore(self.index, name, value) + else: + raise AttributeError, name + + + +class Player: + def __init__(self, index): + print "Player Manager module initialized" + self.index = index + self.score = PlayerScore(index) + self.profileid = 0 + self.GlobalUpdateTime = 0 + + + def isValid(self): return host.pmgr_isIndexValid(self.index) + def isRemote(self): return host.pmgr_p_get("remote", self.index) + def isAIPlayer(self): return host.pmgr_p_get("ai", self.index) + def isAlive(self): return host.pmgr_p_get("alive", self.index) + def isManDown(self): return host.pmgr_p_get("mandown", self.index) + def isConnected(self): return host.pmgr_p_get("connected", self.index) + + +# Added by Chump - for bf2statistics stats +# ------------------------------------------------------------------------------ +# omero 2006-03-31 +# ------------------------------------------------------------------------------ +# using pm_local_pid_txt_file imported from BF2StatisticsConfig module +# for reading Nick/pID mappings. +# ------------------------------------------------------------------------------ +# Wilson212, 2015-02-17 +# ------------------------------------------------------------------------------ +# Removed the method of fetching the pid from the pid.txt file. As omero has coded +# after the fact, the pid is now fetched from the back end, and has rendered the local +# pid text file obsolete. This also prevents pid clashes when using more then 1 server +# on an ASP back end server +# ------------------------------------------------------------------------------ + def getProfileId(self): + # No stats, Then we dont bother fetching Pid from ASP + if not stats_enable: + return host.pmgr_p_get("profileid", self.index) + + pid = self.profileid + + # If we are a human player, attempt to get PID from the bf2 server + if not host.pmgr_p_get("ai", self.index) and pid == 0: + pid = int(host.pmgr_p_get("profileid", self.index)) + + # If we don't have a PID up to this point, fetch it from ASP back end + if pid == 0: + if g_debug: print "Retrieving Profile ID (%s) via HTTP/1.1 miniclient" % str(host.pmgr_p_get("name", self.index)) + + # URL for retrieving player ID via internal miniclient + player_nick = string.replace(str(host.pmgr_p_get("name", self.index)), ' ', '%20') + asp_playerid = '/ASP/getplayerid.aspx?nick=' + player_nick + '&ai=' + str(host.pmgr_p_get("ai", self.index)) + if g_debug: print "URI: %s" % (asp_playerid) + + # Fetch Data using miniclient + data = http_get( http_backend_addr, http_backend_port, asp_playerid ) + if data and data[0] == 'O': + if g_debug: print "Received PID data is VALID, length %d" % int(len(data)) + datalines = data.splitlines() + pidval = datalines[2].split('\t') + pid = int(pidval[1]) + else: + print "Received PID data is INVALID, length %d" % int(len(data)) + + self.profileid = pid + return pid + + def isFlagHolder(self): return host.pmgr_p_get("fholder", self.index) + + def getTeam(self): return host.pmgr_p_get("team", self.index) + def setTeam(self, t): return host.pmgr_p_set("team", self.index, t) + def getPing(self): return host.pmgr_p_get("ping", self.index) + + def getSuicide(self): return host.pmgr_p_get("suicide", self.index) + def setSuicide(self, t): return host.pmgr_p_set("suicide", self.index, t) + + def getTimeToSpawn(self): return host.pmgr_p_get("tts", self.index) + def setTimeToSpawn(self, t): return host.pmgr_p_set("tts", self.index, t) + + def getSquadId(self): return host.pmgr_p_get("sqid", self.index) + def isSquadLeader(self): return host.pmgr_p_get("isql", self.index) + def isCommander(self): return host.pmgr_p_get("commander", self.index) + + def getName(self): return host.pmgr_p_get("name", self.index) + def setName(self, name): return host.pmgr_p_set("name", self.index, name) + + def getSpawnGroup(self): return host.pmgr_p_get("sgr", self.index) + def setSpawnGroup(self, t): return host.pmgr_p_set("sgr", self.index, t) + + def getKit(self): return host.pmgr_p_get("kit", self.index) + def getVehicle(self): return host.pmgr_p_get("vehicle", self.index) + def getDefaultVehicle(self): return host.pmgr_p_get("defaultvehicle", self.index) + def getPrimaryWeapon(self): return host.pmgr_p_get("weapon", self.index, 0) + + def getAddress(self): return host.pmgr_p_get("addr", self.index) + + def setIsInsideCP(self, val): return host.pmgr_p_set("isInsideCP", self.index, val) + def getIsInsideCP(self): return host.pmgr_p_get("isInsideCP", self.index) + + # Functions used to stop STATS "update storm" + def setGlobalUpdateTime(self): + self.GlobalUpdateTime = time() + return self.GlobalUpdateTime + def getGlobalUpdateTime(self): return (time() - self.GlobalUpdateTime) + +class PlayerManager: + def __init__(self): + print "PlayerManager created" + self._pcache = {} + + def getNumberOfPlayers(self): + return host.pmgr_getNumberOfPlayers() + + def getCommander(self, team): + return self.getPlayerByIndex(host.pmgr_getCommander(team)) + + def getPlayers(self): + indices = host.pmgr_getPlayers() + players = [] + # NOTE: this uses getPlayerByIndex so we return cached player objects + # whenever we can + for i in indices: players.append(self.getPlayerByIndex(i)) + return players + + def getPlayerByIndex(self, index): + # dep: this uses a cache so that all references to a certain player + # index will always yield the same object, which is useful because you + # can then test them for object equality + valid = host.pmgr_isIndexValid(index) + if not valid: + if self._pcache.has_key(index): + print "Removed player index %d from player cache" % index + del self._pcache[index] + return None + if not self._pcache.has_key(index): + self._pcache[index] = Player(index) + return self._pcache[index] + + def getNextPlayer(self, index): + startIndex = index + p = None + index = index + 1 + while p == None and index != startIndex: + p = self.getPlayerByIndex(index) + index = index + 1 + if index > 255: index = 0 + if index > 63: index = 255 + + if not p: + return self.getPlayerByIndex(startIndex) + else: + return p + + def getNumberOfPlayersInTeam(self, team): + players = self.getPlayers() + inTeam = 0 + for p in players: + if p.getTeam() == team: + inTeam += 1 + + return inTeam + + def getNumberOfAlivePlayersInTeam(self, team): + players = self.getPlayers() + inTeam = 0 + for p in players: + if p.getTeam() == team and p.isAlive(): + inTeam += 1 + + return inTeam + + # allows temporary disabling of the onPlayerScore event. + def enableScoreEvents(self): + return host.pmgr_enableScoreEvents(1) + def disableScoreEvents(self): + return host.pmgr_enableScoreEvents(0) \ No newline at end of file diff --git a/src/python/bf2/Timer.py b/src/python/bf2/Timer.py new file mode 100644 index 00000000..e5ec3a5f --- /dev/null +++ b/src/python/bf2/Timer.py @@ -0,0 +1,31 @@ + +import host + +class Timer: + + def __init__(self, targetFunc, delta, alwaysTrigger, data=None): + self.targetFunc = targetFunc + self.data = data + self.time = host.timer_getWallTime() + delta + self.interval = 0.0 + self.alwaysTrigger = alwaysTrigger + host.timer_created(self) + + def __del__(self): + print "Timer object destroyed (rc 0)" + + def destroy(self): + host.timer_destroy(self) + + def getTime(self): + return self.time + + def setTime(self, time): + self.time = time + + def setRecurring(self, interval): + self.interval = interval + + def onTrigger(self): + self.targetFunc(self.data) + diff --git a/src/python/bf2/TriggerManager.py b/src/python/bf2/TriggerManager.py new file mode 100644 index 00000000..cc518ff5 --- /dev/null +++ b/src/python/bf2/TriggerManager.py @@ -0,0 +1,19 @@ +import host + +class TriggerManager: + + def createRadiusTrigger(self, object, callback, objName, radius, data=None): + return host.trig_create(object, callback, objName, radius, 0, data) + + def createHemiSphericalTrigger(self, object, callback, objName, radius, data=None): + return host.trig_create(object, callback, objName, radius, 1, data) + + def destroyAllTriggers(self): + host.trig_destroyAll() + + def destroy(self, trig_id): + host.trig_destroy(trig_id) + + def getObjects(self, trig_id): + return host.trig_getObjects(trig_id) + diff --git a/src/python/bf2/VerifyPlayer.py b/src/python/bf2/VerifyPlayer.py new file mode 100644 index 00000000..68c23e8b --- /dev/null +++ b/src/python/bf2/VerifyPlayer.py @@ -0,0 +1,49 @@ +# +# This script is used to prevent Cross Service Exploitation between Gamespy Service Providers +# + +import host +import string +from bf2.BF2StatisticsConfig import http_backend_addr, http_backend_port +from bf2.stats.miniclient import miniclient, http_get +from bf2 import g_debug + +def init(): + print "Player Verify module initialized" + host.registerHandler('PlayerConnect', onPlayerConnect, 1) + + +def onPlayerConnect(aPlayer): + + # Ignore AI players + if aPlayer.isAIPlayer(): + return + + #if g_debug: + player_nick = string.replace(aPlayer.getName(), ' ', '%20') + asp_URI = '/ASP/verifyplayer.aspx?pid=%d&nick=%s' % ( int(aPlayer.getProfileId()), player_nick ) + + # Run check + print "Running CSE Verification Check on Player (%s)" % str(aPlayer.getName()) + if g_debug: print "URI: %s" % (asp_URI) + data = http_get( http_backend_addr, http_backend_port, asp_URI ) + + if data and data[0] == 'O': + + # Split the response into an array + datalines = data.splitlines() + + # Parse result and message + items = datalines[2].split('\t') + result = str(items[1]) + message = str(items[2]) + + #if g_debug: + print "Backend CSE Response on Player (%s): %s - %s " % (str(aPlayer.getName()), str(result), str(message)) + + # Is player OK? + if (result == "NOK"): host.rcon_invoke('admin.kickPlayer ' + str(aPlayer.index)) + + else: + print "Backend CSE Response on Player (%s) is INVALID, length %d" % int(len(data)) + \ No newline at end of file diff --git a/src/python/bf2/__init__.py b/src/python/bf2/__init__.py new file mode 100644 index 00000000..b64c9b69 --- /dev/null +++ b/src/python/bf2/__init__.py @@ -0,0 +1,160 @@ +import host +import sys + +from time import localtime, strftime +from bf2.Timer import Timer +from BF2StatisticsConfig import stats_enable, debug_enable, debug_log_path + +class GameStatus: + Playing = 1 + EndGame = 2 + PreGame = 3 + Paused = 4 + RestartServer = 5 + NotConnected = 6 + +playerManager = None +objectManager = None +triggerManager = None +gameLogic = None +serverSettings = None + +# ------------------------------------------------------------------------------ +# omero 2005-11-19 +# ------------------------------------------------------------------------------ +# CONFIGURATION SECTION +# ------------------------------------------------------------------------------ +# To enable/disable printing of debug messages in (all) python modules +# ------------------------------------------------------------------------------ +g_debug = debug_enable + +# set up singletons +import bf2.PlayerManager +import bf2.ObjectManager +import bf2.TriggerManager +import bf2.GameLogic +playerManager = bf2.PlayerManager.PlayerManager() +objectManager = bf2.ObjectManager.ObjectManager() +triggerManager = bf2.TriggerManager.TriggerManager() +gameLogic = bf2.GameLogic.GameLogic() +serverSettings = bf2.GameLogic.ServerSettings() + +# these are for wrapping purposes when converting c++ pointers into python objects +playerConvFunc = playerManager.getPlayerByIndex + +class fake_stream: + """Implements stdout and stderr on top of BF2's log""" + def __init__(self, name): + self.name = name + self.buf = '' + + def write(self, str): + if len(str) == 0: return + self.buf += str + if str[-1] == '\n': + host.log(self.name + ': ' + self.buf[0:-1]) + self.buf = '' + + def flush(self): pass + def close(self): pass + +class fake_stream2: + """Implements stdout and stderr on top of BF2's log""" + def __init__(self, name): + self.buf = [str(name), ': '] + + def write(self, str): + if len(str) == 0: return + if str[-1] != '\n': + self.buf.append (str) + else: + self.buf.append (str[0:-1]) + host.log("".join (self.buf)) + self.buf = [] + + def flush(self): pass + def close(self): pass + +def init_module(): + # set up stdout and stderr to map to the host's logging function + # --------------------------------------------------- + sys.stdout = fake_stream('stdout') + sys.stderr = fake_stream('stderr') + + # omero, 2005-11-19 + # comment out the above lines and + # uncomment the following for python looging to gui + # --------------------------------------------------- + # NOTE 1: Requires that gui_log.pyw is present in + # /python/bf2 + # + # NOTE 2: gui_log.pyw MUST be started + # BEFORE gameserver + # --------------------------------------------------- + #import gui_log + + + # Added by Chump - for bf2statistics stats + logtime = str(strftime("%Y%m%d", localtime())) + log = file(debug_log_path + '/bf2game_' + logtime + '.log', 'a') + sys.stdout = log + sys.stderr = log + + print "==============================================" + print " BF2 Logging Started: %s" % str(strftime("%x %X", localtime())) + print "==============================================" + + import game.scoringCommon + game.scoringCommon.init() + + try: + import bf2.stats.stats + except ImportError: + print "Official stats module not found." + else: + bf2.stats.stats.init() + + try: + import bf2.stats.endofround + except ImportError: + print "Endofround module not found." + else: + bf2.stats.endofround.init() + + # Don't load snapshot or medals if we aren't enabling stats! + if stats_enable: + try: + import bf2.stats.snapshot + except ImportError: + print "Snapshot module not found." + else: + bf2.stats.snapshot.init() + + try: + import bf2.stats.medals + except ImportError: + print "Medal awarding module not found." + else: + bf2.stats.medals.init() + + try: + import bf2.stats.unlocks + except ImportError: + print "Unlock awarding module not found." + else: + bf2.stats.unlocks.init() + + try: + import bf2.stats.fragalyzer_log + except ImportError: + print "Fragalyzer log module not found." + else: + bf2.stats.fragalyzer_log.init() + + try: + import bf2.VerifyPlayer + except ImportError: + print "VerifyPlayer module not found." + else: + bf2.VerifyPlayer.init() + diff --git a/src/python/bf2/gui_log.pyw b/src/python/bf2/gui_log.pyw new file mode 100644 index 00000000..d7620782 --- /dev/null +++ b/src/python/bf2/gui_log.pyw @@ -0,0 +1,149 @@ +import socket, struct + +HOST = 'localhost' +PORT = 2501 + +def f_conns( sockets ): + return [sock for sock in sockets if isinstance( sock, connection )] +def f_socks( sockets ): + return [sock for sock in sockets if not isinstance( sock, connection )] + +class connection( object ): + def __init__( self, s, addr ): + self.socket = s + self.addr = addr + self.fileno = s.fileno + self.recv_buffer = str() + self.send_buffer = str() + self.messages = list() + def send( self ): + sent = self.socket.send( self.send_buffer ) + self.send_buffer = self.send_buffer[sent:] + def recv( self ): + data = self.socket.recv( 1024 ) + self.recv_buffer += data + def update( self ): + read, write, error = select.select( [self.socket], [self.socket], [self.socket], 0 ) + if read: self.recv() + if write and self.send_buffer: self.send() + def close( self ): + self.socket.close() + + def __iter__( self ): + self.recv_buffer + while 1: + buffer_len = len( self.recv_buffer ) + if buffer_len > 4: + msg_size = struct.unpack( 'i', self.recv_buffer[:4] )[0] + if buffer_len >= 4+msg_size: + yield self.recv_buffer[4:4+msg_size] + self.recv_buffer = self.recv_buffer[4+msg_size:] + else: + return + else: + return + def push( self, msg ): + self.send_buffer += struct.pack( 'i', len( msg ) ) + self.send_buffer += msg + +class server: + def __init__( self, host='', port=PORT ): + acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + acceptor.bind(('', port)) + acceptor.listen(1) + self.sockets = [acceptor] + self.on_disconnect=lambda conn:None + self.on_connect=lambda conn:None + + def connections( self ): + for c in list( self.sockets ): + if isinstance( c, connection ): + yield c + + def __iter__( self ): + need_write = [sock for sock in f_conns( self.sockets ) if sock.send_buffer] + readable, writable, errors = select.select( self.sockets, need_write, self.sockets, 0 ) + for acceptor in f_socks( readable ): + conn, addr = acceptor.accept() + conn = connection( conn, addr ) + self.on_connect( conn ) + self.sockets.append( conn ) + for error in errors: + self.sockets.remove( error ) + for read in f_conns( readable ): + try: + read.recv() + except socket.error: + self.remove( read ) + for msg in read: + yield msg, read + for write in writable: + try: + write.send() + except socket.error: + self.remove( write ) + def remove( self, connection ): + if connection in self.sockets: + self.on_disconnect( connection ) + connection.close() + self.sockets.remove( connection ) + +class network_stream: + def __init__( self, sock, prefix='n' ): + self.sock = sock + self.prefix = prefix + def write( self, msg ): + msg = self.prefix+msg + msg = struct.pack( 'i', len( msg ) )+msg + self.sock.send( msg ) + +def connect( server, port ): + sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) + sock.connect( (server,port) ) + return connection( sock, server ) + +def patch_sys(): + import sys + sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) + sock.connect( (HOST,PORT) ) + sys.stdout = network_stream( sock, 'n' ) + sys.stderr = network_stream( sock, 'e' ) + +if __name__ == '__main__': + import Tix, select + + class application( Tix.Tk ): + def __init__( self ): + Tix.Tk.__init__( self ) + self.title( 'BF2 Python Log' ) + self.out = Tix.ScrolledText( self ) + self.out.text.tag_config( 'normal', foreground='#000000' ) + self.out.text.tag_config( 'error', foreground='#FC0000' ) + self.out.text.tag_config( 'server', foreground='#008F00' ) + self.out.text.configure( wrap='none', state=Tix.DISABLED ) + self.out.pack( fill=Tix.BOTH, expand=True ) + self.server = server() + self.server.on_connect = self.on_connect + self.after( 10, self.netupdate ) + def netupdate( self ): + for msg, connection in self.server: + self.out.text.configure( state=Tix.NORMAL ) + if msg[0] == 'n': + self.out.text.insert( 'end', msg[1:], 'normal' ) + elif msg[0] == 'e': + self.out.text.insert( 'end', msg[1:], 'error' ) + self.out.text.configure( state=Tix.DISABLED ) + self.out.text.see( 'end' ) + self.after( 10, self.netupdate ) + def on_connect( self, conn ): + for c in self.server.connections(): + self.server.remove( c ) + self.out.text.configure( state=Tix.NORMAL ) + self.out.text.insert( 'end','\nconnect from: %s:%s\n'%conn.addr, 'server' ) + self.out.text.configure( state=Tix.DISABLED ) + + + app = application() + app.mainloop() +else: + patch_sys() diff --git a/src/python/bf2/logs/snapshots/sent/DELETE ME b/src/python/bf2/logs/snapshots/sent/DELETE ME new file mode 100644 index 00000000..e69de29b diff --git a/src/python/bf2/logs/snapshots/unsent/DELETE ME b/src/python/bf2/logs/snapshots/unsent/DELETE ME new file mode 100644 index 00000000..e69de29b diff --git a/src/python/bf2/stats/__init__.py b/src/python/bf2/stats/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/bf2/stats/constants.py b/src/python/bf2/stats/constants.py new file mode 100644 index 00000000..c927b5d8 --- /dev/null +++ b/src/python/bf2/stats/constants.py @@ -0,0 +1,1640 @@ +########################################################################################## +# +# constants.py 2011-09-19 +# von http://wiki.sgiersch.de/BF2Statistics_constants-py +# +# Erstellt von +# ++ Thinner - http://www.bf2statistics.com/user.php?id.2900 ++ +# ++ Leon_tbk - http://www.bf2statistics.com/user.php?id.4870 ++ +# +# Informationen ueber die Veraenderungen gibts hier: +# http://wiki.sgiersch.de/Diskussion:BF2Statistics_constants-py +# +########################################################################################## +# Basiert auf: +# stats keys +# aus der Original Datei von dem Packet BF2Statistics Update v1.4.2 +########################################################################################## + + +import host +from bf2 import g_debug + + +VEHICLE_TYPE_ARMOR = 0 +VEHICLE_TYPE_AVIATOR = 1 +VEHICLE_TYPE_AIRDEFENSE = 2 +VEHICLE_TYPE_HELICOPTER = 3 +VEHICLE_TYPE_TRANSPORT = 4 +VEHICLE_TYPE_ARTILLERY = 5 +VEHICLE_TYPE_GRNDDEFENSE = 6 +VEHICLE_TYPE_PARACHUTE = 7 +VEHICLE_TYPE_SOLDIER = 8 +VEHICLE_TYPE_NIGHTVISION = 9 +VEHICLE_TYPE_GASMASK = 10 +NUM_VEHICLE_TYPES = 11 +VEHICLE_TYPE_UNKNOWN = NUM_VEHICLE_TYPES + + +WEAPON_TYPE_ASSAULT = 0 +WEAPON_TYPE_ASSAULTGRN = 1 +WEAPON_TYPE_CARBINE = 2 +WEAPON_TYPE_LMG = 3 +WEAPON_TYPE_SNIPER = 4 +WEAPON_TYPE_PISTOL = 5 +WEAPON_TYPE_ATAA = 6 +WEAPON_TYPE_SMG = 7 +WEAPON_TYPE_SHOTGUN = 8 +WEAPON_TYPE_KNIFE = 9 +WEAPON_TYPE_SHOCKPAD = 10 +WEAPON_TYPE_C4 = 11 +WEAPON_TYPE_CLAYMORE = 12 +WEAPON_TYPE_HANDGRENADE = 13 +WEAPON_TYPE_ATMINE = 14 +WEAPON_TYPE_GRAPPLINGHOOK = 15 +WEAPON_TYPE_ZIPLINE = 16 +WEAPON_TYPE_TACTICAL = 17 +WEAPON_TYPE_TARGETING = 18 +# Hard Justice +#WEAPON_TYPE_APMINE = 19 +#WEAPON_TYPE_AIRDEFENSE = 20 +#WEAPON_TYPE_POISIONGAS = 21 +NUM_WEAPON_TYPES = 19 +WEAPON_TYPE_UNKNOWN = NUM_WEAPON_TYPES + + +KIT_TYPE_AT = 0 +KIT_TYPE_ASSAULT = 1 +KIT_TYPE_ENGINEER = 2 +KIT_TYPE_MEDIC = 3 +KIT_TYPE_SPECOPS = 4 +KIT_TYPE_SUPPORT = 5 +KIT_TYPE_SNIPER = 6 +NUM_KIT_TYPES = 7 +KIT_TYPE_UNKNOWN = NUM_KIT_TYPES + + +# Battlefield2 +ARMY_USA = 0 +ARMY_MEC = 1 +ARMY_CHINESE = 2 +# xpack1 - SpecialForces +ARMY_SEALS = 3 +ARMY_SAS = 4 +ARMY_SPETZNAS = 5 +ARMY_MECSF = 6 +ARMY_REBELS = 7 +ARMY_INSURGENTS = 8 +# booster pack 1 - Euroforces +ARMY_EURO = 9 +# POE +ARMY_GER = 10 +ARMY_UKR = 11 +# AIX +ARMY_UN = 12 +# Hard Justice 1.3 +ARMY_CANADIAN = 13 +NUM_ARMIES = 14 +ARMY_UNKNOWN = NUM_ARMIES + + +vehicleTypeMap = { +# Battlefield2 + "usapc_lav25" : VEHICLE_TYPE_ARMOR, + "apc_btr90" : VEHICLE_TYPE_ARMOR, + "apc_wz551" : VEHICLE_TYPE_ARMOR, + "ustnk_m1a2" : VEHICLE_TYPE_ARMOR, + "rutnk_t90" : VEHICLE_TYPE_ARMOR, + "tnk_type98" : VEHICLE_TYPE_ARMOR, + "usair_f18" : VEHICLE_TYPE_AVIATOR, + "ruair_mig29" : VEHICLE_TYPE_AVIATOR, + "air_j10" : VEHICLE_TYPE_AVIATOR, + "usair_f15" : VEHICLE_TYPE_AVIATOR, + "ruair_su34" : VEHICLE_TYPE_AVIATOR, + "air_su30mkk" : VEHICLE_TYPE_AVIATOR, + "air_f35b" : VEHICLE_TYPE_AVIATOR, + "usaav_m6" : VEHICLE_TYPE_AIRDEFENSE, + "aav_tunguska" : VEHICLE_TYPE_AIRDEFENSE, + "aav_type95" : VEHICLE_TYPE_AIRDEFENSE, + "usaas_stinger" : VEHICLE_TYPE_AIRDEFENSE, + "igla_djigit" : VEHICLE_TYPE_AIRDEFENSE, + "wasp_defence_front" : VEHICLE_TYPE_AIRDEFENSE, + "wasp_defence_back" : VEHICLE_TYPE_AIRDEFENSE, + "usthe_uh60" : VEHICLE_TYPE_HELICOPTER, + "the_mi17" : VEHICLE_TYPE_HELICOPTER, + "chthe_z8" : VEHICLE_TYPE_HELICOPTER, + "ahe_ah1z" : VEHICLE_TYPE_HELICOPTER, + "ahe_havoc" : VEHICLE_TYPE_HELICOPTER, + "ahe_z10" : VEHICLE_TYPE_HELICOPTER, + "jeep_faav" : VEHICLE_TYPE_TRANSPORT, + "usjep_hmmwv" : VEHICLE_TYPE_TRANSPORT, + "jep_paratrooper" : VEHICLE_TYPE_TRANSPORT, + "jep_mec_paratrooper" : VEHICLE_TYPE_TRANSPORT, + "jep_vodnik" : VEHICLE_TYPE_TRANSPORT, + "jep_nanjing" : VEHICLE_TYPE_TRANSPORT, + "uslcr_lcac" : VEHICLE_TYPE_TRANSPORT, + "boat_rib" : VEHICLE_TYPE_TRANSPORT, + "usart_lw155" : VEHICLE_TYPE_ARTILLERY, + "ars_d30" : VEHICLE_TYPE_ARTILLERY, + "ats_tow" : VEHICLE_TYPE_GRNDDEFENSE, + "ats_hj8" : VEHICLE_TYPE_GRNDDEFENSE, + "hmg_m2hb" : VEHICLE_TYPE_GRNDDEFENSE, + "chhmg_kord" : VEHICLE_TYPE_GRNDDEFENSE, + "mec_bipod" : VEHICLE_TYPE_GRNDDEFENSE, + "us_bipod" : VEHICLE_TYPE_GRNDDEFENSE, + "ch_bipod" : VEHICLE_TYPE_GRNDDEFENSE, + "us_soldier" : VEHICLE_TYPE_SOLDIER, + "us_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "us_light_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_light_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_light_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "parachute" : VEHICLE_TYPE_PARACHUTE, +# xpack1 - SpecialForces + "seal_soldier" : VEHICLE_TYPE_SOLDIER, + "seal_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "sas_soldier" : VEHICLE_TYPE_SOLDIER, + "sas_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "spetz_soldier" : VEHICLE_TYPE_SOLDIER, + "spetz_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "mecsf_soldier" : VEHICLE_TYPE_SOLDIER, + "mecsf_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "chinsurgent_soldier" : VEHICLE_TYPE_SOLDIER, + "chinsurgent_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "meinsurgent_soldier" : VEHICLE_TYPE_SOLDIER, + "meinsurgent_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "xpak_bmp3" : VEHICLE_TYPE_ARMOR, + "xpak_forklift" : VEHICLE_TYPE_TRANSPORT, + "xpak_atv" : VEHICLE_TYPE_TRANSPORT, + "xpak_civ1" : VEHICLE_TYPE_TRANSPORT, + "xpak_civ2" : VEHICLE_TYPE_TRANSPORT, + "xpak_jetski" : VEHICLE_TYPE_TRANSPORT, + "xpak_ailraider" : VEHICLE_TYPE_TRANSPORT, + "xpak_apache" : VEHICLE_TYPE_HELICOPTER, + "xpak_hind" : VEHICLE_TYPE_HELICOPTER, + "xpak_hummertow" : VEHICLE_TYPE_TRANSPORT, +# booster pack 1 - Euroforces + "xpak2_vbl" : VEHICLE_TYPE_TRANSPORT, + "xpak2_tnkl2a6" : VEHICLE_TYPE_ARMOR, + "xpak2_tnkc2" : VEHICLE_TYPE_ARMOR, + "xpak2_tiger" : VEHICLE_TYPE_HELICOPTER, + "xpak2_lynx" : VEHICLE_TYPE_HELICOPTER, + "xpak2_eurofighter" : VEHICLE_TYPE_AVIATOR, + "xpak2_harrier" : VEHICLE_TYPE_AVIATOR, + "eu_soldier" : VEHICLE_TYPE_SOLDIER, + "eu_heavy_soldier" : VEHICLE_TYPE_SOLDIER, +# booster pack 2 - ArmoredFury + "air_a10" : VEHICLE_TYPE_AVIATOR, + "air_su39" : VEHICLE_TYPE_AVIATOR, + "xpak2_fantan" : VEHICLE_TYPE_AVIATOR, + "che_wz11" : VEHICLE_TYPE_HELICOPTER, + "she_ec635" : VEHICLE_TYPE_HELICOPTER, + "she_littlebird" : VEHICLE_TYPE_HELICOPTER, + "xpak2_musclecar" : VEHICLE_TYPE_TRANSPORT, + "xpak2_semi" : VEHICLE_TYPE_TRANSPORT, +# POE2 + "gerair_ef2000" : VEHICLE_TYPE_AVIATOR, + "gerair_tornado" : VEHICLE_TYPE_AVIATOR, + "gerhe_eurotigerarh" : VEHICLE_TYPE_HELICOPTER, + "gerhe_nh90" : VEHICLE_TYPE_TRANSPORT, + "ufo" : VEHICLE_TYPE_HELICOPTER, + "ukrair_mig25" : VEHICLE_TYPE_AVIATOR, + "ukrair_su24" : VEHICLE_TYPE_AVIATOR, + "ukrair_su25" : VEHICLE_TYPE_AVIATOR, + "ukrhe_mi24p" : VEHICLE_TYPE_HELICOPTER, + "civsctr" : VEHICLE_TYPE_ARMOR, + "geraav_gepard" : VEHICLE_TYPE_AIRDEFENSE, + "gerapc_boxerGTK" : VEHICLE_TYPE_TRANSPORT, + "gerapc_marder1a5" : VEHICLE_TYPE_ARMOR, + "gerartil_pzh2000" : VEHICLE_TYPE_ARTILLERY, + "gerjeep_dingo" : VEHICLE_TYPE_TRANSPORT, + "gerjeep_wolf" : VEHICLE_TYPE_TRANSPORT, + "gerjeep_wolfsoft" : VEHICLE_TYPE_TRANSPORT, + "gertnk_leopard" : VEHICLE_TYPE_ARMOR, + "snowmobile" : VEHICLE_TYPE_TRANSPORT, + "ukraav_mtlb_sa13_v2" : VEHICLE_TYPE_ARMOR, + "ukraav_shilka" : VEHICLE_TYPE_AIRDEFENSE, + "ukrapc_bmp2" : VEHICLE_TYPE_TRANSPORT, + "ukrapc_mtlb" : VEHICLE_TYPE_TRANSPORT, + "ukrartil_m1974" : VEHICLE_TYPE_ARTILLERY, + "ukrartil_msta" : VEHICLE_TYPE_ARTILLERY, + "ukrjeep_dozer" : VEHICLE_TYPE_TRANSPORT, + "ukrjeep_uaz" : VEHICLE_TYPE_TRANSPORT, + "ukrtnk_oplot" : VEHICLE_TYPE_ARMOR, + "ukrtnk_t55" : VEHICLE_TYPE_ARMOR, + "ger_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "ger_light_soldier" : VEHICLE_TYPE_SOLDIER, + "ukr_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "ukr_light_soldier" : VEHICLE_TYPE_SOLDIER, + "aa_zu23" : VEHICLE_TYPE_GRNDDEFENSE, + "gerartil_fh70" : VEHICLE_TYPE_GRNDDEFENSE, + "mg3_coax" : VEHICLE_TYPE_GRNDDEFENSE, + "remote_kord" : VEHICLE_TYPE_GRNDDEFENSE, + "remote_mg3" : VEHICLE_TYPE_GRNDDEFENSE, +#AIX 1.0 + "ahe_ah1x" : VEHICLE_TYPE_HELICOPTER, + "ahe_ghost" : VEHICLE_TYPE_HELICOPTER, + "ahe_roc" : VEHICLE_TYPE_HELICOPTER, + "ahe_storm" : VEHICLE_TYPE_HELICOPTER, + "ahe_v10" : VEHICLE_TYPE_HELICOPTER, + "aix_ah64" : VEHICLE_TYPE_HELICOPTER, + "aix_ah64gunship" : VEHICLE_TYPE_HELICOPTER, + "aix_ka50" : VEHICLE_TYPE_HELICOPTER, + "aix_notar_littlebird" : VEHICLE_TYPE_HELICOPTER, + "aix_notar_littlebird_trans" : VEHICLE_TYPE_HELICOPTER, + "blizzard" : VEHICLE_TYPE_HELICOPTER, + "chahe_a8" : VEHICLE_TYPE_HELICOPTER, + "usahe_ah60" : VEHICLE_TYPE_HELICOPTER, + "aix_a10" : VEHICLE_TYPE_AVIATOR, + "aix_a10b" : VEHICLE_TYPE_AVIATOR, + "aix_av8b" : VEHICLE_TYPE_AVIATOR, + "aix_draken" : VEHICLE_TYPE_AVIATOR, + "aix_f117a" : VEHICLE_TYPE_AVIATOR, + "aix_f16" : VEHICLE_TYPE_AVIATOR, + "aix_f16lg" : VEHICLE_TYPE_AVIATOR, + "aix_f5tiger" : VEHICLE_TYPE_AVIATOR, + "aix_gr7" : VEHICLE_TYPE_AVIATOR, + "aix_mig19" : VEHICLE_TYPE_AVIATOR, + "aix_mig21" : VEHICLE_TYPE_AVIATOR, + "aix_mig23" : VEHICLE_TYPE_AVIATOR, + "aix_mirage2k" : VEHICLE_TYPE_AVIATOR, + "aix_mirage_iii" : VEHICLE_TYPE_AVIATOR, + "aix_su21" : VEHICLE_TYPE_AVIATOR, + "albatros_diii" : VEHICLE_TYPE_AVIATOR, + "fokker_dr1" : VEHICLE_TYPE_AVIATOR, + "fokker_eiii" : VEHICLE_TYPE_AVIATOR, + "mig21m" : VEHICLE_TYPE_AVIATOR, + "spad_xiii" : VEHICLE_TYPE_AVIATOR, + "aix_atv" : VEHICLE_TYPE_TRANSPORT, + "asset_pco" : VEHICLE_TYPE_ARMOR, + "bradley" : VEHICLE_TYPE_ARMOR, + "maws" : VEHICLE_TYPE_ARMOR, + "rms" : VEHICLE_TYPE_ARMOR, + "usaas_stinger_no_exit" : VEHICLE_TYPE_AIRDEFENSE, + "ch_hmg" : VEHICLE_TYPE_GRNDDEFENSE, + "mec_hmg" : VEHICLE_TYPE_GRNDDEFENSE, + "us_hmg" : VEHICLE_TYPE_GRNDDEFENSE, + "m224_mortar" : VEHICLE_TYPE_ARTILLERY, + "art_fieldcannon" : VEHICLE_TYPE_ARTILLERY, + "art_truckcannon" : VEHICLE_TYPE_ARTILLERY, + "ch_assault_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_at_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_engineer_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_medic_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_sniper_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_specops_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_support_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_assault_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_at_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_engineer_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_medic_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_sniper_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_specops_soldier" : VEHICLE_TYPE_SOLDIER, + "mec_support_soldier" : VEHICLE_TYPE_SOLDIER, + "un_assault_soldier" : VEHICLE_TYPE_SOLDIER, + "un_at_soldier" : VEHICLE_TYPE_SOLDIER, + "un_engineer_soldier" : VEHICLE_TYPE_SOLDIER, + "un_medic_soldier" : VEHICLE_TYPE_SOLDIER, + "un_sniper_soldier" : VEHICLE_TYPE_SOLDIER, + "un_specops_soldier" : VEHICLE_TYPE_SOLDIER, + "un_support_soldier" : VEHICLE_TYPE_SOLDIER, + "us_assault_soldier" : VEHICLE_TYPE_SOLDIER, + "us_at_soldier" : VEHICLE_TYPE_SOLDIER, + "us_engineer_soldier" : VEHICLE_TYPE_SOLDIER, + "us_medic_soldier" : VEHICLE_TYPE_SOLDIER, + "us_sniper_soldier" : VEHICLE_TYPE_SOLDIER, + "us_specops_soldier" : VEHICLE_TYPE_SOLDIER, + "us_support_soldier" : VEHICLE_TYPE_SOLDIER, +#AIX 2.0 + "aix_f16-ns" : VEHICLE_TYPE_AVIATOR, + "hawkextras" : VEHICLE_TYPE_AVIATOR, + "aix_be12" : VEHICLE_TYPE_AVIATOR, + "aix_su47" : VEHICLE_TYPE_AVIATOR, + "aix_su47-ns" : VEHICLE_TYPE_AVIATOR, + "aix_yak38" : VEHICLE_TYPE_AVIATOR, + "aix_mig19-ns" : VEHICLE_TYPE_AVIATOR, + "aix_a10-ns" : VEHICLE_TYPE_AVIATOR, + "mig21" : VEHICLE_TYPE_AVIATOR, + "mirage" : VEHICLE_TYPE_AVIATOR, + "aix_viggen" : VEHICLE_TYPE_AVIATOR, + "aix_firefox" : VEHICLE_TYPE_AVIATOR, + "aix_f12x" : VEHICLE_TYPE_AVIATOR, + "a8_extras" : VEHICLE_TYPE_HELICOPTER, + "blizzardextras" : VEHICLE_TYPE_HELICOPTER, + "blizzardextras" : VEHICLE_TYPE_HELICOPTER, + "aix_mh53j" : VEHICLE_TYPE_HELICOPTER, + "aix_mi24" : VEHICLE_TYPE_HELICOPTER, + "jeep_faav_hf" : VEHICLE_TYPE_TRANSPORT, + "aix_atv2" : VEHICLE_TYPE_TRANSPORT, + "jeep_technical" : VEHICLE_TYPE_TRANSPORT, + "us_minigun" : VEHICLE_TYPE_GRNDDEFENSE, +#Hard Justice 1.3 + "us2_soldier" : VEHICLE_TYPE_SOLDIER, + "us2_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "us2_light_soldier" : VEHICLE_TYPE_SOLDIER, + "mec2_soldier" : VEHICLE_TYPE_SOLDIER, + "mec2_light_soldier" : VEHICLE_TYPE_SOLDIER, + "mec2_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "ch2_soldier" : VEHICLE_TYPE_SOLDIER, + "ch2_light_soldier" : VEHICLE_TYPE_SOLDIER, + "ch2_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "us3_soldier" : VEHICLE_TYPE_SOLDIER, + "us3_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "us3_light_soldier" : VEHICLE_TYPE_SOLDIER, + "mec3_soldier" : VEHICLE_TYPE_SOLDIER, + "mec3_light_soldier" : VEHICLE_TYPE_SOLDIER, + "mec3_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "ch3_soldier" : VEHICLE_TYPE_SOLDIER, + "ch3_light_soldier" : VEHICLE_TYPE_SOLDIER, + "ch3_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "ca_soldier" : VEHICLE_TYPE_SOLDIER, + "ca_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "rah66a" : VEHICLE_TYPE_HELICOPTER, + "ah6c" : VEHICLE_TYPE_HELICOPTER, + "ah6j" : VEHICLE_TYPE_HELICOPTER, + "sa342f" : VEHICLE_TYPE_HELICOPTER, + "sa342a" : VEHICLE_TYPE_HELICOPTER, + "m270" : VEHICLE_TYPE_ARTILLERY, + "tos1" : VEHICLE_TYPE_ARTILLERY, + "f22a" : VEHICLE_TYPE_AVIATOR, + "bradly" : VEHICLE_TYPE_ARMOR, + "m270_m109h" : VEHICLE_TYPE_ARTILLERY, + "apc_cobra" : VEHICLE_TYPE_ARMOR, + "apc_cobraat" : VEHICLE_TYPE_ARMOR, + "a10w" : VEHICLE_TYPE_AVIATOR, + "a10w1" : VEHICLE_TYPE_AVIATOR, + "a10w2" : VEHICLE_TYPE_AVIATOR, + "oelikonaa" : VEHICLE_TYPE_AIRDEFENSE, + "rh202_aa" : VEHICLE_TYPE_AIRDEFENSE, + "humvee_aaag" : VEHICLE_TYPE_TRANSPORT, + "dirtbike" : VEHICLE_TYPE_TRANSPORT, + "naw_apache" : VEHICLE_TYPE_HELICOPTER, + "su25" : VEHICLE_TYPE_AVIATOR, + "su25sc" : VEHICLE_TYPE_AVIATOR, + "baja_bug" : VEHICLE_TYPE_TRANSPORT, + "challenger" : VEHICLE_TYPE_TRANSPORT, + "zero_quad" : VEHICLE_TYPE_TRANSPORT, + "zero_quad125cc" : VEHICLE_TYPE_TRANSPORT, + "zero_quad250cc" : VEHICLE_TYPE_TRANSPORT, + "aa_technical" : VEHICLE_TYPE_TRANSPORT, + "tow_technical" : VEHICLE_TYPE_TRANSPORT, + "usjep_amrpr" : VEHICLE_TYPE_TRANSPORT, + "woodyswagon" : VEHICLE_TYPE_ARTILLERY, + "defense_gun" : VEHICLE_TYPE_ARTILLERY, + "humvee_aa_ag" : VEHICLE_TYPE_ARMOR, + "civ2_tow" : VEHICLE_TYPE_GRNDDEFENSE, +# AIX 2.0 TNG Maps + "aix_su22" : VEHICLE_TYPE_AVIATOR, + "aix_phantom_ii_v2_un_wso" : VEHICLE_TYPE_AVIATOR, + "aix_mirage2k_v2" : VEHICLE_TYPE_AVIATOR, + "aix_draken_v2" : VEHICLE_TYPE_AVIATOR, + "aix_av8b_un" : VEHICLE_TYPE_AVIATOR, + "aix_a7" : VEHICLE_TYPE_AVIATOR, + "aix_a10_v2" : VEHICLE_TYPE_AVIATOR, + "aix_a10b_v2" : VEHICLE_TYPE_AVIATOR, + "aix_av8b_v2" : VEHICLE_TYPE_AVIATOR, + "aix_f14" : VEHICLE_TYPE_AVIATOR, + "aix_f14_rio" : VEHICLE_TYPE_AVIATOR, + "aix_f16_v2" : VEHICLE_TYPE_AVIATOR, + "aix_f16lg_v2" : VEHICLE_TYPE_AVIATOR, + "aix_f5tiger_v2" : VEHICLE_TYPE_AVIATOR, + "aix_mig23_v2" : VEHICLE_TYPE_AVIATOR, + "aix_mirage_iii_v2" : VEHICLE_TYPE_AVIATOR, + "aix_phantom_ii_v2_un" : VEHICLE_TYPE_AVIATOR, + "aix_su21_v2" : VEHICLE_TYPE_AVIATOR, + "aix_su47_v2" : VEHICLE_TYPE_AVIATOR, + "aix_mig21_v2" : VEHICLE_TYPE_AVIATOR, + "aix_f117a_v2" : VEHICLE_TYPE_AVIATOR, + "aix_mig19_v2" : VEHICLE_TYPE_AVIATOR, + "aix_viggen_v2" : VEHICLE_TYPE_AVIATOR, + "rh202_aa" : VEHICLE_TYPE_AIRDEFENSE, +# AIX 2.0 TNG 2.0 + "dirtbike_un" : VEHICLE_TYPE_TRANSPORT, + "unthe_uh60" : VEHICLE_TYPE_HELICOPTER, + "aix_notar_lb_un" : VEHICLE_TYPE_HELICOPTER, + "untnk_m1a2" : VEHICLE_TYPE_ARMOR, + "unjep_hmmwv" : VEHICLE_TYPE_TRANSPORT, + "unapc_lav25" : VEHICLE_TYPE_ARMOR, + "aav_type95_v2" : VEHICLE_TYPE_AIRDEFENSE, + "unaav_m6" : VEHICLE_TYPE_AIRDEFENSE, + "aix_be12_v2" : VEHICLE_TYPE_AVIATOR, + "aix_ah64_v2" : VEHICLE_TYPE_HELICOPTER, + "aix_ah64gunship_v2" : VEHICLE_TYPE_HELICOPTER, + "m1a2_v2" : VEHICLE_TYPE_ARMOR, +# NAV - Nations@War 6.0 + "iran_light_soldier" : VEHICLE_TYPE_SOLDIER, + "Iraq_light_soldier" : VEHICLE_TYPE_SOLDIER, + "czh_soldier" : VEHICLE_TYPE_SOLDIER, + "kor_light_soldier" : VEHICLE_TYPE_SOLDIER, + "uk_soldier" : VEHICLE_TYPE_SOLDIER, + "jap_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "nor_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "ch_light_soldier" : VEHICLE_TYPE_SOLDIER, + "ger_soldier" : VEHICLE_TYPE_SOLDIER, + "pak_light_soldier" : VEHICLE_TYPE_SOLDIER, + "den_soldier" : VEHICLE_TYPE_SOLDIER, + "syr_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "can_heavy_soldier" : VEHICLE_TYPE_SOLDIER, + "a10" : VEHICLE_TYPE_AVIATOR, + "a10_ap" : VEHICLE_TYPE_AVIATOR, + "ahe_ah1z" : VEHICLE_TYPE_HELICOPTER, + "ahe_helln" : VEHICLE_TYPE_HELICOPTER, + "ahe_naw" : VEHICLE_TYPE_HELICOPTER, + "air_su30nuk" : VEHICLE_TYPE_AVIATOR, + "ch_medthe" : VEHICLE_TYPE_HELICOPTER, + "f22a" : VEHICLE_TYPE_AVIATOR, + "kaw_oh6" : VEHICLE_TYPE_HELICOPTER, + "kaw_oh6i" : VEHICLE_TYPE_HELICOPTER, + "mh6_so" : VEHICLE_TYPE_HELICOPTER, + "mh6_tr" : VEHICLE_TYPE_HELICOPTER, + "naw_apache" : VEHICLE_TYPE_HELICOPTER, + "rah66a" : VEHICLE_TYPE_HELICOPTER, + "sa342a" : VEHICLE_TYPE_HELICOPTER, + "sa342f" : VEHICLE_TYPE_HELICOPTER, + "su25" : VEHICLE_TYPE_AVIATOR, + "su25sc" : VEHICLE_TYPE_AVIATOR, + "the_mi17a" : VEHICLE_TYPE_HELICOPTER, + "us_medthe" : VEHICLE_TYPE_HELICOPTER, + "usair_f15n" : VEHICLE_TYPE_AVIATOR, + "usthe_uh606" : VEHICLE_TYPE_HELICOPTER, + "civ_buggy" : VEHICLE_TYPE_TRANSPORT, + "civ_charger" : VEHICLE_TYPE_TRANSPORT, + "civ_cobra" : VEHICLE_TYPE_TRANSPORT, + "civ_digger" : VEHICLE_TYPE_TRANSPORT, + "civ_mustang" : VEHICLE_TYPE_TRANSPORT, + "civ_police" : VEHICLE_TYPE_TRANSPORT, + "mil_cruiser" : VEHICLE_TYPE_TRANSPORT, + "reb_defender" : VEHICLE_TYPE_TRANSPORT, + "reb_hotRod" : VEHICLE_TYPE_TRANSPORT, + "reb_van_01" : VEHICLE_TYPE_TRANSPORT, + "truck1" : VEHICLE_TYPE_TRANSPORT, + "aa_technical" : VEHICLE_TYPE_AIRDEFENSE, + "usaav_m163" : VEHICLE_TYPE_AIRDEFENSE, + "dirtbike" : VEHICLE_TYPE_TRANSPORT, + "humvee_aaag" : VEHICLE_TYPE_ARTILLERY, + "jeep_technical" : VEHICLE_TYPE_TRANSPORT, + "iraqtrk_ural4320" : VEHICLE_TYPE_TRANSPORT, + "ustrk_m35" : VEHICLE_TYPE_TRANSPORT, + "m270" : VEHICLE_TYPE_ARTILLERY, + "nanjing_amrpr" : VEHICLE_TYPE_TRANSPORT, + "tos1" : VEHICLE_TYPE_ARTILLERY, + "iraqart_bm21" : VEHICLE_TYPE_ARTILLERY, + "iraqart_2s1" : VEHICLE_TYPE_ARTILLERY, + "usart_m109" : VEHICLE_TYPE_ARTILLERY, + "tow_technical" : VEHICLE_TYPE_TRANSPORT, + "usav_brad" : VEHICLE_TYPE_ARMOR, + "usjep_amrpr" : VEHICLE_TYPE_TRANSPORT, + "zero_quad" : VEHICLE_TYPE_TRANSPORT, + "zero_quad125cc" : VEHICLE_TYPE_TRANSPORT, + "zero_quad250cc" : VEHICLE_TYPE_TRANSPORT, + "apc_cobra" : VEHICLE_TYPE_TRANSPORT, + "challenger" : VEHICLE_TYPE_TRANSPORT, + "baja_bug" : VEHICLE_TYPE_TRANSPORT, + "apc_cobraat" : VEHICLE_TYPE_TRANSPORT, + "ssn_688i" : VEHICLE_TYPE_TRANSPORT, + "lss" : VEHICLE_TYPE_TRANSPORT, + "air_a10" : VEHICLE_TYPE_AVIATOR, + "air_su39" : VEHICLE_TYPE_AVIATOR, + "xpak2_fantan" : VEHICLE_TYPE_AVIATOR, + "che_wz11" : VEHICLE_TYPE_HELICOPTER, + "xpak2_tnkl2a6" : VEHICLE_TYPE_ARMOR, + "xpak2_tnkc2" : VEHICLE_TYPE_ARMOR, + "ustnk_m1a1" : VEHICLE_TYPE_ARMOR, + "xpak2_tiger" : VEHICLE_TYPE_HELICOPTER, + "xpak2_eurofighter" : VEHICLE_TYPE_AVIATOR, + "she_ec635" : VEHICLE_TYPE_HELICOPTER, + "she_littlebird" : VEHICLE_TYPE_HELICOPTER, + "xpak2_musclecar" : VEHICLE_TYPE_TRANSPORT, + "xpak2_semi" : VEHICLE_TYPE_TRANSPORT, + "bkc_interceptor" : VEHICLE_TYPE_TRANSPORT, + "bkc_pursuit" : VEHICLE_TYPE_TRANSPORT, + "bkc_defender" : VEHICLE_TYPE_TRANSPORT, + "chinook" : VEHICLE_TYPE_HELICOPTER, + "chinookassault" : VEHICLE_TYPE_HELICOPTER, + "aix_av8b" : VEHICLE_TYPE_AVIATOR, + "aix_be12" : VEHICLE_TYPE_AVIATOR, + "aix_draken" : VEHICLE_TYPE_AVIATOR, + "aix_f117a" : VEHICLE_TYPE_AVIATOR, + "aix_gr7" : VEHICLE_TYPE_AVIATOR, + "aix_su47" : VEHICLE_TYPE_AVIATOR, + "aix_yak38" : VEHICLE_TYPE_AVIATOR, + "aix_su22" : VEHICLE_TYPE_AVIATOR, + "aix_spitfire_v" : VEHICLE_TYPE_AVIATOR, + "aix_spitfire_ix" : VEHICLE_TYPE_AVIATOR, + "aix_phantom_ii" : VEHICLE_TYPE_AVIATOR, + "aix_phantom_fgr2" : VEHICLE_TYPE_AVIATOR, + "aix_p51d" : VEHICLE_TYPE_AVIATOR, + "aix_ju87b" : VEHICLE_TYPE_AVIATOR, + "aix_f14" : VEHICLE_TYPE_AVIATOR, + "aix_bf109e" : VEHICLE_TYPE_AVIATOR, + "aix_a7" : VEHICLE_TYPE_AVIATOR, + "boat_markv" : VEHICLE_TYPE_TRANSPORT, +# AIX 2.0 TNG2.0 - Boosterpack + "aix_ah64un" : VEHICLE_TYPE_HELICOPTER, + "aix_rooivalk_un" : VEHICLE_TYPE_HELICOPTER, + "aix_rooivalk" : VEHICLE_TYPE_HELICOPTER, + "aix_f14_mec" : VEHICLE_TYPE_AVIATOR, + "aix_f14_mec_rio" : VEHICLE_TYPE_AVIATOR, + "aix_mi24_v2" : VEHICLE_TYPE_AVIATOR, + "aix_a7_v2" : VEHICLE_TYPE_AVIATOR, + "aix_yak38_ch" : VEHICLE_TYPE_AVIATOR, + "aix_yak38_v2" : VEHICLE_TYPE_AVIATOR, + "jeep_faav_un" : VEHICLE_TYPE_TRANSPORT, + "jeep_technical_un" : VEHICLE_TYPE_TRANSPORT, + "bradley_un" : VEHICLE_TYPE_ARMOR, + "bradley_v2" : VEHICLE_TYPE_ARMOR, + "maws_v2" : VEHICLE_TYPE_ARMOR, + "t90_v2" : VEHICLE_TYPE_ARMOR, + "type98_v2" : VEHICLE_TYPE_ARMOR, + "rms_v2" : VEHICLE_TYPE_ARMOR, + "aav_tunguska_v2" : VEHICLE_TYPE_AIRDEFENSE, + "usaav_m6_v2" : VEHICLE_TYPE_AIRDEFENSE +} + +weaponTypeMap = { +# Battlefield2 + "usrif_m16a2" : WEAPON_TYPE_ASSAULT, + "rurif_ak101" : WEAPON_TYPE_ASSAULT, + "rurif_ak47" : WEAPON_TYPE_ASSAULT, + "usrif_sa80" : WEAPON_TYPE_ASSAULT, + "usrif_g3a3" : WEAPON_TYPE_ASSAULT, + "usrif_m203" : WEAPON_TYPE_ASSAULT, + "rurif_gp30" : WEAPON_TYPE_ASSAULT, + "rurif_gp25" : WEAPON_TYPE_ASSAULT, + "usrgl_m203" : WEAPON_TYPE_ASSAULTGRN, + "rurgl_gp30" : WEAPON_TYPE_ASSAULTGRN, + "rurgl_gp25" : WEAPON_TYPE_ASSAULTGRN, + "rurrif_ak74u" : WEAPON_TYPE_CARBINE, + "usrif_m4" : WEAPON_TYPE_CARBINE, + "rurif_ak74u" : WEAPON_TYPE_CARBINE, + "chrif_type95" : WEAPON_TYPE_CARBINE, + "usrif_g36c" : WEAPON_TYPE_CARBINE, + "uslmg_m249saw" : WEAPON_TYPE_LMG, + "rulmg_rpk74" : WEAPON_TYPE_LMG, + "chlmg_type95" : WEAPON_TYPE_LMG, + "rulmg_pkm" : WEAPON_TYPE_LMG, + "usrif_m24" : WEAPON_TYPE_SNIPER, + "rurif_dragunov" : WEAPON_TYPE_SNIPER, + "chsni_type88" : WEAPON_TYPE_SNIPER, + "ussni_m82a1" : WEAPON_TYPE_SNIPER, + "ussni_m95_barret" : WEAPON_TYPE_SNIPER, + "uspis_92fs" : WEAPON_TYPE_PISTOL, + "uspis_92fs_silencer" : WEAPON_TYPE_PISTOL, + "rupis_baghira" : WEAPON_TYPE_PISTOL, + "rupis_baghira_silencer" : WEAPON_TYPE_PISTOL, + "chpis_qsz92" : WEAPON_TYPE_PISTOL, + "chpis_qsz92_silencer" : WEAPON_TYPE_PISTOL, + "usatp_predator" : WEAPON_TYPE_ATAA, + "chat_eryx" : WEAPON_TYPE_ATAA, + "usrif_mp5_a3" : WEAPON_TYPE_SMG, + "rurif_bizon" : WEAPON_TYPE_SMG, + "chrif_type85" : WEAPON_TYPE_SMG, + "usrif_remington11-87" : WEAPON_TYPE_SHOTGUN, + "rusht_saiga12" : WEAPON_TYPE_SHOTGUN, + "chsht_norinco982" : WEAPON_TYPE_SHOTGUN, + "chsht_protecta" : WEAPON_TYPE_SHOTGUN, + "ussht_jackhammer" : WEAPON_TYPE_SHOTGUN, + "kni_knife" : WEAPON_TYPE_KNIFE, + "c4_explosives" : WEAPON_TYPE_C4, + "ushgr_m67" : WEAPON_TYPE_HANDGRENADE, + "usmin_claymore" : WEAPON_TYPE_CLAYMORE, + "defibrillator" : WEAPON_TYPE_SHOCKPAD, + "at_mine" : WEAPON_TYPE_ATMINE, + "simrad" : WEAPON_TYPE_TARGETING, +# xpack1 - SpecialForces + "nshgr_flashbang" : WEAPON_TYPE_TACTICAL, + "sasrif_teargas" : WEAPON_TYPE_TACTICAL, + "insgr_rpg" : WEAPON_TYPE_ATAA, + "nsrif_crossbow" : WEAPON_TYPE_ZIPLINE, + "rurif_oc14" : WEAPON_TYPE_ASSAULT, + "sasrif_fn2000" : WEAPON_TYPE_ASSAULT, + "sasgr_fn2000" : WEAPON_TYPE_ASSAULTGRN, + "sasrif_g36e" : WEAPON_TYPE_ASSAULT, + "sasrif_g36k" : WEAPON_TYPE_ASSAULT, + "sasrif_mg36" : WEAPON_TYPE_LMG, + "sasrif_mp7" : WEAPON_TYPE_SMG, + "spzrif_aps" : WEAPON_TYPE_ASSAULT, + "usrif_fnscarh" : WEAPON_TYPE_ASSAULT, + "usrif_fnscarl" : WEAPON_TYPE_CARBINE, +# booster pack 1 - Euroforces + "eurif_fnp90" : WEAPON_TYPE_SMG, + "eurif_hk53a3" : WEAPON_TYPE_CARBINE, + "gbrif_benelli_m4" : WEAPON_TYPE_SHOTGUN, + "gbrif_l96a1" : WEAPON_TYPE_SNIPER, + "eurif_famas" : WEAPON_TYPE_ASSAULT, + "gbrif_sa80a2_l85" : WEAPON_TYPE_ASSAULT, + "gbgr_sa80a2_l85" : WEAPON_TYPE_ASSAULTGRN, + "eurif_hk21" : WEAPON_TYPE_LMG, +# POE2 + "at_mine2" : WEAPON_TYPE_ATMINE, + "gergre_dm61" : WEAPON_TYPE_HANDGRENADE, + "gergrl_ag36" : WEAPON_TYPE_ASSAULTGRN, + "gerkni_km2000" : WEAPON_TYPE_KNIFE, + "gerlmg_mg3" : WEAPON_TYPE_LMG, + "gerlmg_mg36" : WEAPON_TYPE_LMG, + "gerpis_p8" : WEAPON_TYPE_PISTOL, + "gerrif_g36" : WEAPON_TYPE_ASSAULT, + "gerrif_g36c" : WEAPON_TYPE_CARBINE , + "gerrif_g36k" : WEAPON_TYPE_ASSAULT, + "gerrif_msg90" : WEAPON_TYPE_SNIPER, + "gerroc_bunkerfaust" : WEAPON_TYPE_ATAA, + "gerroc_fliegerfaust2" : WEAPON_TYPE_ATAA, + "gerroc_panzerfaust3" : WEAPON_TYPE_ATAA, + "gerroc_panzerfaust3t" : WEAPON_TYPE_ATAA, + "gersni_g82" : WEAPON_TYPE_CARBINE, + "gergre_smoke" : WEAPON_TYPE_TACTICAL, + "gergre_smoke2" : WEAPON_TYPE_TACTICAL, + "katana" : WEAPON_TYPE_KNIFE, + "ruskni_expknife" : WEAPON_TYPE_KNIFE, + "ukrgre_rdg2" : WEAPON_TYPE_ASSAULTGRN, + "ukrgre_rdg2_2" : WEAPON_TYPE_ASSAULTGRN, + "ukrgre_rgd5" : WEAPON_TYPE_ASSAULTGRN, + "ukrgrl_gp25" : WEAPON_TYPE_ASSAULTGRN, + "ukrlmg_pkm" : WEAPON_TYPE_LMG, + "ukrlmg_rpk74" : WEAPON_TYPE_LMG, + "ukrpis_fort12" : WEAPON_TYPE_PISTOL, + "ukrpis_pb6p9" : WEAPON_TYPE_PISTOL, + "ukrrif_aks74u" : WEAPON_TYPE_CARBINE, + "ukrrif_pp2000" : WEAPON_TYPE_SMG, + "ukrrif_pp2000_2" : WEAPON_TYPE_SMG, + "ukrrif_svd" : WEAPON_TYPE_SNIPER, + "ukrrif_skorpion" : WEAPON_TYPE_SNIPER, + "ukrrif_vepr" : WEAPON_TYPE_ASSAULT, + "ukrrif_vintorez" : WEAPON_TYPE_SNIPER, + "ukrroc_rpgfrag" : WEAPON_TYPE_ATAA, + "ukrroc_rpgheat" : WEAPON_TYPE_ATAA, + "ukrroc_rpgtandem" : WEAPON_TYPE_ATAA, + "ukrroc_rpgthermo" : WEAPON_TYPE_ATAA, + "ukrroc_sa7" : WEAPON_TYPE_ATAA, + "ukrsht_toz194" : WEAPON_TYPE_SHOTGUN, + "ukrsmg_asval" : WEAPON_TYPE_ASSAULT, + "ukrsni_ntw20" : WEAPON_TYPE_ASSAULT, + "usasht_m1014" : WEAPON_TYPE_SHOTGUN, + "usasmg_mp7" : WEAPON_TYPE_SMG, + "usasmg_mp7_2" : WEAPON_TYPE_SMG, + "usasmg_mp7_scoped" : WEAPON_TYPE_SMG, + "usasmg_mp7_silenced" : WEAPON_TYPE_SMG, + "usmin_claymore2" : WEAPON_TYPE_CLAYMORE, + "usrif_g36c" : WEAPON_TYPE_ASSAULT, +#AIX 1.0 + "aix_ak5_tactical" : WEAPON_TYPE_ASSAULT, + "aix_famas" : WEAPON_TYPE_ASSAULT, + "aix_fs2000" : WEAPON_TYPE_ASSAULT, + "aix_g36k_rif" : WEAPON_TYPE_ASSAULT, + "aix_m41a" : WEAPON_TYPE_ASSAULT, + "aix_mk14ebr" : WEAPON_TYPE_ASSAULT, + "aix_scarl_rif" : WEAPON_TYPE_ASSAULT, + "aix_steyr_aug" : WEAPON_TYPE_ASSAULT, + "chrif_type95_b" : WEAPON_TYPE_ASSAULT, + "rurif_ak47_b" : WEAPON_TYPE_ASSAULT, + "aix_g36k_gl" : WEAPON_TYPE_ASSAULTGRN, + "aix_mgl140" : WEAPON_TYPE_ASSAULTGRN, + "aix_scarl_gl" : WEAPON_TYPE_ASSAULTGRN, + "aix_as50" : WEAPON_TYPE_SNIPER, + "aix_barrett_m109" : WEAPON_TYPE_SNIPER, + "aix_dsr" : WEAPON_TYPE_SNIPER, + "aix_beretta" : WEAPON_TYPE_PISTOL, + "aix_beretta_silencer" : WEAPON_TYPE_PISTOL, + "aix_glock19" : WEAPON_TYPE_PISTOL, + "aix_glock19_silencer" : WEAPON_TYPE_PISTOL, + "aix_gsh" : WEAPON_TYPE_PISTOL, + "aix_gsh_silencer" : WEAPON_TYPE_PISTOL, + "aix_uspmatch" : WEAPON_TYPE_PISTOL, + "aix_uspmatch_silencer" : WEAPON_TYPE_PISTOL, + "aix_fim92a" : WEAPON_TYPE_ATAA, + "aix_rpg7" : WEAPON_TYPE_ATAA, + "aix_strela2" : WEAPON_TYPE_ATAA, + "chat_eryx_lt" : WEAPON_TYPE_ATAA, + "rurpg_rpg7" : WEAPON_TYPE_ATAA, + "mortar_deployable" : WEAPON_TYPE_ATAA, + "aix_g36v" : WEAPON_TYPE_CARBINE, + "aix_hk416" : WEAPON_TYPE_CARBINE, + "aix_sig552" : WEAPON_TYPE_CARBINE, + "aix_xm8" : WEAPON_TYPE_CARBINE, + "rurif_ak47u_b" : WEAPON_TYPE_CARBINE, + "tavor" : WEAPON_TYPE_CARBINE, + "aix_grenade1" : WEAPON_TYPE_HANDGRENADE, + "aix_m41a_shot" : WEAPON_TYPE_SHOTGUN, + "aix_mac11" : WEAPON_TYPE_SMG, + "rurif_ak101_b" : WEAPON_TYPE_SMG, + "aix_portableminigun" : WEAPON_TYPE_LMG, + "aix_portableminigun_mec" : WEAPON_TYPE_LMG, + "aix_stg58" : WEAPON_TYPE_LMG, + "aix_tpg1" : WEAPON_TYPE_SNIPER, + "at4_mine" : WEAPON_TYPE_ATMINE, + "binoculars_mec_ch" : WEAPON_TYPE_TARGETING, + "us_binocular" : WEAPON_TYPE_TACTICAL, + "us_flaretrap" : WEAPON_TYPE_TACTICAL, + "c4_timebomb" : WEAPON_TYPE_C4, + "hgr_flashbang" : WEAPON_TYPE_TACTICAL, + "ch_flaretrap" : WEAPON_TYPE_TACTICAL, + "hgr_incendiary" : WEAPON_TYPE_TACTICAL, + "hgr_incendiary_sticky" : WEAPON_TYPE_TACTICAL, + "hgr_smoke_orange" : WEAPON_TYPE_TACTICAL, + "hgr_smoke_purple" : WEAPON_TYPE_TACTICAL, + "hgr_smoke_yellow" : WEAPON_TYPE_TACTICAL, + "hgr_teargas" : WEAPON_TYPE_TACTICAL, + "mec_flaretrap" : WEAPON_TYPE_TACTICAL, + "grapplinghook" : WEAPON_TYPE_GRAPPLINGHOOK, + "throwknife" : WEAPON_TYPE_KNIFE, +#AIX 2.0 + "aix_flaretrap" : WEAPON_TYPE_TACTICAL, + "aix_kimber" : WEAPON_TYPE_PISTOL, + "aix_kimber_silencer" : WEAPON_TYPE_PISTOL, + "aix_magpul" : WEAPON_TYPE_ASSAULT, + "aix_tavor" : WEAPON_TYPE_ASSAULT, + "aix_sig552specops" : WEAPON_TYPE_CARBINE, + "aix_type97" : WEAPON_TYPE_CARBINE, + "aix_type97_mg" : WEAPON_TYPE_LMG, + "aix_p90" : WEAPON_TYPE_SMG, + "aix_vintorez" : WEAPON_TYPE_SNIPER, +#Hard Justice 1.3 + #"sa7" : WEAPON_TYPE_AIRDEFENSE, + "m14lm" : WEAPON_TYPE_CLAYMORE, + #"hgr_gas" : WEAPON_TYPE_POISIONGAS, + "deserteagal" : WEAPON_TYPE_PISTOL, + "sasrif_fn20001" : WEAPON_TYPE_ASSAULT, + "sasgr_fn20001" : WEAPON_TYPE_ASSAULTGRN, + "gbrif_sa80a21_l85" : WEAPON_TYPE_ASSAULT, + "gbgr_sa80a21_l85" : WEAPON_TYPE_ASSAULTGRN, + "m95_barret" : WEAPON_TYPE_SNIPER, + "designator" : WEAPON_TYPE_TARGETING, + "javelin" : WEAPON_TYPE_ATAA, + "javelin_direct" : WEAPON_TYPE_ATAA, + "hgr_smoke2" : WEAPON_TYPE_TACTICAL, + "mk19" : WEAPON_TYPE_LMG, + "usatp_predator2" : WEAPON_TYPE_ATAA, + "chhmg_type85" : WEAPON_TYPE_SMG, + "usrif_mp5_a3_2" : WEAPON_TYPE_SMG, +# AIX 2.0 TNG Maps + "aix_portableminigun_v2" : WEAPON_TYPE_LMG, + "aix_portableminigun_mec_v2" : WEAPON_TYPE_LMG, + "aix_type97_v2" : WEAPON_TYPE_CARBINE, + "aix_type97_mg_v2" : WEAPON_TYPE_LMG, + "aix_tavor_v2" : WEAPON_TYPE_CARBINE, + "aix_g36k_rif_v2" : WEAPON_TYPE_ASSAULT, + "aix_fs2000_v2" : WEAPON_TYPE_ASSAULT, + "aix_dsr_v2" : WEAPON_TYPE_SNIPER, +# AIX 2.0 TNG 2.0 + "aix_scarl_rif_v2" : WEAPON_TYPE_ASSAULT, + "sasrif_g36e_v2" : WEAPON_TYPE_ASSAULT, + "aix_ak5_tactical_v2" : WEAPON_TYPE_ASSAULT, +# NAV - Nations@War 6.0 + "t2_1887_shotgun" : WEAPON_TYPE_SHOTGUN, + "Rambo_3_knife" : WEAPON_TYPE_KNIFE, + "nsrif_crossbow" : WEAPON_TYPE_SNIPER, + "m14lm" : WEAPON_TYPE_ATMINE, + "ap_mine" : WEAPON_TYPE_ATMINE, + "deserteagle" : WEAPON_TYPE_PISTOL, + "dual_deserteagles" : WEAPON_TYPE_PISTOL, + "dual_uzi" : WEAPON_TYPE_SMG, + "iraq_scorpion" : WEAPON_TYPE_SMG, + "galil" : WEAPON_TYPE_CARBINE, + "grail" : WEAPON_TYPE_ATAA, + "ied" : WEAPON_TYPE_C4, + "javelin" : WEAPON_TYPE_ATAA, + "ksvk" : WEAPON_TYPE_SNIPER, + "m72law" : WEAPON_TYPE_ATAA, + "m40A3_silenced" : WEAPON_TYPE_SNIPER, + "m40A3" : WEAPON_TYPE_SNIPER, + "psg1" : WEAPON_TYPE_SNIPER, + "rpg7" : WEAPON_TYPE_ATAA, + "sigp226" : WEAPON_TYPE_PISTOL, + "steyr_aug" : WEAPON_TYPE_CARBINE, + "steyr_aug_m203" : WEAPON_TYPE_CARBINE, + "steyr_aug_m203_gl" : WEAPON_TYPE_ASSAULTGRN, + "steyr_specops" : WEAPON_TYPE_CARBINE, + "stinger" : WEAPON_TYPE_ATAA, + "svds" : WEAPON_TYPE_SNIPER, + "ump45" : WEAPON_TYPE_PISTOL, + "uzi" : WEAPON_TYPE_SMG, + "mk19" : WEAPON_TYPE_ASSAULTGRN, + "oerlikonaa" : WEAPON_TYPE_ATAA, + "iraqat_rpg7" : WEAPON_TYPE_ATAA, + "usat_smaw" : WEAPON_TYPE_ATAA, + "iraqaa_sa7" : WEAPON_TYPE_ATAA, + "usaa_fm92a" : WEAPON_TYPE_ATAA, + "mim23" : WEAPON_TYPE_ATAA, + "sa-3" : WEAPON_TYPE_ATAA, + "rh202_aa" : WEAPON_TYPE_ATAA, + "Igla_tech" : WEAPON_TYPE_ATAA, + "civ2_tow" : WEAPON_TYPE_ATAA, + "tos1_missile" : WEAPON_TYPE_ATAA, + "tomahawk_bgm109" : WEAPON_TYPE_ATAA, + "mk48_torpedo" : WEAPON_TYPE_ATAA, + "m270_missile" : WEAPON_TYPE_ATAA, + "hh_stinger" : WEAPON_TYPE_ATAA, + "brad_missile" : WEAPON_TYPE_ATAA, + "b57_nuke" : WEAPON_TYPE_ATAA, + "zigs_hellfire" : WEAPON_TYPE_ATAA, + "minigun" : WEAPON_TYPE_SMG, + "hgr_smoke_1" : WEAPON_TYPE_HANDGRENADE, + "hgr_smoke_2" : WEAPON_TYPE_HANDGRENADE, +# AIX 2.0 TNG2.0 - Boosterpack + "chrif_type85_v2" : WEAPON_TYPE_SMG, + "hmg_m2hb" : WEAPON_TYPE_LMG, + "chhmg_kord" : WEAPON_TYPE_LMG +} + + +kitTypeMap = { + "us_at" : KIT_TYPE_AT, + "us_assault" : KIT_TYPE_ASSAULT, + "us_engineer" : KIT_TYPE_ENGINEER, + "us_medic" : KIT_TYPE_MEDIC, + "us_specops" : KIT_TYPE_SPECOPS, + "us_support" : KIT_TYPE_SUPPORT, + "us_sniper" : KIT_TYPE_SNIPER, + "mec_at" : KIT_TYPE_AT, + "mec_assault" : KIT_TYPE_ASSAULT, + "mec_engineer" : KIT_TYPE_ENGINEER, + "mec_medic" : KIT_TYPE_MEDIC, + "mec_specops" : KIT_TYPE_SPECOPS, + "mec_support" : KIT_TYPE_SUPPORT, + "mec_sniper" : KIT_TYPE_SNIPER, + "ch_at" : KIT_TYPE_AT, + "ch_assault" : KIT_TYPE_ASSAULT, + "ch_engineer" : KIT_TYPE_ENGINEER, + "ch_medic" : KIT_TYPE_MEDIC, + "ch_specops" : KIT_TYPE_SPECOPS, + "ch_support" : KIT_TYPE_SUPPORT, + "ch_sniper" : KIT_TYPE_SNIPER, +# xpack1 - SpecialForces + "seal_at" : KIT_TYPE_AT, + "seal_assault" : KIT_TYPE_ASSAULT, + "seal_engineer" : KIT_TYPE_ENGINEER, + "seal_medic" : KIT_TYPE_MEDIC, + "seal_specops" : KIT_TYPE_SPECOPS, + "seal_support" : KIT_TYPE_SUPPORT, + "seal_sniper" : KIT_TYPE_SNIPER, + "sas_at" : KIT_TYPE_AT, + "sas_assault" : KIT_TYPE_ASSAULT, + "sas_engineer" : KIT_TYPE_ENGINEER, + "sas_medic" : KIT_TYPE_MEDIC, + "sas_specops" : KIT_TYPE_SPECOPS, + "sas_support" : KIT_TYPE_SUPPORT, + "sas_sniper" : KIT_TYPE_SNIPER, + "spetsnaz_at" : KIT_TYPE_AT, + "spetsnaz_assault" : KIT_TYPE_ASSAULT, + "spetsnaz_engineer" : KIT_TYPE_ENGINEER, + "spetsnaz_medic" : KIT_TYPE_MEDIC, + "spetsnaz_specops" : KIT_TYPE_SPECOPS, + "spetsnaz_support" : KIT_TYPE_SUPPORT, + "spetsnaz_sniper" : KIT_TYPE_SNIPER, + "mecsf_at" : KIT_TYPE_AT, + "mecsf_assault" : KIT_TYPE_ASSAULT, + "mecsf_engineer" : KIT_TYPE_ENGINEER, + "mecsf_medic" : KIT_TYPE_MEDIC, + "mecsf_specops" : KIT_TYPE_SPECOPS, + "mecsf_support" : KIT_TYPE_SUPPORT, + "mecsf_sniper" : KIT_TYPE_SNIPER, + "chinsurgent_at" : KIT_TYPE_AT, + "chinsurgent_assault" : KIT_TYPE_ASSAULT, + "chinsurgent_engineer" : KIT_TYPE_ENGINEER, + "chinsurgent_medic" : KIT_TYPE_MEDIC, + "chinsurgent_specops" : KIT_TYPE_SPECOPS, + "chinsurgent_support" : KIT_TYPE_SUPPORT, + "chinsurgent_sniper" : KIT_TYPE_SNIPER, + "meinsurgent_at" : KIT_TYPE_AT, + "meinsurgent_assault" : KIT_TYPE_ASSAULT, + "meinsurgent_engineer" : KIT_TYPE_ENGINEER, + "meinsurgent_medic" : KIT_TYPE_MEDIC, + "meinsurgent_specops" : KIT_TYPE_SPECOPS, + "meinsurgent_support" : KIT_TYPE_SUPPORT, + "meinsurgent_sniper" : KIT_TYPE_SNIPER, + "mecsf_at_special" : KIT_TYPE_AT, + "mecsf_assault_special" : KIT_TYPE_ASSAULT, + "mecsf_specops_special" : KIT_TYPE_SPECOPS, + "mecsf_sniper_special" : KIT_TYPE_SNIPER, + "sas_at_special" : KIT_TYPE_AT, + "sas_assault_special" : KIT_TYPE_ASSAULT, + "sas_specops_special" : KIT_TYPE_SPECOPS, + "sas_sniper_special" : KIT_TYPE_SNIPER, +# booster pack 1 - Euroforces + "eu_at" : KIT_TYPE_AT, + "eu_assault" : KIT_TYPE_ASSAULT, + "eu_engineer" : KIT_TYPE_ENGINEER, + "eu_medic" : KIT_TYPE_MEDIC, + "eu_specops" : KIT_TYPE_SPECOPS, + "eu_support" : KIT_TYPE_SUPPORT, + "eu_sniper" : KIT_TYPE_SNIPER, +# POE2 + "ger_assault" : KIT_TYPE_ASSAULT, + "ger_at" : KIT_TYPE_AT, + "ger_engineer" : KIT_TYPE_ENGINEER, + "ger_medic" : KIT_TYPE_MEDIC, + "ger_sniper" : KIT_TYPE_SNIPER, + "ger_specops" : KIT_TYPE_SPECOPS, + "ger_support" : KIT_TYPE_SUPPORT, + "ukr_at" : KIT_TYPE_AT, + "ukr_assault" : KIT_TYPE_ASSAULT, + "ukr_engineer" : KIT_TYPE_ENGINEER, + "ukr_medic" : KIT_TYPE_MEDIC, + "ukr_specops" : KIT_TYPE_SPECOPS, + "ukr_support" : KIT_TYPE_SUPPORT, + "ukr_sniper" : KIT_TYPE_SNIPER, +# AIX 1.0 + "un_at" : KIT_TYPE_AT, + "un_assault" : KIT_TYPE_ASSAULT, + "un_engineer" : KIT_TYPE_ENGINEER, + "un_medic" : KIT_TYPE_MEDIC, + "un_sniper" : KIT_TYPE_SNIPER, + "un_specops" : KIT_TYPE_SPECOPS, + "un_support" : KIT_TYPE_SUPPORT, + # Pickup Kits + "assault_ak5" : KIT_TYPE_ASSAULT, + "assault_ak5" : KIT_TYPE_ASSAULT, + "assault_ak5" : KIT_TYPE_ASSAULT, + "assault_fn_fal" : KIT_TYPE_ASSAULT, + "assault_g36k" : KIT_TYPE_ASSAULT, + "assault_g3a3" : KIT_TYPE_ASSAULT, + "assault_gp25" : KIT_TYPE_ASSAULT, + "assault_gp30" : KIT_TYPE_ASSAULT, + "assault_m16_m203" : KIT_TYPE_ASSAULT, + "assault_m41a" : KIT_TYPE_ASSAULT, + "assault_sa80a2" : KIT_TYPE_ASSAULT, + "at_bizon" : KIT_TYPE_AT, + "at_eryx_lt" : KIT_TYPE_AT, + "at_mgl140" : KIT_TYPE_AT, + "at_mp5" : KIT_TYPE_AT, + "at_rpg7" : KIT_TYPE_AT, + "at_stinger" : KIT_TYPE_AT, + "at_strela2" : KIT_TYPE_AT, + "engineer_benelli_m4" : KIT_TYPE_ENGINEER, + "engineer_famas" : KIT_TYPE_ENGINEER, + "engineer_hk416" : KIT_TYPE_ENGINEER, + "engineer_jackhammer" : KIT_TYPE_ENGINEER, + "engineer_mk14ebr" : KIT_TYPE_ENGINEER, + "engineer_norinco982" : KIT_TYPE_ENGINEER, + "engineer_protecta" : KIT_TYPE_ENGINEER, + "engineer_remington11-87" : KIT_TYPE_ENGINEER, + "engineer_saiga12" : KIT_TYPE_ENGINEER, + "engineer_tavor" : KIT_TYPE_ENGINEER, + "medic_ak101" : KIT_TYPE_MEDIC, + "medic_ak47" : KIT_TYPE_MEDIC, + "medic_fs2000" : KIT_TYPE_MEDIC, + "medic_g36e" : KIT_TYPE_MEDIC, + "medic_m16a2" : KIT_TYPE_MEDIC, + "medic_sa80" : KIT_TYPE_MEDIC, + "medic_steyr_aug" : KIT_TYPE_MEDIC, + "sniper_as50" : KIT_TYPE_SNIPER, + "sniper_dragunov" : KIT_TYPE_SNIPER, + "sniper_dsr" : KIT_TYPE_SNIPER, + "sniper_l96a1" : KIT_TYPE_SNIPER, + "sniper_m109" : KIT_TYPE_SNIPER, + "sniper_m24" : KIT_TYPE_SNIPER, + "sniper_m82" : KIT_TYPE_SNIPER, + "sniper_m95_barret" : KIT_TYPE_SNIPER, + "sniper_tpg1" : KIT_TYPE_SNIPER, + "sniper_type88" : KIT_TYPE_SNIPER, + "specops_aix_famas" : KIT_TYPE_SPECOPS, + "specops_ak74u" : KIT_TYPE_SPECOPS, + "specops_fnscarl" : KIT_TYPE_SPECOPS, + "specops_g36c" : KIT_TYPE_SPECOPS, + "specops_hk53a3" : KIT_TYPE_SPECOPS, + "specops_m4" : KIT_TYPE_SPECOPS, + "specops_sg552" : KIT_TYPE_SPECOPS, + "specops_type95" : KIT_TYPE_SPECOPS, + "specops_xm8" : KIT_TYPE_SPECOPS, + "support_hk21" : KIT_TYPE_SUPPORT, + "support_m249saw" : KIT_TYPE_SUPPORT, + "support_mg36" : KIT_TYPE_SUPPORT, + "support_minigun" : KIT_TYPE_SUPPORT, + "support_minigun_mec" : KIT_TYPE_SUPPORT, + "support_pkm" : KIT_TYPE_SUPPORT, + "support_pkm" : KIT_TYPE_SUPPORT, + "support_stg58" : KIT_TYPE_SUPPORT, + "support_type95" : KIT_TYPE_SUPPORT, +# AIX 2.0 + "ch_assault-inf" : KIT_TYPE_ASSAULT, + "ch_at-inf" : KIT_TYPE_AT, + "ch_engineer-inf" : KIT_TYPE_ENGINEER, + "ch_sniper-inf" : KIT_TYPE_SNIPER, + "ch_specops-inf" : KIT_TYPE_SPECOPS, + "mec_assault-inf" : KIT_TYPE_ASSAULT, + "mec_at-inf" : KIT_TYPE_AT, + "mec_engineer-inf" : KIT_TYPE_ENGINEER, + "mec_sniper-inf" : KIT_TYPE_SNIPER, + "mec_specops-inf" : KIT_TYPE_SPECOPS, + "mec_support_pkm" : KIT_TYPE_SUPPORT, + "un_assault-inf" : KIT_TYPE_ASSAULT, + "un_at-inf" : KIT_TYPE_AT, + "un_engineer-inf" : KIT_TYPE_ENGINEER, + "un_sniper-inf" : KIT_TYPE_SNIPER, + "un_specops-inf" : KIT_TYPE_SPECOPS, + "us_assault-inf" : KIT_TYPE_ASSAULT, + "us_at-inf" : KIT_TYPE_AT, + "us_engineer-inf" : KIT_TYPE_ENGINEER, + "us_sniper-inf" : KIT_TYPE_SNIPER, + "us_specops-inf" : KIT_TYPE_SPECOPS, + "us_support_saw" : KIT_TYPE_SUPPORT, + # Pickup Kits + "engineer_tavor-inf" : KIT_TYPE_ENGINEER, + "sniper_m109-inf" : KIT_TYPE_SNIPER, + "specops_sg552-inf" : KIT_TYPE_SPECOPS, +#Hard Justice 1.3 + "us2_at" : KIT_TYPE_AT, + "us2_assault" : KIT_TYPE_ASSAULT, + "us2_engineer" : KIT_TYPE_ENGINEER, + "us2_medic" : KIT_TYPE_MEDIC, + "us2_specops" : KIT_TYPE_SPECOPS, + "us2_support" : KIT_TYPE_SUPPORT, + "us2_sniper" : KIT_TYPE_SNIPER, + "mec2_at" : KIT_TYPE_AT, + "mec2_assault" : KIT_TYPE_ASSAULT, + "mec2_engineer" : KIT_TYPE_ENGINEER, + "mec2_medic" : KIT_TYPE_MEDIC, + "mec2_specops" : KIT_TYPE_SPECOPS, + "mec2_support" : KIT_TYPE_SUPPORT, + "mec2_sniper" : KIT_TYPE_SNIPER, + "ch2_at" : KIT_TYPE_AT, + "ch2_assault" : KIT_TYPE_ASSAULT, + "ch2_engineer" : KIT_TYPE_ENGINEER, + "ch2_medic2" : KIT_TYPE_MEDIC, + "ch2_specops" : KIT_TYPE_SPECOPS, + "ch2_support" : KIT_TYPE_SUPPORT, + "ch2_sniper" : KIT_TYPE_SNIPER, + "us3_at" : KIT_TYPE_AT, + "us3_assault" : KIT_TYPE_ASSAULT, + "us3_engineer" : KIT_TYPE_ENGINEER, + "us3_medic" : KIT_TYPE_MEDIC, + "us3_specops" : KIT_TYPE_SPECOPS, + "us3_support" : KIT_TYPE_SUPPORT, + "us3_sniper" : KIT_TYPE_SNIPER, + "mec3_at" : KIT_TYPE_AT, + "mec3_assault" : KIT_TYPE_ASSAULT, + "mec3_engineer" : KIT_TYPE_ENGINEER, + "mec3_medic" : KIT_TYPE_MEDIC, + "mec3_specops" : KIT_TYPE_SPECOPS, + "mec3_support" : KIT_TYPE_SUPPORT, + "mec3_sniper" : KIT_TYPE_SNIPER, + "ch3_at" : KIT_TYPE_AT, + "ch3_assault" : KIT_TYPE_ASSAULT, + "ch3_engineer" : KIT_TYPE_ENGINEER, + "ch3_medic" : KIT_TYPE_MEDIC, + "ch3_specops" : KIT_TYPE_SPECOPS, + "ch3_support" : KIT_TYPE_SUPPORT, + "ch3_sniper" : KIT_TYPE_SNIPER, + "ca_at" : KIT_TYPE_AT, + "ca_assault" : KIT_TYPE_ASSAULT, + "ca_engineer" : KIT_TYPE_ENGINEER, + "ca_medic" : KIT_TYPE_MEDIC, + "ca_specops" : KIT_TYPE_SPECOPS, + "ca_support" : KIT_TYPE_SUPPORT, + "ca_sniper" : KIT_TYPE_SNIPER, +# AIX 2.0 TNG Maps + "ch_assault_v2" : KIT_TYPE_ASSAULT, + "ch_at_v2" : KIT_TYPE_AT, + "ch_engineer_v2" : KIT_TYPE_ENGINEER, + "ch_medic_v2" : KIT_TYPE_MEDIC, + "ch_sniper_v2" : KIT_TYPE_SNIPER, + "ch_specops_v2" : KIT_TYPE_SPECOPS, + "ch_support_v2" : KIT_TYPE_SUPPORT, + "mec_support_v2" : KIT_TYPE_SUPPORT, + "us_support_v2" : KIT_TYPE_SUPPORT, +# AIX 2.0 TNG 2.0 + "ch_assault_v2" : KIT_TYPE_ASSAULT, + "ch_at_v2" : KIT_TYPE_AT, + "ch_engineer_v2" : KIT_TYPE_ENGINEER, + "ch_medic_v2" : KIT_TYPE_MEDIC, + "ch_medic_v3" : KIT_TYPE_MEDIC, + "ch_sniper_v2" : KIT_TYPE_SNIPER, + "ch_specops_v2" : KIT_TYPE_SPECOPS, + "ch_support_v2" : KIT_TYPE_SUPPORT, + "ch_support_v3" : KIT_TYPE_SUPPORT, + "un_assault_v2" : KIT_TYPE_ASSAULT, + "un_at_v2" : KIT_TYPE_AT, + "un_engineer_v2" : KIT_TYPE_ENGINEER, + "un_medic_v2" : KIT_TYPE_MEDIC, + "un_medic_v3" : KIT_TYPE_MEDIC, + "un_specops_v2" : KIT_TYPE_SPECOPS, + "un_support_v2" : KIT_TYPE_SUPPORT, + "un_support_v3" : KIT_TYPE_SUPPORT, + "un_sniper_v2" : KIT_TYPE_SNIPER, + "mec_assault_v2" : KIT_TYPE_ASSAULT, + "mec_medic_v2" : KIT_TYPE_MEDIC, + "mec_medic_v3" : KIT_TYPE_MEDIC, + "mec_sniper_v2" : KIT_TYPE_SNIPER, + "mec_specops_v2" : KIT_TYPE_SPECOPS, + "mec_support_v3" : KIT_TYPE_SUPPORT, + "us_assault_v2" : KIT_TYPE_ASSAULT, + "us_at_v2" : KIT_TYPE_AT, + "us_engineer_v2" : KIT_TYPE_ENGINEER, + "us_medic_v2" : KIT_TYPE_MEDIC, + "us_sniper_v2" : KIT_TYPE_SNIPER, + "us_specops_v2" : KIT_TYPE_SPECOPS, +# NAV - Nations@War 6.0 + "iran_specops" : KIT_TYPE_SPECOPS, + "iraq_sniper" : KIT_TYPE_SNIPER, + "czh_sniper" : KIT_TYPE_SNIPER, + "kor_assault" : KIT_TYPE_ASSAULT, + "uk_assault" : KIT_TYPE_ASSAULT, + "jap_support" : KIT_TYPE_SUPPORT, + "nor_support" : KIT_TYPE_SUPPORT, + "ch_engineer" : KIT_TYPE_ENGINEER, + "ger_engineer" : KIT_TYPE_ENGINEER, + "pak_medic" : KIT_TYPE_MEDIC, + "den_medic" : KIT_TYPE_MEDIC, + "syr_at" : KIT_TYPE_AT, + "can_at" : KIT_TYPE_AT, + "us_support_super" : KIT_TYPE_SUPPORT, + "us_sniper_super" : KIT_TYPE_SNIPER, + "us_engineer_super" : KIT_TYPE_ENGINEER, + "us_antiair" : KIT_TYPE_AT, + "ch_engineer_super" : KIT_TYPE_ENGINEER, + "ch_antiair" : KIT_TYPE_AT, + "ch_support_super" : KIT_TYPE_SUPPORT, + "ch_sniper_super" : KIT_TYPE_SNIPER, +# AIX 2.0 TNG2.0 - Boosterpack + "mec_at_v2" : KIT_TYPE_AT, + "mec_engineer_v2" : KIT_TYPE_ENGINEER, + "us_medic_v3" : KIT_TYPE_MEDIC, + "us_support_v3" : KIT_TYPE_SUPPORT +} + +armyMap = { +# Battlefield2 + "us" : ARMY_USA, + "mec" : ARMY_MEC, + "ch" : ARMY_CHINESE, +# xpack1 - SpecialForces + "seal" : ARMY_SEALS, + "sas" : ARMY_SAS, + "spetz" : ARMY_SPETZNAS, + "mecsf" : ARMY_MECSF, + "chinsurgent" : ARMY_REBELS, + "meinsurgent" : ARMY_INSURGENTS, +# booster pack 1 - Euroforces + "eu" : ARMY_EURO, +# POE2 + "ger" : ARMY_GER, + "ukr" : ARMY_UKR, +# AIX + "un" : ARMY_UN, +# Hard Justice + "us2" : ARMY_USA, + "us3" : ARMY_USA, + "mec2" : ARMY_MEC, + "mec3" : ARMY_MEC, + "ch2" : ARMY_CHINESE, + "ch3" : ARMY_CHINESE, + "ca" : ARMY_CANADIAN +} + + +mapMap = { +# !! Doppelte Maps sind auskommentiert, bei bedarf aendern!! +# Battlefield2 + # middle eastern theater + "kubra_dam" : "0", + "mashtuur_city" : "1", + "operation_clean_sweep" : "2", + "zatar_wetlands" : "3", + "strike_at_karkand" : "4", + "sharqi_peninsula" : "5", + "gulf_of_oman" : "6", + "operationsmokescreen" : "10", + "taraba_quarry" : "11", + "road_to_jalalabad" : "12", + # Asian Theater + "daqing_oilfields" : "100", + "dalian_plant" : "101", + "dragon_valley" : "102", + "fushe_pass" : "103", + "hingan_hills" : "104", + "songhua_stalemate" : "105", + "greatwall" : "110", + # US Theatre + "midnight_sun" : "200", + "operationroadrage" : "201", + "operationharvest" : "202", + # xpack1 - SpecialForces + "devils_perch" : "300", + "iron_gator" : "301", + "night_flight" : "302", + "warlord" : "303", + "leviathan" : "304", + "mass_destruction" : "305", + "surge" : "306", + "ghost_town" : "307", + # Special maps + "wake_island_2007" : "601", + "highway_tampa" : "602", + "operation_blue_pearl" : "603", +# BF2 SPX / BoosterSP + "operationsmokescrenn" : "10", + "taraba_quarre" : "11", + "greatwall64" : "110", + "midnight_off" : "200", + "operationrage" : "201", + "operationroadragg" : "201", + "operationharvess" : "202", +# BF2SFSP + "sf_devils_perch" : "300", + "sf_iron_gator" : "301", + "sf_night_flight" : "302", + "sf_warlord" : "303", + "sf_leviathan" : "304", + "sf_mass_destruction" : "305", + "sf_surge" : "306", + "sf_ghost_town" : "307", + "mass_invasion" : "305", +# POE2 + "battle_of_sambir" : "1001", + "carpathian_mountains" : "1002", + "dnipro_sunrise" : "1003", + "dnister_river_valley" : "1004", + "fallen" : "1005", + "first_snow" : "1006", + "guardian" : "1007", + "highway_to_hell" : "1008", + "lutsk" : "1009", + "orel" : "1010", + "rivne" : "1011", + "rolling_thunder" : "1012", + "zhytomyr" : "1013", + "spies_like_us" : "1014", +# AIX 1.0 + "aix_archipelago" : "3000", + "aix_damocles" : "3001", + "daqing_dawn" : "3002", + "dragon_valley_moon" : "3003", + "falklands" : "3004", + #"gulf_of_oman" : "3005", #In Battlefield 2 vorhanden + "karkand_stormfront" : "3006", + "processing_plant" : "3007", + "aix_refinery" : "3008", + "aix_runningman" : "3009", + #"sharqi_peninsula" : "3010", #In Battlefield 2 vorhanden + "the_push_day" : "3011", + "urban_jungle" : "3012", + "wake_twilight" : "3013", + "zatar_wetlands_ii" : "3014", + "zzz_easter_island" : "3015", +# AIX 1.0 ITTH MapPack 1 + "end_of_the_line" : "3020", + "kursk" : "3021", + "marauders_at_midnight" : "3022", + "midway" : "3023", + "snowy_park" : "3024", + "snowy_park_day" : "3025", + "snowy_park_summer" : "3026", + "solomon_showdown" : "3027", +# AIX 1.0 ITTH MapPack 2 + "battle_of_kirkuk_oilfields" : "3030", + "husky" : "3031", + "invasion_of_the_philippines" : "3032", + "iron_thunder" : "3033", + "operation_fox" : "3034", +# AIX 1.0 ITTH MapPack 3 + "eagles_nest" : "3040", + "iwo_jima" : "3041", + "manamoc_island" : "3042", + "rebellion" : "3043", + "red_dawn" : "3044", + "tobruk" : "3045", +# AIX 2.0 + #"aix_archipelago" : "3100", #In AIX 1.0 vorhanden + #"aix_damocles" : "3101", #In AIX 1.0 vorhanden + "aix_greasy_mullet" : "3102", + "aix_hammer_down" : "3103", + "aix_operation_static" : "3104", + #"aix_refinery" : "3105", #In AIX 1.0 vorhanden + #"aix_runningman" : "3106", #In AIX 1.0 vorhanden + "aix_trident" : "3107", + "aix_wake_island_2007" : "3108", + "city_district" : "3109", + #"dalian_plant" : "3110", #In Battlefield 2 vorhanden + #"daqing_dawn" : "3111", #In AIX 1.0 vorhanden + #"dragon_valley" : "3112", #In Battlefield 2 vorhanden + #"dragon_valley_moon" : "3113", #In AIX 1.0 vorhanden + #"falklands" : "3114", #In AIX 1.0 vorhanden + #"gulf_of_oman" : "3115", #In AIX 1.0 vorhanden + #"karkand_stormfront" : "3116", #In AIX 1.0 vorhanden + #"processing_plant" : "3117", #In AIX 1.0 vorhanden + #"sharqi_peninsula" : "3118", #In AIX 1.0 vorhanden + #"the_push_day" : "3119", #In AIX 1.0 vorhanden + #"urban_jungle" : "3120", #In AIX 1.0 vorhanden + #"wake_twilight" : "3121", #In AIX 1.0 vorhanden + #"zatar_wetlands_ii" : "3122", #In AIX 1.0 vorhanden + #"zzz_easter_island" : "3123", #In AIX 1.0 vorhanden +# AIX 2.0 ITTH MapPack + "aberdeen" : "3150", + "bataan" : "3151", + #"battle_of_kirkuk_oilfields" : "3152", # In AIX 1.0 ITTH MapPack 2 vorhanden + "battleaxe" : "3153", + "bizerte" : "3154", + "city_park" : "3155", + "city_park_night" : "3156", + #"eagles_nest" : "3157", # In AIX 1.0 ITTH MapPack 3 vorhanden + #"end_of_the_line" : "3158", # In AIX 1.0 ITTH MapPack 1 vorhanden + "guadalcanal" : "3159", + #"husky" : "3160", # In AIX 1.0 ITTH MapPack 2 vorhanden + "invasion_of_the_coral_sea" : "3161", + #"invasion_of_the_philippines" : "3162", # In AIX 1.0 ITTH MapPack 2 vorhanden + #"iron_thunder" : "3163", # In AIX 1.0 ITTH MapPack 2 vorhanden + #"iwo_jima" : "3164", # In AIX 1.0 ITTH MapPack 3 vorhanden + "kasserine_pass_2008" : "3165", + #"kursk" : "3166", # In AIX 1.0 ITTH MapPack 1 vorhanden + #"manamoc_island" : "3167", # In AIX 1.0 ITTH MapPack 3 vorhanden + #"marauders_at_midnight" : "3168", # In AIX 1.0 ITTH MapPack 1 vorhanden + #"midway" : "3169", # In AIX 1.0 ITTH MapPack 1 vorhanden + #"operation_fox" : "3170", # In AIX 1.0 ITTH MapPack 2 vorhanden + "raid_on_agheila" : "3171", + #"rebellion" : "3172", # In AIX 1.0 ITTH MapPack 3 vorhanden + #"red_dawn" : "3173", # In AIX 1.0 ITTH MapPack 3 vorhanden + #"snowy_park" : "3174", # In AIX 1.0 ITTH MapPack 1 vorhanden + #"snowy_park_day" : "3175", # In AIX 1.0 ITTH MapPack 1 vorhanden + #"snowy_park_summer" : "3176", # In AIX 1.0 ITTH MapPack 1 vorhanden + #"solomon_showdown" : "3177", # In AIX 1.0 ITTH MapPack 1 vorhanden + #"tobruk" : "3178", # In AIX 1.0 ITTH MapPack 3 vorhanden + "urban_decay" : "3179", +# AIX 2 TNG + "tng_archipelago" : "3300", + "tng_clean_sweep_ii" : "3301", + "tng_dalian_plant" : "3302", + "tng_daqing_dawn" : "3303", + "tng_dragon_valley_moon" : "3304", + "tng_frostbite" : "3305", + "tng_fushe_pass" : "3306", + "tng_gazala_v2" : "3307", + "tng_archipelago_moon" : "3308", + "tng_gulf_of_oman" : "3309", + "tng_highway_tampa" : "3310", + "tng_iwo_jima" : "3311", + "tng_kirkuk_basin" : "3312", + "tng_kubra_dam" : "3313", + "tng_the_dam_flood" : "3314", + "tng_the_push_day" : "3315", + "tng_town_strike" : "3316", + "tng_trident" : "3317", + "tng_trident_moon" : "3318", + "tng_wake_island" : "3319", + "tng_zatar_wetlands_ii" : "3320", +# AIX 2 TNG 2.0 + "tng_airport" : "3350", + #"tng_archipelago" : "3351", # In AIX 2 TNG schon vorhanden + #"tng_archipelago_moon" : "3352", # In AIX 2 TNG schon vorhanden + #"tng_clean_sweep_ii" : "3353", # In AIX 2 TNG schon vorhanden + "tng_course_of_the_river" : "3354", + #"tng_dalian_plant" : "3355", # In AIX 2 TNG schon vorhanden + #"tng_daqing_dawn" : "3356", # In AIX 2 TNG schon vorhanden + "tng_dragon_valley" : "3357", + #"tng_dragon_valley_moon" : "3358", # In AIX 2 TNG schon vorhanden + #"tng_frostbite" : "3359", # In AIX 2 TNG schon vorhanden + #"tng_fushe_pass" : "3360", # In AIX 2 TNG schon vorhanden + #"tng_gazala_v2" : "3361", # In AIX 2 TNG schon vorhanden + #"tng_gulf_of_oman" : "3362", # In AIX 2 TNG schon vorhanden + #"tng_highway_tampa" : "3363", # In AIX 2 TNG schon vorhanden + "tng_kandahar_river_valley" : "3364", + #"tng_kirkuk_basin" : "3365", # In AIX 2 TNG schon vorhanden + #"tng_kubra_dam" : "3366", # In AIX 2 TNG schon vorhanden + "tng_oasis_revisited" : "3367", + "tng_op_yellow_dragon" : "3368", + "tng_road_to_jalalabad" : "3369", + "tng_sands_of_sinai" : "3370", + "tng_street" : "3371", + #"tng_the_dam_flood" : "3372", # In AIX 2 TNG schon vorhanden + #"tng_the_push_day" : "3373", # In AIX 2 TNG schon vorhanden + "tng_the_sniper_day" : "3374", + #"tng_town_strike" : "3375", # In AIX 2 TNG schon vorhanden + #"tng_trident" : "3376", # In AIX 2 TNG schon vorhanden + #"tng_trident_moon" : "3377", # In AIX 2 TNG schon vorhanden + #"tng_wake_island" : "3378", # In AIX 2 TNG schon vorhanden + "tng_wake_twilight" : "3379", + #"tng_zatar_wetlands_ii" : "3380", # In AIX 2 TNG schon vorhanden +# Hard Justice 1.3 + "basrah" : "4000", + #"dalian_plant" : "4001", #In Battlefield 2 vorhanden + #"daqing_oilfields" : "4002", #In Battlefield 2 vorhanden + "desert_shield_advanced" : "4003", + #"dragon_valley" : "4004", #In Battlefield 2 vorhanden + #"fuShe_pass" : "4005", #In Battlefield 2 vorhanden + #"gulf_of_oman" : "4006", #In Battlefield 2 vorhanden + #"highway_tampa" : "4007", #In Battlefield 2 vorhanden + "island_city" : "4008", + "juno_beach" : "4009", + "kandaharpatrol" : "4010", + #"kubra_dam" : "4011", #In Battlefield 2 vorhanden + "lost_island" : "4012", + #"mashtuur_city" : "4013", #In Battlefield 2 vorhanden + "omaha_beach_2008" : "4014", + #"operation_clean_sweep" : "4015", #In Battlefield 2 vorhanden + "remagen_bridge" : "4016", + #"road_to_jalalabad" : "4017", #In Battlefield 2 vorhanden + "road_to_karkand" : "4018", + #"sharqi_peninsula" : "4019", #In Battlefield 2 vorhanden + #"songhua_stalemate" : "4020", #In Battlefield 2 vorhanden + #"strike_at_karkand" : "4021", #In Battlefield 2 vorhanden + "the_harbor" : "4022", + "the_middle_ground" : "4023", + #"wake_island_2007" : "4024", #In Battlefield 2 vorhanden + "weapon_bunker" : "4025", + #"zatar_wetlands" : "4026", #In Battlefield 2 vorhanden +# Hard Justice Mappack 1 + # "battle_of_kirkuk_oilfields" : "4030", #In AIX 1.0 ITTH MapPack 2 vorhanden + "bl_bridge2b" : "4031", + "course_of_the_river" : "4032", + "cult_site" : "4033", + "desert_storm" : "4034", + "divided_city" : "4035", + "el_alamein_day1" : "4036", + "gulf_of_aqaba_bfsp" : "4037", + "jammed" : "4038", + "kyzyl_kum" : "4039", + "requiem" : "4040", +# Hard Justice Mappack 2 + "insurgency_on_alcatraz_island" : "4050", + "nantari_crossing" : "4051", + "operation_amos" : "4052", + "operation_compton" : "4053", + "operation_frog" : "4054", + "operation_nightshift" : "4055", + "operation_power_failure_bfsp" : "4056", + "street" : "4057", + #"tobruk" : "4058", # In AIX 1.0 ITTH MapPack 3 vorhanden + "vulcan_island" : "4059", + "zhanjiang_security_area" : "4060", +# Hard Justice Mappack 3 + "heli_attack" : "4070", + "imprisoned" : "4071", + "jibbel_city" : "4072", + "last_stand" : "4073", + #"red_dawn" : "4074", # In AIX 1.0 ITTH MapPack 3 vorhanden + "sands_of_sinai_v1_1" : "4075", + "snow_soldier" : "4076", + "steel_thunder" : "4077", + "volgograd_2010" : "4078", +# Nation@War 6.0 + "adh_oasis_revisited" : "4200", + "al_khafji_docks" : "4201", + "a_bad_surprise" : "4202", + "back_to_the_suribachi" : "4203", + "basrahs_edge_bfds" : "4204", + "berlin" : "4205", + #"bl_bridge2b" : "4206", # In Hard Justice vorhanden + "cat_island" : "4207", + "christmas_hill" : "4208", + "dalian_2" : "4209", + #"daqing_oilfields" : "4210", #In Battlefield 2 vorhanden + #"dragon_valley" : "4211", #In Battlefield 2 vorhanden + #"eagles_nest" : "4212", # In AIX 1.0 ITTH MapPack 3 vorhanden + "el_alamein_bfds_sp" : "4213", + #"end_of_the_line" : "4214", # In AIX 1.0 ITTH MapPack 1 vorhanden + "forest_railway" : "4215", + #"frostbite" : "4216", # In AIX 2 TNG vorhanden + "frostbite_night" : "4217", + #"fushe_pass" : "4218", #In Battlefield 2 vorhanden + "gazala_bfds_v2" : "4219", + #"greatwall" : "4220", #In Battlefield 2 vorhanden + #"gulf_of_oman" : "4221", #In Battlefield 2 vorhanden + "heaven_and_hell" : "4222", + #"highway_tampa" : "4223", #In Battlefield 2 vorhanden + #"invasion_of_the_coral_sea" : "4224", #In AIX 2.0 ITTH MapPack vorhanden + #"invasion_of_the_philippines" : "4225", # In AIX 1.0 ITTH MapPack 2 vorhanden + "iraq_oilfields" : "4226", + #"iwo_jima" : "4227", # In AIX 1.0 ITTH MapPack 3 vorhanden + #"jibbel_city" : "4228", #In Hard Justice Mappack 3 vorhanden + #"kasserine_pass" : "4229", #In AIX 2.0 ITTH MapPack vorhanden + #"kubra_dam" : "4230", #In Battlefield 2 vorhanden + "last_stand_snipers" : "4231", + #"mashtuur_city" : "4232", #In Battlefield 2 vorhanden + #"midnight_sun" : "4233", #In Battlefield 2 vorhanden + #"midway" : "4234", # In AIX 1.0 ITTH MapPack 1 vorhanden + "none_but_the_brave" : "4235", + #"operationharvest" : "4236", #In Battlefield 2 vorhanden + #"operationroadrage" : "4237", #In Battlefield 2 vorhanden + #"operationsmokescreen" : "4238", #In Battlefield 2 vorhanden + "operation_black_hawk_down" : "4239", + #"operation_blue_pearl" : "4240", #In Battlefield 2 vorhanden + #"operation_clean_sweep" : "4241", #In Battlefield 2 vorhanden + "operation_gatecrasher" : "4242", + "philippine_sea" : "4243", + "pripiyat" : "4244", + "prologue" : "4245", + #"road_to_jalalabad" : "4246", #In Battlefield 2 vorhanden + #"sharqi_peninsula" : "4247", #In Battlefield 2 vorhanden + #"songhua_stalemate" : "4248", #In Battlefield 2 vorhanden + "stalingrad" : "4249", + #"strike_at_karkand" : "4250", #In Battlefield 2 vorhanden + "strike_at_karkand_2" : "4251", + "sunset_in_tunisia" : "4252", + #"taraba_quarry" : "4253", #In Battlefield 2 vorhanden + "terminus" : "4254", + #"tobruk" : "4255", # In AIX 1.0 ITTH MapPack 3 vorhanden + "urban_raid" : "4256", + "village_lost" : "4257", + #"vulcan_island" : "4258", # In Hard Justice Mappack 2 vorhanden + #"wake_island_2007" : "4259", #In Battlefield 2 vorhanden + "warbirds_ii" : "4260", + "waterfront" : "4261", + "waylaid" : "4262", + #"zatar_wetlands" : "4263", #In Battlefield 2 vorhanden + "zblankmap" : "4264", +# AIX 2.0 TNG2.0 - Boosterpack + "tng_greatwall" : "4270", + "tng_midnight_sun" : "4271", + "tng_op_harvest" : "4272", + "tng_op_roadrage" : "4273", + "tng_operation_smoke_screen" : "4274", + "tng_taraba_quarry" : "4275", +# NEM2 Network Entertaiment Mod 2 + "nem2_go" : "4300", + "nem2_gor" : "4301", + "nem2_ht" : "4302", + "nem2_htr" : "4303", + "nem2_kd" : "4304", + "nem2_kdr" : "4305", + "nem2_mc" : "4306", + "nem2_mcr" : "4307", + "nem2_ocs" : "4308", + "nem2_ocsr" : "4309", + "nem2_rtj" : "4310", + "nem2_rtjd" : "4311", + "nem2_rtjn" : "4312", + "nem2_rtjr" : "4313", + "nem2_sak" : "4314", + "nem2_sakr" : "4315", + "nem2_sp" : "4316", + "nem2_spr" : "4317", + "nem2_custom_dw" : "4318", + "nem2_custom_e" : "4319", + "nem2_custom_h" : "4320", + "nem2_custom_hahr" : "4321", + "nem2_custom_jc" : "4322", + "nem2_custom_ocb" : "4323", + "nem2_custom_sp" : "4324", + "nem2_custom_uj" : "4325", + "nem2_custom_ujd" : "4326", + "nem2_extra_ig" : "4327", + "nem2_extra_gt" : "4328", + "nem2_extra_md" : "4329", + "nem2_extra_s" : "4330", + "nem2_extra_w" : "4331", + "nem2_bonus_f" : "4332", + "nem2_bonus_fn" : "4333", + "nem2_bonus_1" : "4334", + "nem2_bonus_2" : "4335", + "nem2_bonus_3" : "4336", + "nem2_inf_1" : "4337", + "nem2_inf_2" : "4338", + "nem2_inf_3" : "4339", + "nem2_inf_4" : "4340", + "nem2_inf_5" : "4341", + "nem2_tank_aj" : "4342", + "nem2_tank_av" : "4343", + "nem2_tank_b" : "4344", + "nem2_tank_ko" : "4345", + "nem2_tank_og" : "4346", +# Add your Custom Maps Here, Don't forget the Comma! + "operation_hydra" : "5000" + +} +UNKNOWN_MAP = 99 + +gameModeMap = { + "gpm_cq" : 0, + "gpm_sl" : 1, + "gpm_coop" : 2, +} +UNKNOWN_GAMEMODE = 99 + + + +def getVehicleType(templateName): + return vehicleTypeMap.get(templateName.lower(), VEHICLE_TYPE_UNKNOWN) + + +def getWeaponType(templateName): + return weaponTypeMap.get(templateName.lower(), WEAPON_TYPE_UNKNOWN) + + +def getKitType(templateName): + return kitTypeMap.get(templateName.lower(), KIT_TYPE_UNKNOWN) + + +def getArmy(templateName): + return armyMap.get(templateName.lower(), ARMY_UNKNOWN) + + +def getMapId(mapName): + return mapMap.get(mapName.lower(), UNKNOWN_MAP) + + +def getGameModeId(gameMode): + return gameModeMap.get(gameMode.lower(), UNKNOWN_GAMEMODE) + + +def getRootParent(obj): + parent = obj.getParent() + + if parent == None: + return obj + + return getRootParent(parent) + + +if g_debug: print "Stat constants loaded" \ No newline at end of file diff --git a/src/python/bf2/stats/endofround.py b/src/python/bf2/stats/endofround.py new file mode 100644 index 00000000..7a57d5f5 --- /dev/null +++ b/src/python/bf2/stats/endofround.py @@ -0,0 +1,99 @@ +import host +import bf2.PlayerManager +import bf2.GameLogic +from constants import * +from bf2 import g_debug +from bf2.stats.stats import getStatsMap + + + +def init(): + host.registerHandler('ConsoleSendCommand', onSendCommand) + if g_debug: print "End of round module initialized." + + +def onSendCommand(command, args): + #if g_debug: print "command:", command, " args:", args + if string.lower(command) == "eor": + for p in bf2.playerManager.getPlayers(): + bf2.stats.stats.finalizePlayer(p) + + invoke() + +def invoke(): + if g_debug: print "Invoked end-of-round data-send" + + # collect needed stats + e = {} + + statsMap = getStatsMap() + + # find top player in different categories + for sp in statsMap.itervalues(): + for k in range(0, NUM_KIT_TYPES + 1): + if k in sp.kits and sp.kits[k].timeInObject > 0: + findTop(e, "sk" + str(k), "skn" + str(k), sp.kits[k].score, sp.name) + + for v in range(0, NUM_VEHICLE_TYPES + 1): + if v in sp.vehicles and sp.vehicles[v].timeInObject > 0: + findTop(e, "sv" + str(v), "svn" + str(v), sp.vehicles[v].score, sp.name) + + findTop(e, "ts", "tsn", sp.teamScore, sp.name) + findTop(e, "ss", "ssn", sp.skillScore, sp.name) + findTop(e, "cpc", "cpcn", sp.localScore.cpCaptures, sp.name) + findTop(e, "cpa", "cpan", sp.localScore.cpAssists, sp.name) + findTop(e, "cpd", "cpdn", sp.localScore.cpDefends, sp.name) + findTop(e, "ka", "kan", sp.localScore.damageAssists + sp.localScore.targetAssists + sp.localScore.passengerAssists, sp.name) + findTop(e, "he", "hen", sp.localScore.heals, sp.name) + findTop(e, "rev", "revn", sp.localScore.revives, sp.name) + findTop(e, "rsp", "rspn", sp.localScore.ammos, sp.name) + findTop(e, "rep", "repn", sp.localScore.repairs, sp.name) + findTop(e, "drs", "drsn", sp.localScore.driverSpecials + sp.localScore.driverAssists, sp.name) + + + # find top-3 + if len(statsMap) > 0: + sortedPlayers = [] + for sp in statsMap.itervalues(): + sortedPlayers += [((sp.score, sp.skillScore, -sp.deaths), sp)] + + sortedPlayers.sort() + sortedPlayers.reverse() + + # stats for top-3 scoring players + for i in range(3): + if len(sortedPlayers) <= i: + break + + sp = sortedPlayers[i][1] + e["np" + str(i)] = sp.name + e["tsp" + str(i)] = sp.teamScore + e["ssp" + str(i)] = sp.skillScore + e["csp" + str(i)] = sp.cmdScore + e["bfp" + str(i)] = sp.bulletsFired + e["bhp" + str(i)] = sp.bulletsHit + for k in range(0, NUM_KIT_TYPES + 1): + if sp.kits[k].timeInObject > 0: + e["tk" + str(k) + "p" + str(i)] = int(sp.kits[k].timeInObject) + + for v in range(0, NUM_VEHICLE_TYPES + 1): + if sp.vehicles[v].timeInObject > 0: + e["tv" + str(v) + "p" + str(i)] = int(sp.vehicles[v].timeInObject) + + keyvals = [] + for k in e: + keyvals.append ("\\".join((k, str(e[k])))) + + dataString = "\\" + "\\".join(keyvals) + + if g_debug: print dataString + host.gl_sendEndOfRoundData(dataString) + + + +def findTop(e, vkey, nkey, value, name): + if not vkey in e or value > e[vkey]: + e[vkey] = value + e[nkey] = name + + diff --git a/src/python/bf2/stats/fragalyzer_log.py b/src/python/bf2/stats/fragalyzer_log.py new file mode 100644 index 00000000..8c2e0fbe --- /dev/null +++ b/src/python/bf2/stats/fragalyzer_log.py @@ -0,0 +1,413 @@ +# fragalyzer log file generator. +# +# enable by typing this in the console: +# pythonHost.sendCommand falog 1 + +# needs to be re-enabled in each round. + +import host +import bf2.PlayerManager +import bf2.GameLogic +import fpformat +import datetime +import time +import fpformat +from constants import * +from bf2 import g_debug + +logfile = None +fileName = "" + + +def init(): + host.registerHandler('ConsoleSendCommand', onSendCommand) + + if g_debug: print "Fragalyzer log module initialized." + + +def enable(): + global fileName + global logfile + global startTime + + if logfile and not logfile.closed: + print "Fragalyzer logging already enabled" + return + + host.registerGameStatusHandler(onGameStatusChanged) + + currentDate = datetime.datetime.today() + dateString = "" + dateString = time.strftime("%y%m%d_%H%M", currentDate.timetuple()) + + if dateString != "": + fileName = bf2.gameLogic.getModDir() + "/Logs/" + bf2.gameLogic.getMapName() + "_" + dateString + "_faLog.txt" + else: + fileName = bf2.gameLogic.getModDir() + "/Logs/" + bf2.gameLogic.getMapName() + "_faLog.txt" + + fileName = fileName.replace('/', '\\') + + print "log file: ", fileName + + try: + logfile = file (fileName, 'w') + except Exception: + if g_debug: print "Couldnt open fragalyzer logfile: ", fileName + return + + startTime = int(date()) + timeString = str(startTime) + startDate = time.strftime("%Y.%m.%d,%H:%M", currentDate.timetuple()) + logfile.write("INIT LevelName=" + bf2.gameLogic.getMapName() + " StartTime=" + timeString + " StartDate=" + startDate + " Filename=" + fileName + "\n") + + logfile.flush() + + + # register events + host.registerHandler('PlayerKilled', onPlayerKilled) + host.registerHandler('PlayerDeath', onPlayerDeath) + host.registerHandler('EnterVehicle', onEnterVehicle) + host.registerHandler('ExitVehicle', onExitVehicle) + host.registerHandler('PickupKit', onPickupKit) + host.registerHandler('DropKit', onDropKit) + host.registerHandler('ControlPointChangedOwner', onCPStatusChange) + host.registerHandler('PlayerScore', onPlayerScore) + host.registerHandler('PlayerSpawn', onPlayerSpawn) + + host.registerHandler('PlayerConnect', onPlayerConnect, 1) + + #host.registerHandler('DeployGrapplingHook', onDeployGrapplingHook) + #host.registerHandler('DeployZipLine', onDeployZipLine) + #host.registerHandler('DeployTactical', onDeployTactical) + + # Connect already connected players if reinitializing + for p in bf2.playerManager.getPlayers(): + onPlayerConnect(p) + + print "Fragalyzer logging enabled." + + +class faStat: + def __init__(self): + self.enterAt = 0 + self.enterTemplate = None + self.spawnAt = 0 + + def copyStats(self, player): + self.damageAssists = player.score.damageAssists + self.passengerAssists = player.score.passengerAssists + self.targetAssists = player.score.targetAssists + self.revives = player.score.revives + self.teamDamages = player.score.teamDamages + self.teamVehicleDamages = player.score.teamVehicleDamages + self.cpCaptures = player.score.cpCaptures + self.cpDefends = player.score.cpDefends + self.cpAssists = player.score.cpAssists + self.cpNeutralizes = player.score.cpNeutralizes + self.cpNeutralizeAssists = player.score.cpNeutralizeAssists + self.suicides = player.score.suicides + self.kills = player.score.kills + self.TKs = player.score.TKs + + def getChangedStats(self, player): + res = [] + if player.score.cpCaptures > self.cpCaptures: + res += ["cpCaptures"] + if player.score.cpDefends > self.cpDefends: + res += ["cpDefends"] + if player.score.cpAssists > self.cpAssists: + res += ["cpAssists"] + if player.score.cpNeutralizes > self.cpNeutralizes: + res += ["cpNeutralizes"] + if player.score.cpNeutralizeAssists > self.cpNeutralizeAssists: + res += ["cpNeutralizeAssists"] + if player.score.suicides > self.suicides: + res += ["suicides"] + if player.score.kills > self.kills: + res += ["kills"] + if player.score.TKs > self.TKs: + res += ["TKs"] + if player.score.damageAssists > self.damageAssists: + res += ["damageAssists"] + if player.score.passengerAssists > self.passengerAssists: + res += ["passengerAssists"] + if player.score.targetAssists > self.targetAssists: + res += ["targetAssists"] + if player.score.revives > self.revives: + res += ["revives"] + if player.score.teamDamages > self.teamDamages: + res += ["teamDamages"] + if player.score.teamVehicleDamages > self.teamVehicleDamages: + res += ["teamVehicleDamages"] + + + return res + + +def onPlayerConnect(player): + player.fa = faStat() + player.fa.enterAt = date() + if player.isAlive(): + player.fa.spawnAt = date() + vehicle = player.getVehicle() + onEnterVehicle(player, vehicle) + kit = player.getKit() + if kit: + onPickupKit(player, kit) + + player.fa.copyStats(player) + + +def disable(): + if logfile: + timeString = str(int(date())) + logfile.write("DISABLE LevelName=" + bf2.gameLogic.getMapName() + " EndTime=" + timeString + "\n") + logfile.close() + print "Fragalyzer logging disabled." + else: + print "Fragalyzer logging was already disabled." + + + +def onGameStatusChanged(status): + if status == bf2.GameStatus.Playing: + pass + + elif status == bf2.GameStatus.EndGame: + disable() + + +def getPosStr(orgPos): + worldSize = bf2.gameLogic.getWorldSize(); + scale = [512.0 / worldSize[0], 1, 512.0 / worldSize[1]] + pos = [orgPos[0] * scale[0], orgPos[1] * scale[1], orgPos[2] * scale[2]] + res = str(fpformat.fix(pos[0], 3)) + "," + str(fpformat.fix(pos[1], 3)) + "," + str(fpformat.fix(pos[2], 3)) + return res + + +def onSendCommand(command, args): + if string.lower(command) == "falog": + if len(args) > 0: + if args[0] == "1": + enable() + elif args[0] == "0": + disable() + + +def date(): + return host.timer_getWallTime() + +def wallString(): + return str(int(host.timer_getWallTime()) - startTime) + +#********************************************************* +# XPACK SPECIFIC +#********************************************************* +def onDeployGrapplingHook(player): + vehicle = player.getVehicle() + name = player.getName() + team = str(player.getTeam()) + + if player: + logfile.write("GRAPPLE Name=" + name + " Team=" + team + " Pos=" + getPosStr(vehicle.getPosition()) + "\n") + + logfile.flush() + return + +def onDeployZipLine(player): + vehicle = player.getVehicle() + name = player.getName() + team = str(player.getTeam()) + + if player: + logfile.write("ZIPLINE Name=" + name + " Team=" + team + " Pos=" + getPosStr(vehicle.getPosition()) + "\n") + + logfile.flush() + return + +def onDeployTactical(player): + vehicle = player.getVehicle() + name = player.getName() + team = str(player.getTeam()) + + if player: + logfile.write("TACTICAL Name=" + name + " Team=" + team + " Pos=" + getPosStr(vehicle.getPosition()) + "\n") + + logfile.flush() + return + +#********************************************************* +#********************************************************* +#********************************************************* + +def onEnterVehicle(player, vehicle, freeSoldier = False): + if player == None: return + rootVehicle = bf2.objectManager.getRootParent(vehicle) + if rootVehicle.templateName == 'MultiPlayerFreeCamera': + return + + vehicleType = getVehicleType(rootVehicle.templateName) + + if vehicleType == VEHICLE_TYPE_SOLDIER: + pass + else: + timeString = wallString() + playerTeam = str(player.getTeam()) + logfile.write("ENTER PlayerName=" + player.getName() + " PlayerTeam=" + playerTeam + " VehicleName=" + rootVehicle.templateName + " Time=" + timeString + "\n") + player.fa.enterAt = date() + player.fa.enterTemplate = rootVehicle.templateName + + + logfile.flush() + + return + +def onPlayerSpawn(player, soldier): + pass + +def onExitVehicle(player, vehicle): + if player == None: return + rootVehicle = bf2.objectManager.getRootParent(vehicle) + vehicleType = getVehicleType(rootVehicle.templateName) + playerTeam = str(player.getTeam()) + + if vehicleType == VEHICLE_TYPE_SOLDIER: + pass + else: + timeInVehicle = 0 + if player.fa.enterTemplate == rootVehicle.templateName: + timeInVehicle = date() - player.fa.enterAt + timeString = wallString() + logfile.write("EXIT PlayerName=" + player.getName() + " PlayerTeam=" + playerTeam + " VehicleName=" + rootVehicle.templateName + " VehicleTime="\ + + str(fpformat.fix(timeInVehicle, 1)) + " Time=" + timeString + "\n") + + player.fa.enterAt = 0 + + logfile.flush() + return + +def onPickupKit(player, kit): + timeString = wallString() + playerSpawnTimePickupDiff = str(int(date())-int(player.stats.spawnedAt)) + playerTeam = str(player.getTeam()) + logfile.write("PICKUPKIT PlayerName=" + player.getName() + " PlayerTeam=" + playerTeam + " PlayerKit=" + kit.templateName + " PickupSpawnDiff=" + playerSpawnTimePickupDiff + " Time=" + timeString + "\n") + player.fa.spawnAt = date() + player.lastKitTemplateName = kit.templateName + logfile.flush() + +def onDropKit(player, kit): + timeInVehicle = 0 + if player.fa.spawnAt != 0: + timeInVehicle = date() - player.fa.spawnAt + timeString = wallString() + playerTeam = str(player.getTeam()) + logfile.write("DROPKIT PlayerName=" + player.getName() + " PlayerTeam=" + playerTeam + " PlayerKit=" + kit.templateName + " PlayerKitTime=" + str(fpformat.fix(timeInVehicle, 1)) + " Time=" + timeString + "\n") + logfile.flush() + return + +def onPlayerKilled(victim, attacker, weapon, assists, object): + victimKitName = victim.lastKitTemplateName + victimVehicle = victim.getVehicle() + victimRootVehicle = bf2.objectManager.getRootParent(victimVehicle) + victimVehicleType = getVehicleType(victimRootVehicle.templateName) + victimName = victim.getName() + victimTeam = str(victim.getTeam()) + + if attacker: + attackerKitName = attacker.lastKitTemplateName + attackerVehicle = attacker.getVehicle() + attackerRootVehicle = bf2.objectManager.getRootParent(attackerVehicle) + attackerVehicleType = getVehicleType(attackerRootVehicle.templateName) + attackerName = attacker.getName() + attackerTeam = str(attacker.getTeam()) + else: + attackerKitName = None + attackerVehicle = None + attackerRootVehicle = None + attackerVehicleType = VEHICLE_TYPE_UNKNOWN + + logfile.write("KILL") + if attacker: + logfile.write(" AttackerName=" + attackerName + " AttackerTeam=" + attackerTeam + " AttackerPos=" + getPosStr(attackerVehicle.getPosition())) + if victimVehicle != None: + logfile.write(" VictimName=" + victimName + " VictimTeam=" + victimTeam + " VictimPos=" + getPosStr(victimVehicle.getPosition())) + if victimKitName != None: + logfile.write(" VictimKit=" + victimKitName) + if victimVehicle != None and (attackerVehicleType != VEHICLE_TYPE_SOLDIER): + logfile.write(" VictimVehicle=" + victimRootVehicle.templateName) + + if attackerKitName != None: + logfile.write(" AttackerKit=" + attackerKitName) + if attackerVehicle != None and (attackerVehicleType != VEHICLE_TYPE_SOLDIER): + logfile.write(" AttackerVehicle=" + attackerRootVehicle.templateName) + + if weapon != None: + logfile.write(" AttackerWeapon=" + weapon.templateName) + + timeString = wallString() + logfile.write(" Time=" + timeString + "\n") + logfile.flush() + +def onPlayerDeath(victim, vehicle): + + # dump accuracy stats on death (can't invoke on each shot being fired) + tempFireMap = {} + bulletsHit = victim.score.bulletsGivingDamage + for b in bulletsHit: + templateName = b[0] + nr = b[1] + tempFireMap[templateName] = nr + + bulletsFired = victim.score.bulletsFired + if g_debug: print "bf: ", len(bulletsFired) + for b in bulletsFired: + templateName = b[0] + fired = b[1] + hits = 0 + if templateName in tempFireMap: + hits = tempFireMap[templateName] + timeString = wallString() + logfile.write("FIRED PlayerName=" + victim.getName() + " Weapon=" + templateName + " ShotsFired=" + str(fired) + " ShotsHit=" + str(hits) + " Time=" + timeString + "\n") + + logfile.flush() + + +def onCPStatusChange(cp, attackingTeam): + position = cp.getPosition() + if (cp.cp_getParam('team') == 0): + captureType = "team" + else: + if attackingTeam == 0: + return + captureType = "neutral" + + timeString = wallString() + logfile.write("CAPTURE ControlPointID=" + cp.getTemplateProperty('controlPointId') + " CaptureType=" + captureType\ + + " CaptureTeam=" + str(attackingTeam) + " CapturePointPos=" + getPosStr(cp.getPosition()) + " Time=" + timeString + "\n") + + logfile.flush() + + +def onPlayerScore(player, difference): + if player != None: + playerKitName = player.lastKitTemplateName + playerVeh = player.getVehicle() + playerRootVeh = bf2.objectManager.getRootParent(playerVeh) + playerVehName = playerRootVeh.templateName + playerVehType = getVehicleType(playerRootVeh.templateName) + timeString = wallString() + + # figure out score type + scoreTypeList = player.fa.getChangedStats(player) + player.fa.copyStats(player) + if len(scoreTypeList): + scoreType = scoreTypeList[0] + else: + scoreType = "Unknown" + + logfile.write("SCORE ScoreDiff=" + str(difference) + " PlayerName=" + player.getName() + " PlayerTeam=" + str(player.getTeam()) + " PlayerKit=" + playerKitName) + if (playerVeh != None) and (playerVehType != VEHICLE_TYPE_SOLDIER): + logfile.write(" PlayerVehicle=" + playerVehName) + logfile.write(" PlayerPos=" + getPosStr(playerVeh.getPosition()) + " Time=" + timeString + " Scoretype=" + scoreType + "\n") + + logfile.flush() diff --git a/src/python/bf2/stats/medal_data.py b/src/python/bf2/stats/medal_data.py new file mode 100644 index 00000000..b761e352 --- /dev/null +++ b/src/python/bf2/stats/medal_data.py @@ -0,0 +1,1556 @@ +from bf2.stats.constants import * +from bf2 import g_debug + +globalKeysNeeded = {} + +# criteria functions + +def player_score (player_attr, value=None): + if value == None: + def _player_score (player): + return getattr (player.score, player_attr) + else: + def _player_score (player): + return getattr (player.score, player_attr) >= value + return _player_score + + +def player_stat (player_attr, value): + def _player_stat (player): + return getattr (player.stats, player_attr) >= value + return _player_stat + +def object_stat (object_type, item_attr, item_type, value=None): + if value == None: + def _object_stat (player): + return getattr (getattr (player.stats, object_type)[item_type], item_attr) + else: + def _object_stat (player): + return getattr (getattr (player.stats, object_type)[item_type], item_attr) >= value + return _object_stat + +def has_medal (id, level=1): + def _has_medal (player): +# if not (id in player.medals.roundMedals and player.medals.roundMedals[id] >= level): +# if g_debug: print "Didnt have medal: ", id, " in ", player.medals.roundMedals + return id in player.medals.roundMedals and player.medals.roundMedals[id] >= level + return _has_medal + +def times_awarded(id, player): + if id in player.medals.roundMedals: +# if g_debug: print "Found medal %s with level %d" % (id, player.medals.roundMedals[id]) + return player.medals.roundMedals[id] # TIMES awarded, not level + else: + return 0 + +def global_stat_multiple_times (stat_key, value, id): + globalKeysNeeded[stat_key] = 1 + def _global_stat_multiple_times (player): + new_time_value = (value * (times_awarded(id, player)+1)) + return stat_key in player.medals.globalKeys and player.medals.globalKeys[stat_key] >= new_time_value + return _global_stat_multiple_times + +def global_stat (stat_key, value=None): + globalKeysNeeded[stat_key] = 1 + if value == None: + def _global_stat (player): + if stat_key in player.medals.globalKeys: return player.medals.globalKeys[stat_key] + else: return 0 + else: + def _global_stat (player): + return stat_key in player.medals.globalKeys and player.medals.globalKeys[stat_key] >= value + return _global_stat + + +def has_rank (rank): + def _has_rank (player): + # Can be very noisy + #if g_debug: print "Current rank: %d, going for rank: %d" % (player.score.rank, rank) + return player.score.rank == rank + return _has_rank + +# logical functions + +def f_and (*arg_list): + def _f_and (player): + res = True + for f in arg_list: + res = res and f(player) + #if g_debug: print f(player) + return res + return _f_and + +def f_or (*arg_list): + def _f_or (player): + res = True + for f in arg_list: + res = res or f(player) + return res + return _f_or + +def f_not (f): + def _f_not (player): + return not f(player) + return _f_not + +def f_plus(a, b, value=None): + if value == None: + def _f_plus (player): + return a(player) + b(player) + else: + def _f_plus (player): + return a(player) + b(player) >= value + return _f_plus + +def f_div(a, b, value=None): + if value == None: + def _f_div (player): + denominator = b(player) + if denominator == 0: return a(player)+1 + else: return a(player) / denominator + else: + def _f_div (player): + denominator = b(player) + + if denominator == 0: + return a(player)+1 + else: + return a(player) / denominator >= value + + return _f_div + + + +# medal definitions + +medal_data = ( + + #Badges - Infantry + #Knife Combat Badge + #Basic + ('1031406_1', 'kcb', 1, object_stat ('weapons', 'kills', WEAPON_TYPE_KNIFE, 7)), + + #Veteran + ('1031406_2', 'kcb', 1, + f_and( + has_medal ('1031406_1'), + f_plus( + global_stat ('wkl-9'), + object_stat ('weapons', 'kills', WEAPON_TYPE_KNIFE), + 50 + ) + ) + ), + + #Expert + ('1031406_3', 'kcb', 1, + f_and( + has_medal ('1031406_2'), + f_plus( + global_stat ('wkl-9'), + object_stat ('weapons', 'kills', WEAPON_TYPE_KNIFE), + 100 + ) + ) + ), + + #Pistol Combat Badge + #Basic + ('1031619_1', 'pcb', 1, object_stat ('weapons', 'kills', WEAPON_TYPE_PISTOL, 5)), + + #Veteran + ('1031619_2', 'pcb', 1, + f_and( + has_medal ('1031619_1'), + global_stat ('wkl-5', 50), + object_stat ('weapons', 'kills', WEAPON_TYPE_PISTOL, 7) + ) + ), + + #Expert + ('1031619_3', 'pcb', 1, + f_and( + has_medal ('1031619_2'), + f_plus( global_stat ('wkl-5'), + object_stat ('weapons', 'kills', WEAPON_TYPE_PISTOL), 500), + object_stat ('weapons', 'kills', WEAPON_TYPE_PISTOL, 18) + ) + ), + + #Assault Combat Badge + #Basic + ('1031119_1', 'Acb', 1, object_stat ('kits', 'kills', KIT_TYPE_ASSAULT, 5)), + + #Veteran + ('1031119_2', 'Acb', 1, + f_and( + has_medal ('1031119_1'), + global_stat ('ktm-1', 54000), + object_stat ('kits', 'kills', KIT_TYPE_ASSAULT, 20) + ) + ), + + #Expert + ('1031119_3', 'Acb', 1, + f_and( + has_medal ('1031119_2'), + global_stat ('ktm-1', 360000), + object_stat ('kits', 'kills', KIT_TYPE_ASSAULT, 40) + ) + ), + + #Anti-Tank Combat Badge + #Basic + ('1031120_1', 'Atcb', 1, object_stat ('kits', 'kills', KIT_TYPE_AT, 10)), + + #Veteran + ('1031120_2', 'Atcb', 1, + f_and( + has_medal ('1031120_1'), + global_stat ('ktm-0', 54000), + object_stat ('kits', 'kills', KIT_TYPE_AT, 20) + ) + ), + + #Expert + ('1031120_3', 'Atcb', 1, + f_and( + has_medal ('1031120_2'), + global_stat ('ktm-0', 360000), + object_stat ('kits', 'kills', KIT_TYPE_AT, 40) + ) + ), + + #Sniper Combat Badge + #Basic + ('1031109_1', 'Sncb', 1, object_stat ('kits', 'kills', KIT_TYPE_SNIPER, 10)), + + #Veteran + ('1031109_2', 'Sncb', 1, + f_and( + has_medal ('1031109_1'), + global_stat ('ktm-6', 54000), + object_stat ('kits', 'kills', KIT_TYPE_SNIPER, 15) + ) + ), + + #Expert + ('1031109_3', 'Sncb', 1, + f_and( + has_medal ('1031109_2'), + global_stat ('ktm-6', 360000), + object_stat ('kits', 'kills', KIT_TYPE_SNIPER, 35) + ) + ), + + #Spec Ops Combat Badge + #Basic + ('1031115_1', 'Socb', 1, object_stat ('kits', 'kills', KIT_TYPE_SPECOPS, 5)), + + #Veteran + ('1031115_2', 'Socb', 1, + f_and( + has_medal ('1031115_1'), + global_stat ('ktm-4', 54000), + object_stat ('kits', 'kills', KIT_TYPE_SPECOPS, 20) + ) + ), + + #Expert + ('1031115_3', 'Socb', 1, + f_and( + has_medal ('1031115_2'), + global_stat ('ktm-4', 360000), + object_stat ('kits', 'kills', KIT_TYPE_SPECOPS, 40) + ) + ), + + #Support Combat Badge + #Basic + ('1031121_1', 'Sucb', 1, object_stat ('kits', 'kills', KIT_TYPE_SUPPORT, 10)), + + #Veteran + ('1031121_2', 'Sucb', 1, + f_and( + has_medal ('1031121_1'), + global_stat ('ktm-5', 54000), + object_stat ('kits', 'kills', KIT_TYPE_SUPPORT, 20) + ) + ), + + #Expert + ('1031121_3', 'Sucb', 1, + f_and( + has_medal ('1031121_2'), + global_stat ('ktm-5', 360000), + object_stat ('kits', 'kills', KIT_TYPE_SUPPORT, 40) + ) + ), + + #Engineer Combat Badge + #Basic + ('1031105_1', 'Ecb', 1, object_stat ('kits', 'kills', KIT_TYPE_ENGINEER, 10)), + + #Veteran + ('1031105_2', 'Ecb', 1, + f_and( + has_medal ('1031105_1'), + global_stat ('ktm-2', 54000), + object_stat ('kits', 'kills', KIT_TYPE_ENGINEER, 20) + ) + ), + + #Expert + ('1031105_3', 'Ecb', 1, + f_and( + has_medal ('1031105_2'), + global_stat ('ktm-2', 360000), + object_stat ('kits', 'kills', KIT_TYPE_ENGINEER, 40) + ) + ), + + #Medic Combat Badge + #Basic + ('1031113_1', 'Mcb', 1, object_stat ('kits', 'kills', KIT_TYPE_MEDIC, 10)), + + #Veteran + ('1031113_2', 'Mcb', 1, + f_and( + has_medal ('1031113_1'), + global_stat ('ktm-3', 54000), + object_stat ('kits', 'kills', KIT_TYPE_MEDIC, 20) + ) + ), + + #Expert + ('1031113_3', 'Mcb', 1, + f_and( + has_medal ('1031113_2'), + global_stat ('ktm-3', 360000), + object_stat ('kits', 'kills', KIT_TYPE_MEDIC, 40) + ) + ), + + #Explosive Ordinance Badge + #Basic + ('1032415_1', 'Eob', 1, + f_plus( + object_stat ('weapons', 'kills', WEAPON_TYPE_C4), + f_plus( + object_stat ('weapons', 'kills', WEAPON_TYPE_ATMINE), + object_stat ('weapons', 'kills', WEAPON_TYPE_CLAYMORE) + ), + 5 + ) + ), + + #Veteran + ('1032415_2', 'Eob', 1, + f_and( + has_medal ('1032415_1'), + global_stat ('wkl-11', 50), + f_plus( + object_stat ('weapons', 'kills', WEAPON_TYPE_C4), + f_plus( + object_stat ('weapons', 'kills', WEAPON_TYPE_ATMINE), + object_stat ('weapons', 'kills', WEAPON_TYPE_CLAYMORE) + ), + 20 + ) + ) + ), + + #Expert + ('1032415_3', 'Eob', 1, + f_and( + has_medal ('1032415_2'), + global_stat ('wkl-11', 300), + f_plus( + object_stat ('weapons', 'kills', WEAPON_TYPE_C4), + f_plus( + object_stat ('weapons', 'kills', WEAPON_TYPE_ATMINE), + object_stat ('weapons', 'kills', WEAPON_TYPE_CLAYMORE) + ), + 30 + ) + ) + ), + + #First Aid Badge + #Basic + ('1190601_1', 'Fab', 1, player_score ('heals', 5)), + + #Veteran + ('1190601_2', 'Fab', 1, + f_and( + has_medal ('1190601_1'), + global_stat ('ktm-3', 54000), + player_score ('heals', 10) + ) + ), + + #Expert + ('1190601_3', 'Fab', 1, + f_and( + has_medal ('1190601_2'), + global_stat ('heal', 750), + global_stat ('ktm-3', 360000), + player_score ('heals', 20) + ) + ), + + #Engineer Badge + #Basic + ('1190507_1', 'Eb', 1, player_score ('repairs', 5)), + + #Veteran + ('1190507_2', 'Eb', 1, + f_and( + has_medal ('1190507_1'), + global_stat ('ktm-2', 54000), + player_score ('repairs', 10) + ) + ), + + #Expert + ('1190507_3', 'Eb', 1, + f_and( + has_medal ('1190507_2'), + global_stat ('rpar', 250), + global_stat ('ktm-2', 360000), + player_score ('repairs', 25) + ) + ), + + #Resupply Badge + #Basic + ('1191819_1', 'Rb', 1, player_score ('ammos', 5)), + + #Veteran + ('1191819_2', 'Rb', 1, + f_and( + has_medal ('1191819_1'), + global_stat ('ktm-5', 54000), + player_score ('ammos', 10) + ) + ), + + #Expert + ('1191819_3', 'Rb', 1, + f_and( + has_medal ('1191819_2'), + global_stat ('rsup', 500), + global_stat ('ktm-5', 360000), + player_score ('ammos', 25) + ) + ), + + #Command Badge + #Basic + ('1190304_1', 'Cb', 1, player_score ('cmdScore', 40)), + + #Veteran + ('1190304_2', 'Cb', 1, + f_and( + has_medal ('1190304_1'), + global_stat ('cdsc', 1000), + player_stat ('timeAsCmd', 1500) + ) + ), + + #Expert + ('1190304_3', 'Cb', 1, + f_and( + has_medal ('1190304_2'), + global_stat ('cdsc', 10000), + player_stat ('timeAsCmd', 1800) + ) + ), + + #Badges - Vehicles + #Armour Badge + #Basic + ('1220118_1', 'Ab', 1, object_stat ('vehicles', 'rtime', VEHICLE_TYPE_ARMOR, 600)), + + #Veteran + ('1220118_2', 'Ab', 1, + f_and( + has_medal ('1220118_1'), + global_stat ('vtm-0', 360000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_ARMOR, 12) + ) + ), + + #Expert + ('1220118_3', 'Ab', 1, + f_and( + has_medal ('1220118_2'), + global_stat ('vtm-0', 1440000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_ARMOR, 24) + ) + ), + + #Transport Badge + #Basic + ('1222016_1', 'Tb', 1, object_stat ('vehicles', 'rtime', VEHICLE_TYPE_TRANSPORT, 600)), + + #Veteran + ('1222016_2', 'Tb', 1, + f_and( + has_medal ('1222016_1'), + global_stat ('vtm-4', 90000), + global_stat ('dsab', 200), + object_stat ('vehicles', 'roadKills', VEHICLE_TYPE_TRANSPORT, 5) + ) + ), + + #Expert + ('1222016_3', 'Tb', 1, + f_and( + has_medal ('1222016_2'), + global_stat ('vtm-4', 270000), + global_stat ('dsab', 2000), + object_stat ('vehicles', 'roadKills', VEHICLE_TYPE_TRANSPORT, 11) + ) + ), + + #Helicopter Badge + #Basic + ('1220803_1', 'Hb', 1, object_stat ('vehicles', 'rtime', VEHICLE_TYPE_HELICOPTER, 900)), + + #Veteran + ('1220803_2', 'Hb', 1, + f_and( + has_medal ('1220803_1'), + global_stat ('vtm-3', 180000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_HELICOPTER, 12) + ) + ), + + #Expert + ('1220803_3', 'Hb', 1, + f_and( + has_medal ('1220803_2'), + global_stat ('vtm-3', 540000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_HELICOPTER, 24) + ) + ), + + #Aviator Badge + #Basic + ('1220122_1', 'Avb', 1, object_stat ('vehicles', 'rtime', VEHICLE_TYPE_AVIATOR, 600)), + + #Veteran + ('1220122_2', 'Avb', 1, + f_and( + has_medal ('1220122_1'), + global_stat ('vtm-1', 180000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_AVIATOR, 12) + ) + ), + + #Expert + ('1220122_3', 'Avb', 1, + f_and( + has_medal ('1220122_2'), + global_stat ('vtm-1', 540000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_AVIATOR, 24) + ) + ), + + #Air Defence Badge + #Basic + ('1220104_1', 'adb', 1, object_stat ('vehicles', 'rtime', VEHICLE_TYPE_AIRDEFENSE, 600)), + + #Veteran + ('1220104_2', 'adb', 1, + f_and( + has_medal ('1220104_1'), + #global_stat ('vtm-2', 108000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_AIRDEFENSE, 10) + ) + ), + + #Expert + ('1220104_3', 'adb', 1, + f_and( + has_medal ('1220104_2'), + #global_stat ('vtm-2', 360000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_AIRDEFENSE, 20) + ) + ), + + #Ground Defence Badge + #Basic + ('1031923_1', 'Swb', 1, object_stat ('vehicles', 'rtime', VEHICLE_TYPE_GRNDDEFENSE, 300)), + + #Veteran + ('1031923_2', 'Swb', 1, + f_and( + has_medal ('1031923_1'), + #global_stat ('vtm-6', 54000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_GRNDDEFENSE, 10) + ) + ), + + #Expert + ('1031923_3', 'Swb', 1, + f_and( + has_medal ('1031923_2'), + #global_stat ('vtm-6', 216000), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_GRNDDEFENSE, 20) + ) + ), + + #Ribbons +# Added by Chump - for bf2statistics stats + #Updated these service ribbons to be based on Global Map Time + #Mid-East Service + # Move to BACKEND!! + # ('3191305', 'Msr', 1, f_and( global_stat('mtm-0', 1), # kubra_dam + # global_stat('mtm-1', 1), # mashtuur_city + # global_stat('mtm-2', 1), # operation_clean_sweep + # global_stat('mtm-3', 1), # zatar_wetlands + # global_stat('mtm-4', 1), # strike_at_karkand + # global_stat('mtm-5', 1), # sharqi_peninsula + # global_stat('mtm-6', 1), # gulf_of_oman + # )), + + #Far-East Service + # Moved to BACKEND!! + # ('3190605', 'Fsr', 1, f_and( global_stat('mtm-100', 1), # daqing_oilfields + # global_stat('mtm-101', 1), # dalian_plant + # global_stat('mtm-102', 1), # dragon_valley + # global_stat('mtm-103', 1), # fushe_pass + # #global_stat('mtm-104', 1), # hingan_hills (Doesn't Exist!) + # global_stat('mtm-105', 1), # songhua_stalemate + # global_stat('mtm-601', 1), # wake_island_2007 + # )), + + #Combat Action Ribbon + ('3240301', 'Car', 1, + f_and( + global_stat ('bksk', 10), + player_score ('kills', 18) + ) + ), + + #Meritorious Unit Ribbon + ('3211305', 'Mur', 1, + f_and( + player_stat ('timeInSquad', 1560), + player_score ('rplScore', 40) + ) + ), + + #Infantry Officer Ribbon + ('3150914', 'Ior', 1, + f_and( + global_stat ('twsc', 250), + player_stat ('timeAsSql', 1500) + ) + ), + + #Staff Officer Ribbon + ('3151920', 'Sor', 1, + f_and( + player_stat ('timeAsCmd', 1680), + player_score ('cmdScore', 50) + ) + ), + + #Distinguished Service Ribbon + ('3190409', 'Dsr', 1, + f_and( + global_stat ('tsqm', 36000), + global_stat ('tsql', 36000), + global_stat ('tcdr', 36000), + player_score ('rplScore', 15) + ) + ), + + #War College Ribbon + ('3242303', 'Wcr', 1, + f_and( + global_stat ('tcdr', 360000), + global_stat ('wins', 200), + global_stat ('cdsc', 25000) + ) + ), + + #Valorous Unit Ribbon + ('3212201', 'Vur', 1, + f_and( + global_stat ('tsqm', 90000), + global_stat ('tsql', 90000), + player_score ('rplScore', 45) + ) + ), + + #Legion of Merit Ribbon + ('3241213', 'Lmr', 1, + f_and( + global_stat ('time', 720000), + global_stat ('bksk', 10), + global_stat ('wdsk', 8), + player_score ('rplScore', 50) + ) + ), + + #Crew Service Ribbon + ('3190318', 'Csr', 1, + f_and( + f_plus( + player_score ('driverSpecials'), + player_score ('driverAssists'), + 13 + ), + player_score ('kills', 5) + ) + ), + + #Armoured Service Ribbon + ('3190118', 'Arr', 1, + f_and( + object_stat ('vehicles', 'rtime', VEHICLE_TYPE_ARMOR, 1200), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_ARMOR, 19) + ) + ), + + #Aerial Service Ribbon + ('3190105', 'Aer', 1, + f_and( + object_stat ('vehicles', 'rtime', VEHICLE_TYPE_AVIATOR, 900), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_AVIATOR, 19) + ) + ), + + #Helicopter Service Ribbon + ('3190803', 'Hsr', 1, + f_and( + object_stat ('vehicles', 'rtime', VEHICLE_TYPE_HELICOPTER, 900), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_HELICOPTER, 19) + ) + ), + + #Air-Defence Ribbon + ('3040109', 'Adr', 1, + f_and( + object_stat ('vehicles', 'rtime', VEHICLE_TYPE_AIRDEFENSE, 180), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_AIRDEFENSE, 11) + ) + ), + + #Ground Defence Ribbon + ('3040718', 'Gdr', 1, + f_and( + object_stat ('vehicles', 'rtime', VEHICLE_TYPE_GRNDDEFENSE, 180), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_GRNDDEFENSE, 5) + ) + ), + + #Airborne Ribbon + ('3240102', 'Ar', 1, f_and( object_stat ('vehicles', 'rtime', VEHICLE_TYPE_PARACHUTE, 10))), + + #Good Conduct Ribbon + #Move to BACKEND?? + ('3240703', 'gcr', 1, + f_and( + global_stat ('time', 180000), + player_score ('kills', 14), + f_not ( + f_plus( + player_score ('TKs'), + f_plus( + player_score ('teamDamages'), player_score ('teamVehicleDamages') + ), + 1 + ) + ) + ) + ), + + #Medals + #Purple Heart + ('2191608', 'ph', 0, + f_and( + player_score ('kills', 5), + player_score ('deaths', 20), + f_div (player_score ('deaths'), player_score ('kills'), 4) + ) + ), + +# Added by Chump - these are calculated in medals.py + #Gold Star + #(2051907, + #Silver Star + # + #Bronze Star + # + + #Meritorious Service Medal + ('2191319', 'Msm', 2, + f_and( + global_stat_multiple_times ('time', 900000, '2191319'), + global_stat_multiple_times ('heal', 1000, '2191319'), + global_stat_multiple_times ('rpar', 1000, '2191319'), + global_stat_multiple_times ('rsup', 1000, '2191319') + ) + ), + + #Combat Action Medal + ('2190303', 'Cam', 2, + f_and( + global_stat_multiple_times ('time', 900000, '2190303'), + global_stat_multiple_times ('kill', 25000, '2190303'), + global_stat ('bksk', 25), + player_stat ('timePlayed', 1980) + ) + ), + + #Air Combat Medal + ('2190309', 'Acm', 2, + f_and( + global_stat_multiple_times ('vtm-1', 360000, '2190309'), + global_stat_multiple_times ('vkl-1', 5000, '2190309'), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_AVIATOR, 25) + ) + ), + + #Armour Combat Medal + ('2190318', 'Arm', 2, + f_and( + global_stat_multiple_times ('vtm-0', 360000, '2190318'), + global_stat_multiple_times ('vkl-0', 5000, '2190318'), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_ARMOR, 25) + ) + ), + + #Helicopter Combat Medal + ('2190308', 'Hcm', 2, + f_and( + global_stat_multiple_times ('vtm-3', 360000, '2190308'), + global_stat_multiple_times ('vkl-3', 5000, '2190308'), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_HELICOPTER, 30) + ) + ), + + #Good Conduct MEDAL + ('2190703', 'gcm', 2, + f_and( + global_stat_multiple_times ('time', 900000, '2190703'), + player_score ('kills', 27), + f_not ( + f_plus( + player_score ('TKs'), + f_plus( + player_score ('teamDamages'), + player_score ('teamVehicleDamages') + ), + 1 + ) + ) + ) + ), + + #Combat Infantry Medal + ('2020903', 'Cim', 1, + f_and( + global_stat ('time', 720000), + has_medal ('1031406_1'), + has_medal ('1031619_1'), + has_medal ('1031119_1'), + has_medal ('1031120_1'), + has_medal ('1031109_1'), + has_medal ('1031115_1'), + has_medal ('1031121_1'), + has_medal ('1031105_1'), + has_medal ('1031113_1') + ) + ), + + #Marksman Infantry Medal + ('2020913', 'Mim', 1, + f_and( + global_stat ('time', 1080000), + has_medal ('2020903'), + has_medal ('1031406_2'), + has_medal ('1031619_2'), + has_medal ('1031119_2'), + has_medal ('1031120_2'), + has_medal ('1031109_2'), + has_medal ('1031115_2'), + has_medal ('1031121_2'), + has_medal ('1031105_2'), + has_medal ('1031113_2') + ) + ), + + #Sharpshooter Infantry Medal + ('2020919', 'Sim', 1, + f_and( + global_stat ('time', 1440000), + has_medal ('2020913'), + has_medal ('1031406_3'), + has_medal ('1031619_3'), + has_medal ('1031119_3'), + has_medal ('1031120_3'), + has_medal ('1031109_3'), + has_medal ('1031115_3'), + has_medal ('1031121_3'), + has_medal ('1031105_3'), + has_medal ('1031113_3') + ) + ), + + #Medal of Valour + ('2021322', 'Mvm', 2, + f_and( + global_stat_multiple_times ('time', 900000, '2021322'), + global_stat_multiple_times ('dsab', 5000, '2021322'), + global_stat_multiple_times ('dfcp', 1000, '2021322'), + global_stat_multiple_times ('twsc', 30000, '2021322') + ) + ), + + #Distinguished Service Medal + ('2020419', 'Dsm', 2, + f_and( + global_stat_multiple_times ('tcdr', 360000, '2020419'), + global_stat_multiple_times ('tsql', 360000, '2020419'), + global_stat_multiple_times ('tsqm', 360000, '2020419'), + player_score ('rplScore', 45) + ) + ), + +# Added by Chump - added for bf2statistics + #Navy Cross + # Move to BACKEND ?? + # ('2021403', 'Ncm', 2, f_and( global_stat_multiple_times ('atm-0', 360000, '2021403'), + # global_stat_multiple_times ('abr-0', 100, '2021403'), + # global_stat_multiple_times ('awn-0', 100, '2021403'))), + + #Golden Scimitar + # Move to BACKEND ?? + # ('2020719', 'Gsm', 2, f_and( global_stat_multiple_times ('atm-1', 360000, '2020719'), + # global_stat_multiple_times ('abr-1', 100, '2020719'), + # global_stat_multiple_times ('awn-1', 100, '2020719'))), + + #People's Medallion + # Move to BACKEND ?? + # ('2021613', 'pmm', 2, f_and( global_stat_multiple_times ('atm-2', 360000, '2021613'), + # global_stat_multiple_times ('abr-2', 100, '2021613'), + # global_stat_multiple_times ('awn-2', 100, '2021613'))), + +#**************************************************************************************** +# B P 1 / B P 2 stuff Ribbons = 3, Medals = 2, Badges = 1 +#**************************************************************************************** + # Added by Wolverine 2006-06-18 + #European Union Special Service Medal + # WARNING! Can Cause problems if EF Booster Pack not isnatlled correctly! :( + # Move to BACKEND ?? + # ('2270521', 'Eum', 2, f_and( global_stat_multiple_times ('atm-9', 180000, '2270521'), + # global_stat_multiple_times ('abr-9', 100, '2270521'), + # global_stat_multiple_times ('awn-9', 50, '2270521'))), + + #European Union Service ribbon + # WARNING! Can Cause problems if EF Booster Pack not installed correctly! :( + # Move to BACKEND ?? + # ('3270519', 'Esr', 1, f_and( f_plus(global_stat('mtm-10'), + # f_plus(global_stat('mtm-11'), + # global_stat('mtm-110')), 180000), # 50hrs in European Theater + # global_stat('mtm-10', 1), # EF: operationsmokescreen + # global_stat('mtm-11', 1), # EF: taraba_quarry + # global_stat('mtm-110', 1), # EF: greatwall + # )), + + #North American Service Ribbon + # WARNING! Can Cause problems if AF Booster Pack not installed correctly! :( + # Move to BACKEND ?? + # ('3271401', 'Nas', 1, f_and( f_plus(global_stat('mtm-200'), + # f_plus(global_stat('mtm-201'), + # global_stat('mtm-202')), 90000), # 25hrs in Nth American Theater + # global_stat('mtm-200', 1), # AF: midnight_sun + # global_stat('mtm-201', 1), # AF: operationroadrage + # global_stat('mtm-202', 1), # AF: operationharvest + # )), + + +#**************************************************************************************** +#**************************************************************************************** +#**************************************************************************************** +# X P A C K 1 stuff Ribbons = 3, Medals = 2, Badges = 1 +#**************************************************************************************** +#**************************************************************************************** +#**************************************************************************************** + #Badges + #Assault Combat Badge + #Basic + ('1261119_1', 'X1Acb', 1, object_stat ('kits', 'kills', KIT_TYPE_ASSAULT, 6)), + + #Veteran + ('1261119_2', 'X1Acb', 1, + f_and( + has_medal ('1261119_1'), + global_stat ('ktm-1', 57600), + object_stat ('kits', 'kills', KIT_TYPE_ASSAULT, 22) + ) + ), + + #Expert + ('1261119_3', 'X1Acb', 1, + f_and( + has_medal ('1261119_2'), + global_stat ('ktm-1', 360000), + object_stat ('kits', 'kills', KIT_TYPE_ASSAULT, 44) + ) + ), + + #Anti-Tank Combat Badge + #Basic + ('1261120_1', 'X1Atcb', 1, object_stat ('kits', 'kills', KIT_TYPE_AT, 11)), + + #Veteran + ('1261120_2', 'X1Atcb', 1, + f_and( + has_medal ('1261120_1'), + global_stat ('ktm-0', 57600), + object_stat ('kits', 'kills', KIT_TYPE_AT, 22) + ) + ), + + #Expert + ('1261120_3', 'X1Atcb', 1, + f_and( + has_medal ('1261120_2'), + global_stat ('ktm-0', 360000), + object_stat ('kits', 'kills', KIT_TYPE_AT, 44) + ) + ), + + #Sniper Combat Badge + #Basic + ('1261109_1', 'X1Sncb', 1, object_stat ('kits', 'kills', KIT_TYPE_SNIPER, 11)), + + #Veteran + ('1261109_2', 'X1Sncb', 1, + f_and( + has_medal ('1261109_1'), + global_stat ('ktm-6', 57600), + object_stat ('kits', 'kills', KIT_TYPE_SNIPER, 17) + ) + ), + + #Expert + ('1261109_3', 'X1Sncb', 1, + f_and( + has_medal ('1261109_2'), + global_stat ('ktm-6', 360000), + object_stat ('kits', 'kills', KIT_TYPE_SNIPER, 38) + ) + ), + + #Spec Ops Combat Badge + #Basic + ('1261115_1', 'X1Socb', 1, object_stat ('kits', 'kills', KIT_TYPE_SPECOPS, 6)), + + #Veteran + ('1261115_2', 'X1Socb', 1, + f_and( + has_medal ('1261115_1'), + global_stat ('ktm-4', 57600), + object_stat ('kits', 'kills', KIT_TYPE_SPECOPS, 22) + ) + ), + + #Expert + ('1261115_3', 'X1Socb', 1, + f_and( + has_medal ('1261115_2'), + global_stat ('ktm-4', 360000), + object_stat ('kits', 'kills', KIT_TYPE_SPECOPS, 44) + ) + ), + + #Support Combat Badge + #Basic + ('1261121_1', 'X1Sucb', 1, object_stat ('kits', 'kills', KIT_TYPE_SUPPORT, 11)), + + #Veteran + ('1261121_2', 'X1Sucb', 1, + f_and( + has_medal ('1261121_1'), + global_stat ('ktm-5', 57600), + object_stat ('kits', 'kills', KIT_TYPE_SUPPORT, 22) + ) + ), + + #Expert + ('1261121_3', 'X1Sucb', 1, + f_and( + has_medal ('1261121_2'), + global_stat ('ktm-5', 360000), + object_stat ('kits', 'kills', KIT_TYPE_SUPPORT, 44) + ) + ), + + #Engineer Combat Badge + #Basic + ('1261105_1', 'X1Ecb', 1, object_stat ('kits', 'kills', KIT_TYPE_ENGINEER, 11)), + + #Veteran + ('1261105_2', 'X1Ecb', 1, + f_and( + has_medal ('1261105_1'), + global_stat ('ktm-2', 57600), + object_stat ('kits', 'kills', KIT_TYPE_ENGINEER, 22) + ) + ), + + #Expert + ('1261105_3', 'X1Ecb', 1, + f_and( + has_medal ('1261105_2'), + global_stat ('ktm-2', 360000), + object_stat ('kits', 'kills', KIT_TYPE_ENGINEER, 44) + ) + ), + + #Medic Combat Badge + #Basic + ('1261113_1', 'X1Mcb', 1, object_stat ('kits', 'kills', KIT_TYPE_MEDIC, 11)), + + #Veteran + ('1261113_2', 'X1Mcb', 1, + f_and( + has_medal ('1261113_1'), + global_stat ('ktm-3', 57600), + object_stat ('kits', 'kills', KIT_TYPE_MEDIC, 22) + ) + ), + + #Expert + ('1261113_3', 'X1Mcb', 1, + f_and( + has_medal ('1261113_2'), + global_stat ('ktm-3', 360000), + object_stat ('kits', 'kills', KIT_TYPE_MEDIC, 44) + ) + ), + + #Tactical Support Combat Badge + #Basic + ('1260602_1', 'X1fbb', 1, object_stat ('weapons', 'deployed', WEAPON_TYPE_TACTICAL, 10)), + + #Veteran + ('1260602_2', 'X1fbb', 1, + f_and( + has_medal ('1260602_1'), + f_plus( + global_stat ('de-6'), + object_stat ('weapons', 'deployed', WEAPON_TYPE_TACTICAL), + 100 + ) + ) + ), + + #Expert + ('1260602_3', 'X1fbb', 1, + f_and( + has_medal ('1260602_2'), + f_plus( + global_stat ('de-6'), + object_stat ('weapons', 'deployed', WEAPON_TYPE_TACTICAL), + 500 + ) + ) + ), + +# Added by Chump - nvg time does not register with onEnterVehicle() + #Night Vision Usage Badge + #Basic + #('1261422_1', 'X1nvb', 1, object_stat ('vehicles', 'rtime', VEHICLE_TYPE_NIGHTVISION, 900)), + #Veteran + #('1261422_2', 'X1nvb', 1, f_and( has_medal ('1261422_1'), + # global_stat ('tvn', 57600))), + #Expert + #('1261422_3', 'X1nvb', 1, f_and( has_medal ('1261422_2'), + # global_stat ('tvn', 360000))), + + #Grappling Hook Usage + #Basic + ('1260708_1', 'X1ghb', 1, object_stat ('weapons', 'deployed', WEAPON_TYPE_GRAPPLINGHOOK, 10)), + + #Veteran + ('1260708_2', 'X1ghb', 1, + f_and( + has_medal ('1260708_1'), + f_plus( + global_stat ('de-7'), + object_stat ('weapons', 'deployed', WEAPON_TYPE_GRAPPLINGHOOK), + 100 + ) + ) + ), + + #Expert + ('1260708_3', 'X1ghb', 1, + f_and( + has_medal ('1260708_2'), + f_plus( + global_stat ('de-7'), + object_stat ('weapons', 'deployed', WEAPON_TYPE_GRAPPLINGHOOK), + 500 + ) + ) + ), + + #Zip Line Usage + #Basic + ('1262612_1', 'X1zlb', 1, object_stat ('weapons', 'deployed', WEAPON_TYPE_ZIPLINE, 10)), + + #Veteran + ('1262612_2', 'X1zlb', 1, + f_and( + has_medal ('1262612_1'), + f_plus( + global_stat ('de-8'), + object_stat ('weapons', 'deployed', WEAPON_TYPE_ZIPLINE), + 100 + ) + ) + ), + + #Expert + ('1262612_3', 'X1zlb', 1, + f_and( + has_medal ('1262612_2'), + f_plus( + global_stat ('de-8'), + object_stat ('weapons', 'deployed', WEAPON_TYPE_ZIPLINE), + 500 + ) + ) + ), + + #Medals + +# Added by Chump - for bf2statistics stats + # Navy Seal Special Service Medal + # ('2261913', 'X1Nsm', 2, f_and( global_stat_multiple_times ('atm-3', 180000, '2261913'), + # global_stat_multiple_times ('abr-3', 100, '2261913'), + # global_stat_multiple_times ('awn-3', 50, '2261913'))), + + # SAS Special Service Medal + # ('2261919', 'X1Ssm', 2, f_and( global_stat_multiple_times ('atm-4', 180000, '2261919'), + # global_stat_multiple_times ('abr-4', 100, '2261919'), + # global_stat_multiple_times ('awn-4', 50, '2261919'))), + + # SPETZ Special Service Medal + # ('2261613', 'X1Spm', 2, f_and( global_stat_multiple_times ('atm-5', 180000, '2261613'), + # global_stat_multiple_times ('abr-5', 100, '2261613'), + # global_stat_multiple_times ('awn-5', 50, '2261613'))), + + # MECSF Special Service Medal + # ('2261303', 'X1Mcm', 2, f_and( global_stat_multiple_times ('atm-6', 180000, '2261303'), + # global_stat_multiple_times ('abr-6', 100, '2261303'), + # global_stat_multiple_times ('awn-6', 50, '2261303'))), + + # Rebel Special Service Medal + # ('2261802', 'X1Rbm', 2, f_and( global_stat_multiple_times ('atm-7', 180000, '2261802'), + # global_stat_multiple_times ('abr-7', 100, '2261802'), + # global_stat_multiple_times ('awn-7', 50, '2261802'))), + + # Insurgent Special Service Medal + # ('2260914', 'X1Inm', 2, f_and( global_stat_multiple_times ('atm-8', 180000, '2260914'), + # global_stat_multiple_times ('abr-8', 100, '2260914'), + # global_stat_multiple_times ('awn-8', 50, '2260914'))), + + #Ribbons + +# Added by Chump - for bf2statistics stats + # Navy Seal Service Ribbon + # ('3261919', 'X1Nss', 1, f_and( global_stat_multiple_times ('atm-3', 180000, '3261919'), + # global_stat('mtm-300', 1), # SF: devils_perch + # global_stat('mtm-301', 1), # SF: iron_gator + # global_stat('mtm-304', 1), # SF: leviathan + # )), + + # SAS Service Ribbon + # ('3261901', 'X1Sas', 1, f_and( global_stat_multiple_times ('atm-4', 180000, '3261919'), + # global_stat('mtm-302', 1), # SF: night_flight + # global_stat('mtm-303', 1), # SF: warlord + # global_stat('mtm-307', 1), # SF: ghost_town + # )), + + # SPETZNAS Service Ribbon + # ('3261819', 'X1Rsz', 1, f_and( global_stat_multiple_times ('atm-5', 180000, '3261919'), + # global_stat('mtm-305', 1), # SF: mass_destruction + # global_stat('mtm-306', 1), # SF: surge + # global_stat('mtm-307', 1), # SF: ghost_town + # )), + + # MECSF Service Ribbon + # ('3261319', 'X1Msf', 1, f_and( global_stat_multiple_times ('atm-6', 180000, '3261919'), + # global_stat('mtm-300', 1), # SF: devils_perch + # global_stat('mtm-301', 1), # SF: iron_gator + # global_stat('mtm-304', 1), # SF: leviathan + # )), + + # Rebel Service Ribbon + # ('3261805', 'X1Reb', 1, f_and( global_stat_multiple_times ('atm-7', 180000, '3261919'), + # global_stat('mtm-305', 1), # SF: mass_destruction + # global_stat('mtm-306', 1), # SF: surge + # )), + + # Insurgent Service Ribbon + # ('3260914', 'X1Ins', 1, f_and( global_stat_multiple_times ('atm-8', 180000, '3261919'), + # global_stat('mtm-302', 1), # SF: night_flight + # global_stat('mtm-303', 1), # SF: warlord + # )), + + #Crew Service Ribbon + ('3260318', 'X1Csr', 1, + f_and( + player_score ('driverSpecials', 1), + player_score ('driverAssists', 20), + player_score ('kills', 10) + ) + ), + + #Armoured Service Ribbon + ('3260118', 'X1Arr', 1, + f_and( + object_stat ('vehicles', 'rtime', VEHICLE_TYPE_ARMOR, 1200), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_ARMOR, 22) + ) + ), + + #Aerial Service Ribbon + ('3260105', 'X1Aer', 1, + f_and( + object_stat ('vehicles', 'rtime', VEHICLE_TYPE_AVIATOR, 900), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_AVIATOR, 22) + ) + ), + + #Helicopter Service Ribbon + ('3260803', 'X1Hsr', 1, + f_and( + object_stat ('vehicles', 'rtime', VEHICLE_TYPE_HELICOPTER, 900), + object_stat ('vehicles', 'kills', VEHICLE_TYPE_HELICOPTER, 22) + ) + ), + +#**************************************************************************************** +#**************************************************************************************** +#**************************************************************************************** +#**************************************************************************************** +#**************************************************************************************** +#**************************************************************************************** + + #end of medals_data + ) + + + +rank_data = ( + + # Private First Class: + (1, 'rank', + f_plus (global_stat ('scor'), player_score ('score'), 150) + ), + + # Lance Corporal: + (2, 'rank', + f_and( + has_rank(1), + f_plus (global_stat ('scor'), player_score ('score'), 500) + ) + ), + + # Corporal: + (3, 'rank', + f_and( + has_rank(2), + f_plus (global_stat ('scor'), player_score ('score'), 800) + ) + ), + + # Sergeant: + (4, 'rank', + f_and( + has_rank(3), + f_plus (global_stat ('scor'), player_score ('score'), 2500) + ) + ), + + # Staff Sergeant: + (5, 'rank', + f_and( + has_rank(4), + f_plus (global_stat ('scor'), player_score ('score'), 5000) + ) + ), + + # Gunnery Sergeant: + (6, 'rank', + f_and( + has_rank(5), + f_plus (global_stat ('scor'), player_score ('score'), 8000) + ) + ), + + # Master Sergeant / 1st Sergeant: + (7, 'rank', + f_and( + has_rank(6), + f_plus (global_stat ('scor'), player_score ('score'), 20000) + ) + ), + + (8, 'rank', + f_and( + has_rank(6), + f_plus (global_stat ('scor'), player_score ('score'), 20000), + has_medal('1031406_1'), #knife + has_medal('1031619_1'), #pistol + has_medal('1031119_1'), #assault + has_medal('1031120_1'), #AT + has_medal('1031109_1'), #Sniper + has_medal('1031115_1'), #spec op + has_medal('1031121_1'), #Support + has_medal('1031105_1'), #Eng + has_medal('1031113_1') #medic + ) + ), + + # Master Gunnery Sergeant / SGM: + (9, 'rank', + f_and( + f_or(has_rank(7), has_rank(8)), + f_plus (global_stat ('scor'), player_score ('score'), 50000) + ) + ), + + (10,'rank', + f_and( + f_or(has_rank(7), has_rank(8)), + f_plus (global_stat ('scor'), player_score ('score'), 50000), + has_medal('1220118_1'), # armour + has_medal('1222016_1'), # transport + has_medal('1220803_1'), # helicopter + has_medal('1220122_1'), # aviator + has_medal('1220104_1'), # Air defence + has_medal('1031923_1') # Ground Defence + ) + ), + + # Added by Chump - for bf2statistics stats (smoc is awarded in bf2statistics.php) + # Sergeant Major Of the Corp + (11, 'rank', + f_and( + f_plus (global_stat ('scor'), player_score ('score'), 50000), + has_medal('6666666') # highest rank this month, never awarded from here + ) + ), + + # 2nd Lieutenant + (12, 'rank', + f_and( + f_or(f_or(has_rank(9), has_rank(10)), has_rank(11)), + f_plus (global_stat ('scor'), player_score ('score'), 60000) + ) + ), + + # 1st Lieutenant + (13, 'rank', + f_and( + has_rank(12), + f_plus (global_stat ('scor'), player_score ('score'), 75000) + ) + ), + + # Captain + (14, 'rank', + f_and( + has_rank(13), + f_plus (global_stat ('scor'), player_score ('score'), 90000) + ) + ), + + # Major + (15, 'rank', + f_and( + has_rank(14), + f_plus (global_stat ('scor'), player_score ('score'), 115000) + ) + ), + + # Lt Colonel + (16, 'rank', + f_and( + has_rank(15), + f_plus (global_stat ('scor'), player_score ('score'), 125000) + ) + ), + + # Colonel + (17, 'rank', + f_and( + has_rank(16), + f_plus (global_stat ('scor'), player_score ('score'), 150000) + ) + ), + + # Brigadier General + (18, 'rank', + f_and( + has_rank(17), + f_plus (global_stat ('scor'), player_score ('score'), 180000), + has_medal('1220118_2'), # armour + has_medal('1222016_2'), # transport + has_medal('1220803_2'), # helicopter + has_medal('1220122_2'), # aviator + has_medal('1220104_2'), # Air defence + has_medal('1031923_2'), # Ground Defence + global_stat ('time', 3888000) + ) + ), + + # Major General + (19, 'rank', + f_and( + has_rank(18), + f_plus (global_stat ('scor'), player_score ('score'), 180000), + has_medal('1031406_2'), #knife + has_medal('1031619_2'), #pistol + has_medal('1031119_2'), #assault + has_medal('1031120_2'), #AT + has_medal('1031109_2'), #Sniper + has_medal('1031115_2'), #spec op + has_medal('1031121_2'), #Support + has_medal('1031105_2'), #Eng + has_medal('1031113_2'), #medic + global_stat ('time', 4500000) + ) + ), + + # Lieutenant General + (20, 'rank', + f_and( + has_rank(19), + f_plus (global_stat ('scor'), player_score ('score'), 200000), + global_stat ('time', 5184000) + ) + ), + + # General (awarded from back end. Must be Lt Gen and make leaderboard for 1 week.) + (21, 'rank', + f_and( + has_rank(20), + f_plus (global_stat ('scor'), player_score ('score'), 200000), + has_medal('6666666') # highest rank this month, never awarded from here + ) + ), +) diff --git a/src/python/bf2/stats/medals.py b/src/python/bf2/stats/medals.py new file mode 100644 index 00000000..c2d083ee --- /dev/null +++ b/src/python/bf2/stats/medals.py @@ -0,0 +1,713 @@ +# medals upgrades + +# Changelog +# ------------------------------------------------------------------------------ +# omero, 2006-06-02 +# + corrected wrong indentation bug in onPlayerConnect() event callback function. +# +# omero, 2006-03-31 +# + finalized import of configuration settings from bf2.BF2StatisticsConfig +# +# omero, 2006-03-15 +# +minor cosmethic changes to debug statements +# +# omero, 2006-03-10 +# +import http_backend_addr, http_backend_port from bf2.stats.BF2StatisticsConfig +# +import http_get from bf2.stats.miniclient (improved code, reverted to HTTP/1.1) +# +# omero, 2006-03-03 +# +import http_backend_addr, http_backend_port from __init__.py +# +# omero, 2006-02-27 +# +added substitutes for onPlayerStatsResponse(), onPlayerAwardsResponse() +# +# omero, 2006-02-20 +# +miniclient functions (HTTP/1.0) working. +# +stats and award processing hardcoded in onPlayerConnect() +# +# omero, 2006-02-12 +# +experimental calls to miniclient functions (HTTP/1.1) working but with +# +long time required to process each player (not closing socket?). +# +# Wilson212, 2012-02-02 +# + Improved custom medals data loading +# +# Wilson212, 2015-02-17 +# + Fixed a typo +# + Fixed a bug loading xpack medal data from the Control Center +# + createGlobalKeyString() removed, globalKeyString is now static (as it should be), since +# the ASP stats server requires the keystring to be static +# + Reverted to original Xpack medal checking as it was in the official python files +# Mods that will use SF medals are defined in the Bf2StatisticsConfig.py as "medals_xpack_mods" +# ------------------------------------------------------------------------------ + +import host +import bf2.PlayerManager +import bf2.Timer +import os + +from bf2 import g_debug + +from bf2.stats.constants import * +from bf2.BF2StatisticsConfig import stats_enable, http_backend_addr, http_backend_port, medals_custom_data, medals_xpack_mods +from bf2.stats.miniclient import miniclient, http_get + +# Import relevant medals data +if (medals_custom_data != ''): + try: + exec 'from bf2.stats.medal_data_' + str(medals_custom_data) + ' import *' + except: + print "Custom Medals Data Pack (%s) *NOT* found or is corrupt!" % (str(medals_custom_data)) + # Use default medals_data instead + from bf2.stats.medal_data import * + else: + print "Custom Medals Data Pack (%s) loaded." % (str(medals_custom_data)) +else: + from bf2.stats.medal_data import * + +# Get Player Stats Data +from bf2.stats.stats import getStatsMap, getPlayerConnectionOrderIterator, setPlayerConnectionOrderIterator + + + +# ------------------------------------------------------------------------------ +# mimics onPlayerStatsResponse() +# ------------------------------------------------------------------------------ +def attachPlayerStats(player, stats): + + if not player: + if g_debug: print "No player for STATS response? Aborting..." + return + + if g_debug: print "Processing STATS response for player %d, size %d." % (player.index, len(stats)) + + # add medal values + for key in globalKeysNeeded: + if not key in stats: + if g_debug: print "Key %s not found in stats response" % key + + else: + value = stats[key] + if value == "": + if g_debug: print "No value for stats key %s." % key + else: + if g_debug: print "Key %s has value %d" % ( key, int(stats[key]) ) + player.medals.globalKeys[key] = int(stats[key]) + + # add rank + if not 'rank' in stats: + if g_debug: print "Key %s not found in stats response" % 'rank' + + else: + value = stats['rank'] + if value == "": + print "No value for rank." + rank = 0 + + else: + try: + print "Found GSI rank %s for player %d" % (str(value), player.index) + rank = int(value) + except: + print "Could not convert rank %s to int." % value + rank = 0 + + if g_debug: print "Setting GSI rank %d for player %d" % (rank, player.index) + + player.score.rank = rank + player.stats.rank = rank + +# omero 2006-02-27 +# ------------------------------------------------------------------------------ +# mimics onPlayerAwardsResponse() +# ------------------------------------------------------------------------------ +def attachPlayerAwards(player, awards): + + if not player: + if g_debug: print "No player for awards response." + return + + if g_debug: print "Processing AWARDS response for player %d, size %d." % (player.index, len(awards)) + + for medalKey in awards: + # distinguish between 4 types of medal-entry: + # 1. Regular medal with key like '123456', with only one level and can only be gotten once + # 2. Medal with simple key like '123456', can be gotten multiple times, where criteria is changed depending on previous level + # 3. Medal with simple key like '123456', can be gotten multiple times regardless of previous level, but only once per round + # 4. Badge with key like '123456_1', that has individual medal entries per level + item = getMedalEntry(medalKey) + if item: + # some medals are not kept, and can be gotten regardless of previous level. ex: purple heart + keep = item[2] != 0 + if keep: + # case 1, 2 + player.medals.gsiMedals[medalKey] = int(awards[medalKey]) + player.medals.roundMedals[medalKey] = int(awards[medalKey]) + else: + # case 3 + pass + + else: + # case 4: badge with individual per-level criterias, + # skip placement medals + if ( awards[medalKey] > 0 ): + medalKey += '_' + str(awards[medalKey]) + + item = getMedalEntry(medalKey) + if item: + player.medals.gsiMedals[medalKey] = 1 + player.medals.roundMedals[medalKey] = 1 + else: + print "Medal", medalKey,"not found in medal data." + + + +sessionPlayerMedalMap = {} +def getMedalMap(): + global sessionPlayerMedalMap + return sessionPlayerMedalMap + +def setMedalMap(map): + global sessionPlayerMedalMap + sessionPlayerMedalMap = map + +# The global key string used by servers to fetch stats from the ASP Backend +globalKeyString = "&info=rank,ktm-,dfcp,rpar,vtm-,bksk,scor,wdsk,wkl-,heal,dsab,cdsc,tsql,tsqm,wins,vkl-,twsc,time,kill,rsup,tcdr,de-,vac-" +g_lastPlayerChecked = 0 + +# get our current running mod +running_mod = bf2.gameLogic.getModDir() +allow_xpack_medals = running_mod.lower() in medals_xpack_mods + +def init(): + # If stats are disabled, quit + if not stats_enable: + print "Medal awarding module disabled by config" + return + + # Events + host.registerHandler('PlayerConnect', onPlayerConnect, 1) + host.registerHandler('PlayerDisconnect', onPlayerDisconnect, 1) + host.registerHandler('PlayerStatsResponse', onStatsResponse, 1) + host.registerHandler('PlayerAwardsResponse', onAwardsResponse, 1) + host.registerGameStatusHandler(onGameStatusChanged) + + print "Medal awarding module initialized" + print "Using Xpack Medals: ", str(allow_xpack_medals) + print "Global key string: ", globalKeyString + + +updateTimer = None + +def onGameStatusChanged(status): + global updateTimer + if status == bf2.GameStatus.Playing: + host.registerHandler('PlayerKilled', onPlayerKilled3) + host.registerHandler('ExitVehicle', onExitVehicle) + host.registerHandler('PlayerScore', onPlayerScore) + + if updateTimer: + updateTimer.destroy() + + updateTimer = bf2.Timer(onUpdate, 1, 0) + updateTimer.setRecurring(1) + + # connect already connected players if reinitializing + for p in bf2.playerManager.getPlayers(): + onPlayerConnect(p) + + global g_lastPlayerChecked + g_lastPlayerChecked = 0 + + elif status == bf2.GameStatus.EndGame: + print " ---------------- END OF GAME ----------------" + givePositionalMedals(True, bf2.gameLogic.getWinner()) + + # produce snapshot + bf2.stats.snapshot.invoke() + + if g_debug: print "Destroyed timer" + if updateTimer: + updateTimer.destroy() + + + +def onPlayerConnect(player): + global updateTimer + + id = player.stats.connectionOrderNr + + # Check if player already in MedalMap, if so reconnect them + reconnect = id in sessionPlayerMedalMap + + if id in sessionPlayerMedalMap: + if g_debug: print "Player id=%d found in sessionPlayerMedalMap" % int(id) + + if not reconnect: + newMedalSet = MedalSet() + sessionPlayerMedalMap[id] = newMedalSet + + player.medals = sessionPlayerMedalMap[id] + player.medals.connect(reconnect) + + if not reconnect: + #rank + player.score.rank = 0 + + # Added by Chump - for bf2statistics stats + if g_debug: print "Added player %d, %s (%s) to medal/rank checking" % ( player.index, player.getName(), str(player.getProfileId()) ) + + else: + player.score.rank = player.stats.rank + + # Added by Chump - for bf2statistics stats + if g_debug: print "Readded player %d to medal/rank checking" % player.index + + # This code is used to reduce the "request storm" generated at the start of a round. + # Check if this player's STATS were updated in the last 30 seconds + # We only need to do this at the start of a round, just ignore otherwise + if player.getGlobalUpdateTime() > 30 and player.stats.wasHereAtStart == 1: + # STATS are a bit stale, force gamespy request (this should only occur ONCE per round) + # Final check just to make sure player isn't reconnecting mid-round due to a CTD + if player.stats.timeOnLine < 30: + reconnect = False + + if player.getProfileId() > 2000 and not reconnect: + print "Getting STATS for player %s (%s)..." % ( player.getName(), str(player.getProfileId()) ) + # get persistant stats from gamespy + + # Added by Chump - for bf2statistics stats (plus de-indenting) + #if host.ss_getParam('ranked'): + player.score.rank = player.stats.rank + + # STATS + success = False + if not player.isAIPlayer(): + if g_debug: print "Requesting player STATS via Host" + # This will only work for "online" accounts via the Gamespy Emulator + success = host.pers_plrRequestStats(player.index, 1, globalKeyString) + + # Player is either AI or Offline, so we will manually get STATS + if not success: + if g_debug: print "Retrieving player STATS via HTTP/1.1 miniclient" + + # URL for retrieving player's awards and stats records via internal miniclient + asp_playerinfo = '/ASP/getplayerinfo.aspx?pid=' + str(player.getProfileId()) + globalKeyString + + # Fetch Data + data = http_get( http_backend_addr, http_backend_port, asp_playerinfo ) + if data and data[0] == 'O': + print "Received STATS data is VALID, length %d" % int(len(data)) + + stats = {} + datalines = data.splitlines() + keys = datalines[3].split('\t') + vals = datalines[4].split('\t') + + if (len(keys) == len(vals)): + if g_debug: print "Assembling STATS dictionary with %d keys" % int(len(keys)) + + for idx in range(1,len(keys)): + stats[keys[idx]] = vals[idx] + + # eventually reattach persistent stats records to this player + attachPlayerStats(player,stats) + + else: + print "ERROR: Received STATS data is NOT VALID, length %d" % int(len(data)) + + # AWARDS + success = False + if not player.isAIPlayer(): + if g_debug: print "Requesting player AWARDS via Host" + # This will only work for "online" accounts via the Gamespy Emulator + success = host.pers_plrRequestAwards(player.index, 1, "") + + # Player is either AI or Offline, so we will manually get AWARDS + if not success: + print "Getting AWARDS for player %s (%s)..." % ( player.getName(), str(player.getProfileId()) ) + + # URL for retrieving player's awards and stats records via internal miniclient + asp_awardsinfo = '/ASP/getawardsinfo.aspx?pid=' + str(player.getProfileId()) + + # Fetch Data + data = http_get( http_backend_addr, http_backend_port, asp_awardsinfo ) + if data and data[0] == 'O': + print "Received AWARDS data is VALID, length %d" % int(len(data)) + + awards = {} + datalines = data.splitlines() + skip = True + for dataline in datalines: + # the first dataline retrieved only contains pid and nick, + # do nothing and mark the skip flag to false. + # all subsequent datalines will be processed normally + if dataline[0] == 'D' and skip: + skip = False + + elif dataline[0] == 'D': + items = dataline.split('\t') + medalkey = items[1] + medallev = items[2] + awards[medalkey] = medallev + + # eventually reattach persistent awards records to this player + attachPlayerAwards(player,awards) + + else: + print "ERROR: Received AWARDS data is NOT VALID, length %d" % int(len(data)) + + # Record STATS update time + player.setGlobalUpdateTime() + + +def onPlayerDisconnect(player): + pass + +class MedalSet: + def __init__(self): + self.gsiMedals = {} + self.roundMedals = {} + self.globalKeys = {} + + + def connect(self, reconnect): + + if not reconnect: + # omero, 2006-03-14 + if g_debug: print "Will retrieve medals from GSI..." + + # init position medals + self.placeMedals = [0, 0, 0] + + else: + # already connected, just clear round-only medals + if g_debug: print "Resetting unkept round-only medals..." + for medal in medal_data: + id = medal[0] + keep = medal[2] != 0 + if not keep and id in self.roundMedals: + del self.roundMedals[id] + + self.placeMedalThisRound = 0 + + if g_debug: print "roundMedals: ", self.roundMedals + + + def getSnapShot(self): + medalKeys = {} + prevKeys = {} + + # sum up medals with same key into one record (badges), for backend state and for current game state + for medal in medal_data: + id = medal[0] + key = medal[1] + + if g_debug: print "Found Medal (%s:%s)" % (id, key) + + if '_' in medal[0]: + # do special level calculation on badges, as they are sent as one key, but received as several + if id in self.roundMedals: + if not key in medalKeys: + # can only have one + medalKeys[key] = 1 + else: + # increase medal level + medalKeys[key] = medalKeys[key] + 1 + + if id in self.gsiMedals: + if not key in prevKeys: + # can only have one + prevKeys[key] = 1 + else: + # increase medal level + prevKeys[key] = prevKeys[key] + 1 + + + else: + # regular medals + if id in self.roundMedals: + medalKeys[key] = self.roundMedals[id] + + if id in self.gsiMedals: + prevKeys[key] = self.gsiMedals[id] + + + # only send medal stats when we have increased level + removeList = [] + for key in medalKeys: + if key in prevKeys: + if prevKeys[key] >= medalKeys[key]: + # already had this medal, no need to send in snapshot + removeList += [key] + + for key in removeList: + del medalKeys[key] + + if self.placeMedalThisRound == 1: + medalKeys['erg'] = 1 + elif self.placeMedalThisRound == 2: + medalKeys['ers'] = 1 + elif self.placeMedalThisRound == 3: + medalKeys['erb'] = 1 + + keyvals = [] + for k in medalKeys: + keyvals.append ('{"id":"' + str(k) + '","level":' + str(medalKeys[k]) + '}') + + return ",".join(keyvals) + + + +def givePositionalMedals(endOfRound, winningTeam): + if endOfRound: + # give medals for position + sortedPlayers = [] + + statsMap = getStatsMap() + for sp in statsMap.itervalues(): + sortedPlayers += [((sp.score, sp.skillScore, -sp.deaths), sp.connectionOrderNr)] + + sortedPlayers.sort() + sortedPlayers.reverse() + + global sessionPlayerMedalMap + if len(sortedPlayers) > 0 and sortedPlayers[0][1] in sessionPlayerMedalMap: + sessionPlayerMedalMap[sortedPlayers[0][1]].placeMedals[0] += 1 + sessionPlayerMedalMap[sortedPlayers[0][1]].placeMedalThisRound = 1 + if len(sortedPlayers) > 1 and sortedPlayers[1][1] in sessionPlayerMedalMap: + sessionPlayerMedalMap[sortedPlayers[1][1]].placeMedals[1] += 1 + sessionPlayerMedalMap[sortedPlayers[1][1]].placeMedalThisRound = 2 + if len(sortedPlayers) > 2 and sortedPlayers[2][1] in sessionPlayerMedalMap: + sessionPlayerMedalMap[sortedPlayers[2][1]].placeMedals[2] += 1 + sessionPlayerMedalMap[sortedPlayers[2][1]].placeMedalThisRound = 3 + + + +def onUpdate(data): + global g_lastPlayerChecked + + # check one player + for i in range (0, 2): + p = bf2.playerManager.getNextPlayer(g_lastPlayerChecked) + if not p: break + +# Added by Chump - for bf2statistics stats + #if p.isAlive() and not p.isAIPlayer(): + if p.isAlive(): + checkMedals(p) + + g_lastPlayerChecked = p.index + + + +def onPlayerKilled3(victim, attacker, weapon, assists, object): + if attacker != None: + checkMedals(attacker) + + + +def onExitVehicle(player, vehicle): + checkMedals(player) + + + +def onPlayerScore(player, difference): + if player != None and difference > 0: + checkRank(player) + + + +def checkMedals(player): + if not player.isAlive(): + return + + global allow_xpack_medals + for medal in medal_data: + + # check that player does not already have this medal this round + id = medal[0] + + #if its an xpack award, skip it if we are not playing SF + if not allow_xpack_medals: + if id[1:3] == "26": + continue + + # determine if player already has award + player_has_award = id in player.medals.roundMedals + + # If medal does not have multiple-times criteria, and player has it already, skip + if player_has_award and medal[2] != 2: + continue + + # check if criteria was met + checkCriteria = medal[3] + if not checkCriteria(player): + continue + + idStr = medal[0] + newLevel = 1 + if '_' in medal[0]: + # strip underscore + newLevel = int(idStr[idStr.find('_') + 1:]) + idStr = idStr[:idStr.find('_')] + + awardMedal(player, int(idStr), newLevel) + else: + if player_has_award: + newLevel = player.medals.roundMedals[id] + 1 + + awardMedal(player, int(idStr), 0) + + player.medals.roundMedals[id] = newLevel + + + +def checkRank(player): + + oldRank = player.score.rank + + rankCriteria = None + highestRank = player.score.rank + for rankItem in rank_data: + rankCriteria = rankItem[2] + if rankItem[0] > highestRank and rankCriteria(player): + highestRank = rankItem[0] + + if oldRank < highestRank: + player.score.rank = highestRank + awardRank(player, player.score.rank) + if g_debug: print "Player %s got promoted to rank: %d" % (player.getName(),player.score.rank) + + + +def awardMedal(player, id, level): + if g_debug: print "Player %s earned AWARD %d at level %d" % (player.getName(), id, level) + bf2.gameLogic.sendMedalEvent(player, id, level) + + + +def awardRank(player, rank): + if g_debug: print "Player %s promoted from RANK %d to %d" % (player.getName(), player.score.rank, rank) + bf2.gameLogic.sendRankEvent(player, rank, player.score.score) + + + +def onStatsResponse(succeeded, player, stats): + if not succeeded: + if player == None: + playerIndex = "unknown" + else: + playerIndex = player.index + print "onStatsResponse -> Stats request FAILED for player ", playerIndex, ": ", stats + return + + if not player: + if g_debug: print "onStatsResponse -> No player for stats response." + return + + if "" in stats: + print "onStatsResponse -> The stats response seems wrong:" + print stats + print "" + return + + if stats and stats[0] == 'O': + print "onStatsResponse -> Stats response received for player %d size %d." % (player.index, len(stats)) + + data = {} + datalines = stats.splitlines() + keys = datalines[3].split('\t') + vals = datalines[4].split('\t') + + if (len(keys) == len(vals)): + #if g_debug: + print "Assembling STATS dictionary with %d keys" % int(len(keys)) + + for idx in range(1,len(keys)): + data[keys[idx]] = vals[idx] + + # eventually reattach persistent stats records to this player + attachPlayerStats(player, data) + + else: + print "onStatsResponse -> Stats response received for player %d is NOT VALID! size %d" % (int(player.index), int(len(stats))) + + + +# omero, 2006-03-15 +# todo: +# is still of any use? +def getMedalEntry(key): + for item in medal_data: + if medalKey == item[0]: + return item + return None + + + +# create faster medal-data lookup map +medalDataKeyLookup = {} +for item in medal_data: + medalDataKeyLookup[item[0]] = item + + + +def getMedalEntry(key): + if key in medalDataKeyLookup: + return medalDataKeyLookup[key] + return None + + + +def onAwardsResponse(succeeded, player, awards): + if not succeeded: + if player == None: + playerIndex = "unknown" + else: + playerIndex = player.index + + print "onAwardsResponse -> Medal request failed for player ", playerIndex, ": ", stats + return + + if g_debug: print "onAwardsResponse -> Awards response received: ", awards + + if not player: + print "onAwardsResponse -> No player for medal response." + return + + for a in awards: + medalKey = str(a[0]) + # distinguish between 4 types of medal-entry: + # 1. Regular medal with key like '123456', with only one level and can only be gotten once + # 2. Medal with simple key like '123456', can be gotten multiple times, where criteria is changed depending on previous level + # 3. Medal with simple key like '123456', can be gotten multiple times regardless of previous level, but only once per round + # 4. Badge with key like '123456_1', that has individual medal entries per level + item = getMedalEntry(medalKey) + if item: + + # some medals are not kept, and can be gotten regardless of previous level. ex: purple heart + keep = item[2] != 0 + if keep: + # case 1, 2 + player.medals.gsiMedals[medalKey] = int(a[1]) + player.medals.roundMedals[medalKey] = int(a[1]) + else: + # case 3 + pass + + else: + # case 4: badge with individual per-level criterias + if a[1] > 0: + medalKey += '_' + str(a[1]) + + item = getMedalEntry(medalKey) + + if item: + player.medals.gsiMedals[medalKey] = 1 + player.medals.roundMedals[medalKey] = 1 + else: + print "onAwardsResponse -> Medal", medalKey,"not found in medal data." + + print "onAwardsResponse -> Player medals:", player.medals.gsiMedals + diff --git a/src/python/bf2/stats/miniclient.py b/src/python/bf2/stats/miniclient.py new file mode 100644 index 00000000..f746e7bc --- /dev/null +++ b/src/python/bf2/stats/miniclient.py @@ -0,0 +1,232 @@ +# ------------------------------------------------------------------------------ +# omero 2006-02-27 +# ------------------------------------------------------------------------------ + +import socket, string + +CRLF = "\r\n" + +def http_get(host, port = 80, document = "/"): + + try: + http = miniclient(host, port) + + except Exception, e: + + if e[0] == 111: + print "Connection refused by server %s on port %d" % (host,port) + + raise + + try: + http.writeline("GET %s HTTP/1.1" % str(document)) + http.writeline("Host: %s" % host) + http.writeline("User-Agent: GameSpyHTTP/1.0") + http.writeline("Connection: close") # do not keep-alive + http.writeline("") + + # Determine Status + statusCode = 0 + status = string.split(http.readline()) + if status[0] != "HTTP/1.1": + print "MiniClient: Unknown status response (%s)" % str(status[0]) + + try: + statusCode = string.atoi(status[1]) + except ValueError: + print "MiniClient: Non-numeric status code (%s)" % str(status[1]) + + #Extract Headers + headers = {} + while 1: + line = http.readline() + if not line: + break + split = line.split(":") + headers[split[0].strip()] = split[1].strip() + + #Check we got a valid HTTP response + if statusCode == 200: + body = "" + if "Content-Length" in headers: + content_length = headers["Content-Length"] + body = http.read() + elif "Transfer-Encoding" in headers and headers["Transfer-Encoding"] == "chunked": + while 1: + chunk_length = int(http.readline(), 16) + if chunk_length != 0: + body += http.read(chunk_length) + http.readline() # CRLF + if chunk_length == 0: + break + else: + # No Content-Length nor Transfer-Encoding header. Read until EOF + body = http.read() + + http.shutdown() # be nice, tell the http server we're done sending the request + http.close() # all done + return body + else: + http.shutdown() # be nice, tell the http server we're done sending the request + http.close() # all done + return "E\nH\terr\nD\tHTTP Error %s \"%s\"\n$\tERR\t$" % (str(statusCode), str(status[2])) + + except Exception, e: + http.shutdown() # be nice, tell the http server we're done sending the request + http.close() # all done + raise + + + +def http_postSnapshot(host, port = 80, document = "/", snapshot = ""): + + try: + http = miniclient(host, port) + + except Exception, e: + + if e[0] == 111: + print "Connection refused by server %s on port %d" % (host,port) + + raise + + try: + http.writeline("POST %s HTTP/1.1" % str(document)) + http.writeline("HOST: %s" % str(host)) + http.writeline("User-Agent: GameSpyHTTP/1.0") + http.writeline("Content-Type: application/x-www-form-urlencoded") + http.writeline("Content-Length: %s" % str(len(snapshot))) + http.writeline("Connection: close") + http.writeline("") + http.writeline(str(snapshot)) + http.writeline("") + + # Check that SnapShot Arrives. + # Determine Status + statusCode = 0 + status = string.split(http.readline()) + if status[0] != "HTTP/1.1": + print "MiniClient: Unknown status response (%s)" % str(status[0]) + + try: + statusCode = string.atoi(status[1]) + except ValueError: + print "MiniClient: Non-numeric status code (%s)" % str(status[1]) + + #Extract Headers + headers = {} + while 1: + line = http.readline() + if not line: + break + split = line.split(":") + headers[split[0].strip()] = split[1].strip() + + if statusCode == 200: + body = "" + if "Content-Length" in headers: + content_length = headers["Content-Length"] + body = http.read() + elif "Transfer-Encoding" in headers and headers["Transfer-Encoding"] == "chunked": + while 1: + chunk_length = int(http.readline(), 16) + if chunk_length != 0: + body += http.read(chunk_length) + http.readline() # CRLF + if chunk_length == 0: + break + else: + # No Content-Length nor Transfer-Encoding header. Read until EOF + body = http.read() + + http.shutdown() # be nice, tell the http server we're done sending the request + http.close() # all done + return body + else: + http.shutdown() # be nice, tell the http server we're done sending the request + http.close() # all done + return "E\nH\terr\nD\tHTTP Error %s \"%s\"\n$\tERR\t$" % (str(statusCode), str(status[2])) + + except Exception, e: + http.shutdown() # be nice, tell the http server we're done sending the request + http.close() # all done + raise + +class miniclient: + "Client support class for simple Internet protocols." + + def __init__(self, host, port): + "Connect to an Internet server." + + + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock.settimeout(30) + + try: + self.sock.connect((host, port)) + self.file = self.sock.makefile("rb") + + except socket.error, e: + + #if e[0] == 111: + # print "Connection refused by server %s on port %d" % (host,port) + raise + + + def writeline(self, line): + "Send a line to the server." + + try: + # Updated to sendall to resolve partial data transfer errors + self.sock.sendall(line + CRLF) # unbuffered write + + except socket.error, e: + if e[0] == 32 : #broken pipe + self.sock.close() # mutual close + self.sock = None + + raise e + + except socket.timeout: + self.sock.close() # mutual close + self.sock = None + raise + + def readline(self): + "Read a line from the server. Strip trailing CR and/or LF." + + s = self.file.readline() + + if not s: + raise EOFError + + if s[-2:] == CRLF: + s = s[:-2] + + elif s[-1:] in CRLF: + s = s[:-1] + + return s + + + def read(self, maxbytes = None): + "Read data from server." + + if maxbytes is None: + return self.file.read() + + else: + return self.file.read(maxbytes) + + + def shutdown(self): + + if self.sock: + self.sock.shutdown(1) + + + def close(self): + + if self.sock: + self.sock.close() + self.sock = None diff --git a/src/python/bf2/stats/rank.py b/src/python/bf2/stats/rank.py new file mode 100644 index 00000000..229787a9 --- /dev/null +++ b/src/python/bf2/stats/rank.py @@ -0,0 +1,112 @@ +# rank upgrades + +import host +import bf2.PlayerManager +import bf2.Timer +from bf2.stats.constants import * +from bf2 import g_debug + + + +def init(): + # Events + host.registerHandler('ConsoleSendCommand', onSendCommand) + + if bf2.serverSettings.getUseGlobalRank(): + host.registerHandler('PlayerConnect', onPlayerConnect, 1) + host.registerHandler('PlayerStatsResponse', onStatsResponse, 1) + + host.registerGameStatusHandler(onGameStatusChanged) + + # Connect already connected players if reinitializing + for p in bf2.playerManager.getPlayers(): + onPlayerConnect(p) + + if g_debug: print "Rank module initialized" + + +def onSendCommand(command, args): + if command == "giverank": + pId = int(args[0]) + rank = int(args[1]) + + player = bf2.playerManager.getPlayerByIndex(pId) + awardRank(player, rank) + + #jlo: temp for laedre! remove! + elif command == "setname": + pId = int(args[0]) + name = args[1] + player = bf2.playerManager.getPlayerByIndex(pId) + player.setName(name) + +def onGameStatusChanged(status): + if status == bf2.GameStatus.Playing: + #updateTimer = bf2.Timer(onUpdate, 20) + #updateTimer.setRecurring(20) + pass + else: + if g_debug: print "Destroyed timer" + #updateTimer.destroy() + + +def onUpdate(data): + #if g_debug: print "update rank" + for p in bf2.playerManager.getPlayers(): + if p.isAlive(): + checkRank(p) + + + +### Event hooks + +def onPlayerConnect(player): + id = player.index + if player.score.rank == -1: + player.score.rank = 0 + + # request rank + if bf2.serverSettings.getUseGlobalRank(): + if player.getProfileId() > 2000: + success = host.pers_plrRequestStats(player.index, 1, "&info=rank") + else: + if g_debug: print "Player %d had no profile id, can't request rank" % player.index + + + if g_debug: print "Added player %d to rank checking" % (player.index) + + + +def onStatsResponse(succeeded, player, stats): + if player == None: + playerIndex = "unknown" + else: + playerIndex = player.index + + if not "rank" in stats: + if g_debug: print "rank not found, aborting" + return + + if g_debug: print "Rank received for player ", playerIndex, ":", host.pers_getStatsKeyVal("rank") + if not player: return + + + if not player: return + + if not "rank" in stats: + if g_debug: print "Rank not found in stats response" + else: + value = host.pers_getStatsKeyVal("rank") + if g_debug: print "Player %s Rank:%s" % (player.index, int(value)) + player.score.rank = int(value) + player.stats.rank = int(value) + + + + + + + + + + diff --git a/src/python/bf2/stats/snapshot.py b/src/python/bf2/stats/snapshot.py new file mode 100644 index 00000000..7a930eba --- /dev/null +++ b/src/python/bf2/stats/snapshot.py @@ -0,0 +1,473 @@ +################################################# +# +# History: +# 11/24/05 v0.0.1 - ALPHA build +# 11/28/05 v0.0.2 - Removed killedByPlayer +# - Added kills +# 12/08/05 v0.0.3 - Added deaths +# 12/09/05 v0.0.4 - Removed tnv/tgm +# 12/10/05 v0.0.5 - Added prefix +# 12/14/05 v0.0.6 - Removed useless GS call +# - Removed tactical/zip/grappling kills +# - Added grappling deaths +# 12/25/05 v0.0.7 - Added v +# 01/03/06 v0.1 - BETA release +# 01/05/06 v0.1.1 - Added master db +# - Added socket timeout/error handling +# 01/25/06 v0.1.2 - Updated CDB IP +# 02/15/06 v0.1.3 - Updated CDB URL +# 06/17/06 v0.1.4 - Added EF army +# 02/01/06 v1.0 - Public Release +# +# 06/10/10 - Removed Combat scores, they now calculate in bf2statistics.php +# 06/10/10 - Added return +# 06/10/10 - Corrected Teamwork keys +# +# 3/10/18 v2.0 - Converted to snapshot to JSON format +# +################################################# + +################################################# +# DO NOT EDIT ANYTHING BELOW THIS LINE! +################################################# + +import host +import bf2.PlayerManager +import fpformat +from constants import * +from bf2 import g_debug +from bf2.stats.stats import getStatsMap, setStatsMap, getPlayerConnectionOrderIterator, setPlayerConnectionOrderIterator, roundArmies +from bf2.stats.medals import getMedalMap, setMedalMap + +# ------------------------------------------------------------------------------ +# omero 2006-03-31 +# ------------------------------------------------------------------------------ +from bf2.BF2StatisticsConfig import * +from bf2.stats.miniclient import miniclient, http_postSnapshot + +# Added by Chump - for bf2statistics stats +from time import time, localtime, strftime + +map_start = 0 + +def init(): + print "Snapshot module initialized" + + # Added by Chump - for bf2statistics stats + host.registerGameStatusHandler(onChangeGameStatus) + + +# Added by Chump - for bf2statistics stats +def onChangeGameStatus(status): + global map_start + if status == bf2.GameStatus.Playing: + map_start = time() + +def invoke(): + + # Added by Chump - for bf2statistics stats + #host.pers_gamespyStatsNewGame() + + snapshot_start = time() + + if g_debug: print "Gathering SNAPSHOT Data" + snapShot = getSnapShot() + + + elapsedTime = time() - snapshot_start; + ms = elapsedTime * 1000; + print "SNAPSHOT Data generated in %d ms" % ms + + # Send snapshot to Backend Server + print "Sending SNAPSHOT to backend: %s" % str(http_backend_addr) + snapshot_sent = 0 + + # ------------------------------------------------------------------- + # Attempt to send snapshot + # ------------------------------------------------------------------- + try: + backend_response = http_postSnapshot( http_backend_addr, http_backend_port, http_backend_asp, snapShot ) + if backend_response and backend_response[0] == 'O': + print "SNAPSHOT Received: OK" + snapshot_sent = 1 + if g_debug: sayAll("Game Stats Received OK") + + else: + print "SNAPSHOT Received: ERROR" + if backend_response and backend_response[0] == 'E': + datalines = backend_response.splitlines() + response = datalines[2].split("\t") + print "Backend Response: %s" % str(response[-1:]) + if g_debug: sayAll("Game Stats Received in ERROR: %s" % str(response[-1:])) + + snapshot_sent = 0 + + except Exception, e: + snapshot_sent = 0 + print "An error occurred while sending SNAPSHOT to backend: %s" % str(e) + if g_debug: sayAll("An error occurred while sending stats data to backend: %s" % str(e)) + + + # ------------------------------------------------------------------- + # If SNAPSHOT logging is enabled, or the snapshot failed to send, + # then log the snapshot + # ------------------------------------------------------------------- + if snapshot_logging == 1 or snapshot_sent == 0: + snaplog_title = "" + log_time = str(strftime("%Y%m%d_%H%M", localtime())) + + if snapshot_sent == 0: + snaplog_title = snapshot_log_path_unsent + "/" + bf2.gameLogic.getMapName() + "_" + log_time + ".json" + print "Logging snapshot for manual processing..." + else: + snaplog_title = snapshot_log_path_sent + "/" + bf2.gameLogic.getMapName() + "_" + log_time + ".json" + + print "SNAPSHOT log file: %s" % snaplog_title + try: + snap_log = file(snaplog_title, 'a') + snap_log.write(snapShot) + snap_log.close() + + except Exception, e: + print "Cannot write to SNAPSHOT log file! Reason: %s" % str(e) + print "Printing Snapshot as last resort manual processing: ", snapShot + + + # Log snapshot timing + elapsedTime = time() - snapshot_start; + ms = elapsedTime * 1000; + print "SNAPSHOT Processing Time: %d ms" % ms + +# ------------------------------------------------------------------------------ +# omero 2006-03-31 +# ------------------------------------------------------------------------------ +# always do the following at the end... + repackStatsVectors() + + +def repackStatsVectors(): + + # remove disconnected players + cleanoutStatsVector() + cleanoutMedalsVector() + + # repack stats and medal vector so there are no holes. gamespy doesnt like holes. + medalMap = getMedalMap() + statsMap = getStatsMap() + playerOrderIt = getPlayerConnectionOrderIterator() + + newOrderIterator = 0 + newStatsMap = {} + newMedalMap = {} + + highestId = 0 + for id, statsItem in statsMap.iteritems(): + + newStatsMap[newOrderIterator] = statsItem + if id in medalMap: + newMedalMap[newOrderIterator] = medalMap[id] + + statsItem.connectionOrderNr = newOrderIterator + newOrderIterator += 1 + + print "Repacked stats map. Stats map size=%d. OrderIt changed from %d to %d" % (len(statsMap), playerOrderIt, newOrderIterator) + + setPlayerConnectionOrderIterator(newOrderIterator) + setStatsMap(newStatsMap) + setMedalMap(newMedalMap) + + + +def cleanoutStatsVector(): + print "Cleaning out unconnected players from stats map" + statsMap = getStatsMap() + + # remove disconnected players after snapshot was sent + removeList = [] + for pid in statsMap: + foundPlayer = False + for p in bf2.playerManager.getPlayers(): + if p.stats == statsMap[pid]: + foundPlayer = True + break + + if not foundPlayer: + removeList += [pid] + + for pid in removeList: + print "Removed player %d from stats." % pid + del statsMap[pid] + + + +def cleanoutMedalsVector(): + print "Cleaning out unconnected players from medal map" + medalMap = getMedalMap() + + # remove disconnected players after snapshot was sent + removeList = [] + for pid in medalMap: + foundPlayer = False + for p in bf2.playerManager.getPlayers(): + if p.medals == medalMap[pid]: + foundPlayer = True + break + + if not foundPlayer: + removeList += [pid] + + for pid in removeList: + if g_debug: print "Removed player %d from medals." % pid + del medalMap[pid] + + + +def getSnapShot(): + print "Assembling snapshot" + global map_start + statsMap = getStatsMap() + + # ---------------------------------------------------------------------------- + # Wilson212 2016-06-24 + # ---------------------------------------------------------------------------- + # Changed standardKeys['v'] from mod, to python version! + # standardKeys['m'] is now for mod name + # + running_mod = str(host.sgl_getModDirectory()) + running_mod = running_mod.lower().replace("mods/", "") + + if g_debug: print 'Running MOD: %s' % running_mod + + standardKeys = [ + ("authId", str(stats_auth_id)), + ("authToken", str(stats_auth_token)), + ("serverName", str(bf2.serverSettings.getServerConfig('sv.serverName'))), + ("gamePort", str(bf2.serverSettings.getServerConfig('sv.serverPort'))), + ("queryPort", str(bf2.serverSettings.getServerConfig('sv.gameSpyPort'))), + ("mapId", str(getMapId(bf2.serverSettings.getMapName()))), + ("mapName", str(bf2.gameLogic.getMapName())), + ("mapStart", str(map_start)), + ("mapEnd", str(time())), + ("winner", str(bf2.gameLogic.getWinner())), + ("gameMode", str(getGameModeId(bf2.serverSettings.getGameMode()))), + ("mod", str(running_mod)), + ("version", "3.1"), + ("pc", len(statsMap)), + ] + + if g_debug: print 'Finished Pre-Compile SNAPSHOT' + + # only send rwa key if there was a winner + winner = bf2.gameLogic.getWinner() + if winner != 0: + standardKeys += [("rwa", roundArmies[winner])] + + # get final ticket score + if g_debug: print "Army 1 (%s) Score: %s" % (str(roundArmies[1]), str(bf2.gameLogic.getTickets(1))) + if g_debug: print "Army 2 (%s) Score: %s" % (str(roundArmies[2]), str(bf2.gameLogic.getTickets(2))) + standardKeys += [ + ("ra1", str(roundArmies[1])), + ("rs1", str(bf2.gameLogic.getTickets(1))), + ("ra2", str(roundArmies[2])), + ("rs2", str(bf2.gameLogic.getTickets(2))), + ] + + standardKeys += [("rst2", str(bf2.gameLogic.getTickets(2)))] + + stdKeyVals = [] + for k in standardKeys: + stdKeyVals.append (":".join(( '"' + str(k[0]) + '"', '"' + str(k[1]) + '"'))) + + snapShot = "{" + snapShot += ",".join(stdKeyVals) + + if g_debug: print 'Snapshot Pre-processing complete: %s' % (str(snapShot)) + + playerSnapShots = [] + if g_debug: print 'Num clients to base snap on: %d' % (len(statsMap)) + for sp in statsMap.itervalues(): + if g_debug: print 'Processing PID: %s' % (str(sp.profileId)) + playerSnap = getPlayerSnapshot(sp) + if len(playerSnap) > 0: + playerSnapShots.append (playerSnap) + + print "Doing Player SNAPSHOTS" + snapShot += ',"players":[' + ",".join(playerSnapShots) + ']' + + # Add EOF marker for validation + snapShot += "}" + + return snapShot + + + +def getPlayerSnapshot(playerStat): + + # The player didn't spawn in... + if playerStat.timePlayed == 0: + return "" + + playerKeys = [ + + # main keys + ("pID", playerStat.profileId), + ("name", playerStat.name), + ("t", playerStat.team), + ("a", playerStat.army), + ("ctime", int(playerStat.timePlayed)), + ("c", playerStat.complete), + ("ip", playerStat.ipaddr), + ("ai", playerStat.isAIPlayer), + + # score keys + ("rs", playerStat.score), + ("cs", playerStat.cmdScore), + ("ss", playerStat.skillScore), + ("ts", playerStat.teamScore), + ("kills", playerStat.kills), + ("deaths", playerStat.deaths), + ("cpc", playerStat.localScore.cpCaptures), + ("cpn", playerStat.localScore.cpNeutralizes), + ("cpa", playerStat.localScore.cpAssists), + ("cpna", playerStat.localScore.cpNeutralizeAssists), + ("cpd", playerStat.localScore.cpDefends), + ("ka", playerStat.localScore.damageAssists), + ("he", playerStat.localScore.heals), + ("rev", playerStat.localScore.revives), + ("rsp", playerStat.localScore.ammos), + ("rep", playerStat.localScore.repairs), + ("tre", playerStat.localScore.targetAssists), + ("drs", playerStat.localScore.driverSpecials + playerStat.localScore.driverAssists), + #("drs", playerStat.localScore.driverSpecials), // Processed in backend + #("dra", playerStat.localScore.driverAssists), // Processed in backend + #("pa", playerStat.localScore.passengerAssists), // Processed in backend + + # Additional player stats + ("tmkl", playerStat.teamkills), + ("tmdg", playerStat.localScore.teamDamages), + ("tmvd", playerStat.localScore.teamVehicleDamages), + ("su", playerStat.localScore.suicides), + ("ks", playerStat.longestKillStreak), + ("ds", playerStat.longestDeathStreak), + ("rank", playerStat.rank), + ("ban", playerStat.timesBanned), + ("kck", playerStat.timesKicked), + + # time keys + ("tco", int(playerStat.timeAsCmd)), + ("tsl", int(playerStat.timeAsSql)), + ("tsm", int(playerStat.timeInSquad - playerStat.timeAsSql)), + ("tlw", int(playerStat.timePlayed - playerStat.timeAsCmd - playerStat.timeInSquad)), + ("tvp", str(int(playerStat.vehicles[VEHICLE_TYPE_PARACHUTE].timeInObject)) ) + + ] + + # Combine current keys into player snapshot + keyvals = [] + for k in playerKeys: + keyvals.append (":".join(( '"' + str(k[0]) + '"', '"' + str(k[1]) + '"'))) + + playerSnapShot = ",".join(keyvals) + + # army time + keyvals = [] + for index in range(NUM_ARMIES): + aTime = int(playerStat.timeAsArmy[index]) + if aTime > 0: + keyvals.append ('{"id":' + str(index) + ',"time":' + str(aTime) + '}') + + armySnapShot = '"armyData":[' + ",".join(keyvals) + ']' + + # victims + keyvals = [] + statsMap = getStatsMap() + + for p in playerStat.killedPlayer: + if not p in statsMap: + if g_debug: print "killedplayer_id victim connorder: ", playerStat.killedPlayer[p], " wasnt in statsmap!" + else: + keyvals.append ('{"id":' + str(statsMap[p].profileId) + ',"count":' + str(playerStat.killedPlayer[p]) + '}') + + victimSnapShot = '"victims":[' +",".join(keyvals) + ']' + + # medals + medalsSnapShot = '"awards":[' + if playerStat.medals: + if g_debug: print "Medals Found (%s), Processing Medals Snapshot" % (playerStat.profileId) + medalsSnapShot += playerStat.medals.getSnapShot() + + medalsSnapShot = medalsSnapShot + ']' + + # vehicles - Backend does not care about VEHICLE_TYPE_[SOLDIER, NIGHTVISION, or GASMASK] + # NOTE: VEHICLE_TYPE_NIGHTVISION and VEHICLE_TYPE_GASMASK do not register with onEnterVehicle() + vehkeyvals = [] + for i in range(7): + index = str(i) + v = playerStat.vehicles[i] + vTime = int(v.timeInObject) + if vTime > 0: + keyvals = [] + keyvals.append ('"id":' + str(i)) + keyvals.append ('"time":' + str(vTime)) + keyvals.append ('"score":' + str(v.score)) + keyvals.append ('"kills":' + str(v.kills)) + keyvals.append ('"deaths":' + str(v.deaths)) + keyvals.append ('"roadkills":' + str(v.roadKills)) + vehkeyvals.append ('{' + ",".join(keyvals) + '}') + + vehicleSnapShot = '"vehicleData":[' + ",".join(vehkeyvals) + ']' + + # kits + kitkeyvals = [] + for i in range(NUM_KIT_TYPES): + index = str(i) + k = playerStat.kits[i] + kTime = int(k.timeInObject) + if kTime > 0: + keyvals = [] + keyvals.append ('"id":' + str(i)) + keyvals.append ('"time":' + str(kTime)) + keyvals.append ('"score":' + str(k.score)) + keyvals.append ('"kills":' + str(k.kills)) + keyvals.append ('"deaths":' + str(k.deaths)) + kitkeyvals.append ('{' + ",".join(keyvals) + '}') + + kitSnapShot = '"kitData":[' + ",".join(kitkeyvals) + ']' + + # weapons + # NOTE Backend does not care about WEAPON_TYPE_TARGETING, so skip it! + i = 0 + weapkeyvals = [] + for j in range(NUM_WEAPON_TYPES): + + # Skip targetting + if (j == WEAPON_TYPE_TARGETING): + continue + + index = str(i) + w = playerStat.weapons[i] + wTime = int(w.timeInObject) + if wTime > 0: + keyvals = [] + keyvals.append ('"id":' + str(i)) + keyvals.append ('"time":' + str(wTime)) + keyvals.append ('"score":' + str(w.score)) + keyvals.append ('"kills":' + str(w.kills)) + keyvals.append ('"deaths":' + str(w.deaths)) + keyvals.append ('"fired":' + str(w.bulletsFired)) + keyvals.append ('"hits":' + str(w.bulletsHit)) + keyvals.append ('"deployed":' + str(w.deployed)) + weapkeyvals.append ('{' + ",".join(keyvals) + '}') + + i += 1 + + weaponSnapShot = '"weaponData":[' + ",".join(weapkeyvals) + ']' + + allSnapShots = [playerSnapShot, armySnapShot, kitSnapShot, vehicleSnapShot, weaponSnapShot, victimSnapShot, medalsSnapShot] + playerSnapShot = ",".join(allSnapShots) + return "{" + playerSnapShot + "}" + + +def sayAll(msg): + host.rcon_invoke("game.sayAll \"" + str(msg) + "\"") + diff --git a/src/python/bf2/stats/stats.py b/src/python/bf2/stats/stats.py new file mode 100644 index 00000000..6cf5d35a --- /dev/null +++ b/src/python/bf2/stats/stats.py @@ -0,0 +1,1037 @@ +import host +import bf2.PlayerManager +import fpformat +from constants import * +from bf2 import g_debug + +#omero, 2006-04-13 +from bf2.BF2StatisticsConfig import pm_ai_player_addr, debug_fraglog_enable + +#omero, 2006-04-13 +#assign the bots an ip +def fixPlayerAddress(player): + if player.isAIPlayer(): + return pm_ai_player_addr + else: + return player.getAddress() + + +#omero, 2006-05-01 +#borrowed from fragalizer_log.py module +def getPosStr(orgPos): + worldSize = bf2.gameLogic.getWorldSize(); + scale = [512.0 / worldSize[0], 1, 512.0 / worldSize[1]] + pos = [orgPos[0] * scale[0], orgPos[1] * scale[1], orgPos[2] * scale[2]] + res = str(fpformat.fix(pos[0], 3)) + "," + str(fpformat.fix(pos[1], 3)) + "," + str(fpformat.fix(pos[2], 3)) + return res + + + +roundArmies = [None, None, None] + +sendEndOfRoundStats = False +def getSendEndOfRoundStats(): + global sendEndOfRoundStats + return sendEndOfRoundStats + +def setSendEndOfRoundStats( value ): + global sendEndOfRoundStats + sendEndOfRoundStats = value + +playerConnectionOrderIterator = 0 +def getPlayerConnectionOrderIterator(): + global playerConnectionOrderIterator + return playerConnectionOrderIterator + +def setPlayerConnectionOrderIterator(value): + global playerConnectionOrderIterator + playerConnectionOrderIterator = value + + +sessionPlayerStatsMap = {} +def getStatsMap(): + global sessionPlayerStatsMap + return sessionPlayerStatsMap + +def setStatsMap(map): + global sessionPlayerStatsMap + sessionPlayerStatsMap = map + + + +def init(): + host.registerHandler('PlayerConnect', onPlayerConnect, 1) + host.registerHandler('PlayerDisconnect', onPlayerDisconnect, 1) + host.registerHandler('Reset', onReset, 1) + + host.registerGameStatusHandler(onGameStatusChanged) + + print "Persistant stats module initialized." + + + +def onGameStatusChanged(status): + if status == bf2.GameStatus.Playing: + + # find highest player still connected + highestPid = -1 + for pid in sessionPlayerStatsMap: + if pid > highestPid: + highestPid = pid + + global playerConnectionOrderIterator + playerConnectionOrderIterator = highestPid + 1 + print "Reset orderiterator to %d based on highest pid kept" % playerConnectionOrderIterator + + # Reconnect players + if len(sessionPlayerStatsMap) == 0: + print "Reloading players" + for p in bf2.playerManager.getPlayers(): + onPlayerConnect(p) + + global army + roundArmies[1] = getArmy(bf2.gameLogic.getTeamName(1)) + roundArmies[2] = getArmy(bf2.gameLogic.getTeamName(2)) + + # All other hooks + host.registerHandler('PlayerKilled', onPlayerKilled) + host.registerHandler('PlayerDeath', onPlayerDeath) + host.registerHandler('EnterVehicle', onEnterVehicle) + host.registerHandler('ExitVehicle', onExitVehicle) + host.registerHandler('PickupKit', onPickupKit) + host.registerHandler('DropKit', onDropKit) + host.registerHandler('PlayerChangedSquad', onPlayerChangedSquad) + host.registerHandler('ChangedCommander', onChangedCommander) + host.registerHandler('ChangedSquadLeader', onChangedSquadLeader) + host.registerHandler('PlayerChangeWeapon', onPlayerChangeWeapon) + host.registerHandler('PlayerBanned', onPlayerBanned) + host.registerHandler('PlayerKicked', onPlayerKicked) + host.registerHandler('PlayerSpawn', onPlayerSpawn) + host.registerHandler('DeployGrapplingHook', onDeployGrapplingHook) + host.registerHandler('DeployZipLine', onDeployZipLine) + host.registerHandler('DeployTactical', onDeployTactical) + + for s in sessionPlayerStatsMap.itervalues(): + s.reset() + + for p in bf2.playerManager.getPlayers(): + p.stats.reinit(p) + p.stats.wasHereAtStart = 1 + + bf2.playerManager.enableScoreEvents() + + # stats have all been cleared enable next end of round stats + setSendEndOfRoundStats( True ) + +# Added by Chump - for fragalyzer + if debug_fraglog_enable: bf2.stats.fragalyzer_log.enable() + + elif status == bf2.GameStatus.EndGame: + + # finalize stats and send snapshot + for p in bf2.playerManager.getPlayers(): + p.stats.wasHereAtEnd = 1 + finalizePlayer(p) + + # check ensure we only send the end of round stats once + if getSendEndOfRoundStats(): + # show end-of-round information + setSendEndOfRoundStats( False ) + bf2.stats.endofround.invoke() + +# Added by Chump - for bf2statistics stats + # if not ranked, clean out stats vectors + #if not host.ss_getParam('ranked'): + # playerConnectionOrderIterator = 0 + # sessionPlayerStatsMap.clear() + + + +def onReset(data): + for s in sessionPlayerStatsMap.itervalues(): + s.reset() + + for p in bf2.playerManager.getPlayers(): + p.stats.reinit(p) + p.stats.wasHereAtStart = 1 + + + +class PlayerStat: + def __init__(self, player): + self.profileId = player.getProfileId() + self.playerId = player.index + self.id = self.playerId + self.isAIPlayer = player.isAIPlayer() + self.connectionOrderNr = 0 + self.rank = 0 + + self.reinit(player) + self.reset() + + def reinit(self, player): + self.name = player.getName() + #omero, 2006-04-13 + #self.ipaddr = player.getAddress() + self.ipaddr = fixPlayerAddress(player) + self.localScore = player.score + + def reset(self): + self.connectAt = date() + self.timeOnLine = 0 + + self.score = 0 + self.cmdScore = 0 + self.teamScore = 0 + self.skillScore = 0 + self.kills = 0 + self.teamkills = 0 + self.deaths = 0 + + self.vehicles = {} + for v in range(0, NUM_VEHICLE_TYPES + 1): + if not v in self.vehicles: + self.vehicles[v] = VehicleStat(v) + else: + self.vehicles[v].reset() + + self.weapons = {} + for w in range(0, NUM_WEAPON_TYPES + 1): + if not w in self.weapons: + self.weapons[w] = WeaponStat(w) + else: + self.weapons[w].reset() + + self.kits = {} + for k in range(0, NUM_KIT_TYPES + 1): + if not k in self.kits: + self.kits[k] = KitStat(k) + else: + self.kits[k].reset() + + self.killedByPlayer = {} + self.killedPlayer = {} + + self.team = 0 + + self.localScore.reset() + + self.bulletsFired = 0 + self.bulletsHit = 0 + + self.currentKillStreak = 0 + self.longestKillStreak = 0 + self.currentDeathStreak = 0 + self.longestDeathStreak = 0 + self.wasHereAtStart = 0 + self.wasHereAtEnd = 0 + self.complete = 0 + self.medals = None + + self.spawnedTeam = 3 + self.spawnedAt = 0 + self.becameCmdAt = 0 + self.becameSqlAt = 0 + self.joinedSquadAt = 0 + self.rawTimePlayed = 0 + self.rawTimeAsCmd = 0 + self.rawTimeAsSql = 0 + self.rawTimeInSquad = 0 + + self.timesBanned = 0 + self.timesKicked = 0 + + self.timeAsArmy = {} + for a in range(0, NUM_ARMIES + 1): + self.timeAsArmy[a] = 0 + + self.currentWeaponType = NUM_WEAPON_TYPES + + def __getattr__(self, name): + if name in self.__dict__: return self.__dict__[name] + elif name == 'timePlayed': + if self.spawnedAt: + timeDiff = date() - self.spawnedAt + self.rawTimePlayed += timeDiff + self.timeAsArmy[roundArmies[self.spawnedTeam]] += timeDiff + self.spawnedAt = date() + return self.rawTimePlayed + elif name == 'timeAsCmd': + if self.becameCmdAt: + self.rawTimeAsCmd += date() - self.becameCmdAt + self.becameCmdAt = date() + return self.rawTimeAsCmd + elif name == 'timeAsSql': + if self.becameSqlAt: + self.rawTimeAsSql += date() - self.becameSqlAt + self.becameSqlAt = date() + return self.rawTimeAsSql + elif name == 'timeInSquad': + if self.joinedSquadAt: + self.rawTimeInSquad += date() - self.joinedSquadAt + self.joinedSquadAt = date() + return self.rawTimeInSquad + elif name == 'accuracy': + if self.bulletsFired == 0: + return 0 + else: + return 1.0 * self.bulletsHit / self.bulletsFired + else: + raise AttributeError, name + + # when same player rejoins server + def reconnect(self, player): + self.connectAt = date() + #self.ipaddr = player.getAddress() + self.ipaddr = fixPlayerAddress(player) + + bf2.playerManager.disableScoreEvents() + + print "Reattaching score object from old dead player %d to new player %d" % (self.localScore.index, player.index) + + player.score = self.localScore + player.score.index = player.index + + player.score.score = self.score + player.score.cmdScore = self.cmdScore + player.score.rplScore = self.teamScore + player.score.skillScore = self.skillScore + player.score.kills = self.kills + player.score.TKs = self.teamkills + player.score.deaths = self.deaths + + player.score.rank = self.rank + + bf2.playerManager.enableScoreEvents() + + # calculate final stats values for this player (disconnected or end of round) + def finalize(self, player): + + self.copyPlayerData(player) + + if self.currentWeaponType != NUM_WEAPON_TYPES: + self.weapons[self.currentWeaponType].exit(player) + self.currentWeaponType = NUM_WEAPON_TYPES + + stopSpawned(player) + stopInSquad(player) + stopAsSql(player) + stopAsCmd(player) + +# Added by Chump - for bf2statistics stats + #if self.wasHereAtStart == 1 and self.wasHereAtEnd == 1: + if self.wasHereAtEnd == 1: + self.complete = 1 + + # sum up vehicles & kits + collectBulletsFired(player) + finalizeBulletsFired(player) + + for v in player.stats.vehicles.itervalues(): + if v.enterAt != 0: v.exit(player) + for v in player.stats.kits.itervalues(): + if v.enterAt != 0: v.exit(player) + for v in player.stats.weapons.itervalues(): + if v.enterAt != 0: v.exit(player) + + # copy data to player-stats, as player might not be available after this + def copyPlayerData(self, player): + self.timeOnLine += date() - self.connectAt + + self.localScore = player.score + + self.score = player.score.score + self.cmdScore = player.score.cmdScore + self.teamScore = player.score.rplScore + self.skillScore = player.score.skillScore + + if self.score < 0: self.score = 0 + if self.cmdScore < 0: self.cmdScore = 0 + if self.teamScore < 0: self.teamScore = 0 + if self.skillScore < 0: self.skillScore = 0 + + self.kills = player.score.kills + self.teamkills = player.score.TKs + self.deaths = player.score.deaths + + self.rank = player.score.rank + self.army = roundArmies[player.getTeam()] + self.team = player.getTeam() + +# Added by Chump - for bf2statistics stats (plus de-indenting) + #if host.ss_getParam('ranked'): + if hasattr(player, 'medals'): + self.medals = player.medals + else: + if g_debug: print "Player had no medal stats. pid=", player.index + + + +class ObjectStat: + def __init__(self, type): + self.reset() + self.type = type + + def reset(self): + + # reset all non-global + self.kills = 0 + self.killedBy = 0 + self.rawTimeInObject = 0 + self.deaths = 0 + self.score = 0 + self.bulletsFired = 0 + self.bulletsFiredTemp = 0 + self.bulletsHit = 0 + self.bulletsHitTemp = 0 + self.enterAt = 0 + self.enterScore = 0 + self.deployed = 0 + + def enter(self, player): + self.enterAt = date() + self.enterScore = player.score.score + if g_debug: print "STATS ObjectStat: %s Enter type=%s --- enterAt:%s score:%d" % (player.getName(), self.type, self.enterAt, self.enterScore) + + def exit(self, player): + if self.enterAt == 0: return + time = self.timeInObject + self.enterAt = 0 + + self.score += player.score.score - self.enterScore + self.enterScore = 0 + if g_debug: print "STATS ObjectStat: %s Exit type=%s --- timeInObject:%s score:%d" % (player.getName(), self.type, time, self.score) + + def __getattr__(self, name): + if name in self.__dict__: return self.__dict__[name] + elif name == 'timeInObject' or name == 'rtime': + if self.enterAt: + self.rawTimeInObject += date() - self.enterAt + self.enterAt = date() + return self.rawTimeInObject + elif name == 'accuracy': + if self.bulletsFired == 0: + return 0 + else: + return 1.0 * self.bulletsHit / self.bulletsFired + else: + raise AttributeError, name + + + +class VehicleStat(ObjectStat): + def __init__(self, type): + ObjectStat.__init__(self, type) + self.reset() + + def reset(self): + ObjectStat.reset(self) + self.roadKills = 0 + + + +class KitStat(ObjectStat): + def __init__(self, type): + ObjectStat.__init__(self, type) + self.reset() + + def reset(self): + ObjectStat.reset(self) + + + +class WeaponStat(ObjectStat): + def __init__(self, type): + ObjectStat.__init__(self, type) + self.reset() + + def reset(self): + ObjectStat.reset(self) + + def enter(self, player): + if player.stats.currentWeaponType != NUM_WEAPON_TYPES: + player.stats.weapons[player.stats.currentWeaponType].exit(player) + player.stats.currentWeaponType = self.type + + ObjectStat.enter(self, player) + + def exit(self,player): + time = date() - self.enterAt + + ObjectStat.exit(self, player) + + + +def date(): + return host.timer_getWallTime() + + + +def finalizePlayer(player): + player.stats.finalize(player) + + + +def onPlayerConnect(player): + + # see if player already has a record + player.stats = None + connectingProfileId = player.getProfileId() + for stats in sessionPlayerStatsMap.itervalues(): + if connectingProfileId > 0 and connectingProfileId == stats.profileId: + print "Found old player record, profileId ", str(stats.profileId) + player.stats = stats + player.stats.reconnect(player) + + if not player.stats: + + print "Creating new record for player profileId ", str(connectingProfileId) + + # add stats record + global playerConnectionOrderIterator + id = playerConnectionOrderIterator + + newPlayerStats = PlayerStat(player) + + sessionPlayerStatsMap[id] = newPlayerStats + player.stats = sessionPlayerStatsMap[id] + + player.stats.connectionOrderNr = playerConnectionOrderIterator + playerConnectionOrderIterator += 1 + + player.score.rank = player.stats.rank + + + +def onPlayerDisconnect(player): + finalizePlayer(player) + + +#********************************************************* +# XPACK SPECIFIC +#********************************************************* +def onDeployGrapplingHook(player): + if player == None: return + + if g_debug: print "STATS.py: Deployed Grappling hook" + player.stats.weapons[WEAPON_TYPE_GRAPPLINGHOOK].deployed += 1 + return + +def onDeployZipLine(player): + if player == None: return + + if g_debug: print "STATS.py: Deployed Zipline" + player.stats.weapons[WEAPON_TYPE_ZIPLINE].deployed += 1 + return + +def onDeployTactical(player): + if player == None: return + + if g_debug: print "STATS.py: Deployed Tactical" + player.stats.weapons[WEAPON_TYPE_TACTICAL].deployed += 1 + return + +#********************************************************* +#********************************************************* +#********************************************************* + +def onEnterVehicle(player, vehicle, freeSoldier = False): + + if player == None: return + + vehicleType = getVehicleType(vehicle.templateName) + if vehicleType != VEHICLE_TYPE_SOLDIER: + rootVehicle = bf2.objectManager.getRootParent(vehicle) + vehicleType = getVehicleType(rootVehicle.templateName) + else: + rootVehicle = vehicle + + if vehicleType != VEHICLE_TYPE_SOLDIER: + for w in player.stats.weapons.itervalues(): + w.exit(player) + + weapon = player.getPrimaryWeapon() + if weapon: + weaponType = getWeaponType(weapon.templateName) + player.stats.weapons[weaponType].enter(player) + + if not vehicleType in player.stats.vehicles: + player.stats.vehicles[vehicleType] = VehicleStat() + + player.stats.vehicles[vehicleType].enter(player) + if vehicleType != VEHICLE_TYPE_UNKNOWN: + player.stats.lastVehicleType = vehicleType + + weapon = player.getPrimaryWeapon() + if weapon: + player.stats.lastWeaponType = getWeaponType(weapon.templateName) + + collectBulletsFired(player) + + if g_debug: + pos = getPosStr(vehicle.getPosition()) + print "STATS onEnterVehicle: Enter vehicle=%s type=%s Pos=%s" % ( rootVehicle.templateName, vehicleType, pos ) + +def onExitVehicle(player, vehicle): + + vehicleType = getVehicleType(vehicle.templateName) + if vehicleType != VEHICLE_TYPE_SOLDIER: + rootVehicle = bf2.objectManager.getRootParent(vehicle) + vehicleType = getVehicleType(rootVehicle.templateName) + + # keep track of last driver, for road kill scoring purposes + if rootVehicle == vehicle: + vehicle.lastDrivingPlayerIndex = player.index + + else: rootVehicle = vehicle + + weapon = player.getPrimaryWeapon() + if weapon: + weaponType = getWeaponType(weapon.templateName) + player.stats.weapons[weaponType].enter(player) + + player.stats.vehicles[vehicleType].exit(player) + + weapon = player.getPrimaryWeapon() + if weapon: + player.stats.lastWeaponType = getWeaponType(weapon.templateName) + + collectBulletsFired(player) + + pos = getPosStr(vehicle.getPosition()) + if g_debug: print "STATS onExitVehicle: Exit vehicle=%s type=%s Pos=%s" % ( rootVehicle.templateName, vehicleType, pos ) + + +def onPlayerSpawn(player, soldier): + if g_debug: print "STATS onPlayerSpawn %s" % ( player.getName() ) + + startSpawned(player) + if player.getSquadId() != 0: startInSquad(player) + if player.isSquadLeader(): startAsSql(player) + if player.isCommander(): startAsCmd(player) + + onEnterVehicle(player, soldier) + player.soldier = soldier + + +def onPickupKit(player, kit): + if g_debug: print "STATS onPickupKit %s kit=%s " % ( player.getName(), kit.templateName ) + + kitType = getKitType(kit.templateName) + + if not kitType in player.stats.kits: + player.stats.kits[kitType] = KitStat() + + if g_debug: print "STATS onPickupKit %s triggering --> player.stats.kits[kitType].enter(player)" % ( player.getName() ) + player.stats.kits[kitType].enter(player) + player.stats.lastKitType = kitType + + weapon = player.getPrimaryWeapon() + if weapon: + player.stats.lastWeaponType = getWeaponType(weapon.templateName) + + + +def onDropKit(player, kit): + if g_debug: print "STATS onDropKit %s kit=%s " % ( player.getName(), kit.templateName ) + + kitType = getKitType(kit.templateName) + + if g_debug: print "STATS onDropKit %s triggering --> player.stats.kits[kitType].exit(player)" % ( player.getName() ) + player.stats.kits[kitType].exit(player) + + for w in player.stats.weapons.itervalues(): + w.exit(player) + + collectBulletsFired(player) + + + +def onPlayerChangeWeapon(player, oldWeapon, newWeapon): + if g_debug: print "STATS onPlayerChangeWeapon %s " % ( player.getName() ) + + if oldWeapon: + oldWeaponType = getWeaponType(oldWeapon.templateName) + + if g_debug: print "STATS onPlayerChangeWeapon %s oldWeapon=%s triggering --> player.stats.weapons[oldWeaponType].exit(player) " % ( player.getName(), oldWeapon.templateName ) + player.stats.weapons[oldWeaponType].exit(player) + + if newWeapon: + newWeaponType = getWeaponType(newWeapon.templateName) + + if g_debug: print "STATS onPlayerChangeWeapon %s newWeapon=%s triggering --> player.stats.weapons[newWeaponType].exit(player) " % ( player.getName(), newWeapon.templateName ) + player.stats.weapons[newWeaponType].enter(player) + player.stats.lastWeaponType = newWeaponType + + + +def onPlayerKilled(victim, attacker, weapon, assists, object): + # check if killed by vehicle in motion + killedByEmptyVehicle = False + if attacker == None and weapon == None and object != None: + if hasattr(object, 'lastDrivingPlayerIndex'): + attacker = bf2.playerManager.getPlayerByIndex(object.lastDrivingPlayerIndex) + killedByEmptyVehicle = True + + #omero,2006-05-01 + #known informations + #This is only for debug info, so lets not do anything unless + # we are actually debugging. ;) + if g_debug: + vctm_name=victim.getName() + vctm_vehv=victim.getVehicle() + vctm_veht=getVehicleType(vctm_vehv.templateName) + if vctm_veht != VEHICLE_TYPE_SOLDIER: + vctm_vehr=bf2.objectManager.getRootParent(vctm_vehv) + vctm_vehn=str(vctm_vehr.templateName) + vctm_veht=getVehicleType(vctm_vehn) + else: + vctm_vehr=vctm_vehv + vctm_vehn=str(vctm_vehr.templateName) + vctm_veht=getVehicleType(vctm_vehn) + + atkr_name='None' + atkr_vehn='None' + atkr_veht='None' + if attacker and not killedByEmptyVehicle: + atkr_name=attacker.getName() + atkr_vehv=attacker.getVehicle() + atkr_veht=getVehicleType(atkr_vehv.templateName) + if atkr_veht != VEHICLE_TYPE_SOLDIER: + atkr_vehr=bf2.objectManager.getRootParent(atkr_vehv) + atkr_vehn=str(atkr_vehr.templateName) + atkr_veht=getVehicleType(atkr_vehn) + else: + atkr_vehr=atkr_vehv + atkr_vehn=str(atkr_vehr.templateName) + atkr_veht=getVehicleType(atkr_vehn) + + if attacker and killedByEmptyVehicle: + atkr_name=attacker.getName() + atkr_vehn=object.templateName + atkr_veht=getVehicleType(atkr_vehn) + + + if attacker == None and object != None: + if g_debug: print "STATS onPlayerKilled %s (maybe) killed by ARTILLERY" % ( victim.getName() ) + + if attacker == None and weapon == None and object != None: + if g_debug: print "STATS onPlayerKilled %s (maybe) killed by EMPTYMOVINGVEHICLE" % ( victim.getName() ) + + + if victim and attacker: + if victim.getName() == attacker.getName(): + if g_debug: print "STATS onPlayerKilled %s killed by SUICIDE!" % ( victim.getName() ) + + if victim.getTeam() == attacker.getTeam(): + if g_debug: print "STATS onPlayerKilled %s killed by MATES!" % ( victim.getName() ) + + + if weapon == None and object != None: + if g_debug: print "STATS onPlayerKilled no weapon but object=" + object.templateName + + if weapon: + if g_debug: print "STATS onPlayerKilled weapon=%s" %( weapon.templateName ) + + if object: + if g_debug: print "STATS onPlayerKilled object=%s" % ( object.templateName ) + + wepn_name='None' + if weapon: + wepn_name=weapon.templateName + + elif object: + wepn_name=object.templateName + + else: + if g_debug: print "STATS onPlayerKilled no weapon nor object" + + + # killed by enemy + if attacker != None: + + # no kill stats for teamkills / suicides! + if attacker.getTeam() != victim.getTeam(): + + # streaks + attacker.stats.currentKillStreak += 1 + if attacker.stats.currentKillStreak > attacker.stats.longestKillStreak: + attacker.stats.longestKillStreak = attacker.stats.currentKillStreak + + # end current death streak + attacker.stats.currentDeathStreak = 0 + + # killedBy + if attacker != None: + if not victim.stats.connectionOrderNr in attacker.stats.killedPlayer: + attacker.stats.killedPlayer[victim.stats.connectionOrderNr] = 0 + attacker.stats.killedPlayer[victim.stats.connectionOrderNr] += 1 + + if not attacker.stats.connectionOrderNr in victim.stats.killedByPlayer: + victim.stats.killedByPlayer[attacker.stats.connectionOrderNr] = 0 + victim.stats.killedByPlayer[attacker.stats.connectionOrderNr] += 1 + + + # weapon stats + if weapon != None: + weaponType = getWeaponType(weapon.templateName) + + if attacker != None: + attacker.stats.weapons[weaponType].kills += 1 + + if victim != None: + victim.stats.weapons[weaponType].killedBy += 1 + + # vehicle stats + vehicleType = None + if killedByEmptyVehicle: + vehicleType = getVehicleType(object.templateName) + else: + vehicle = attacker.getVehicle() + vehicleType = getVehicleType(vehicle.templateName) + + if vehicleType != VEHICLE_TYPE_SOLDIER: + rootVehicle = bf2.objectManager.getRootParent(vehicle) + if rootVehicle != None: + vehicleType = getVehicleType(rootVehicle.templateName) + + if vehicleType != None: + if attacker != None: + attacker.stats.vehicles[vehicleType].kills += 1 + if victim != None: + victim.stats.vehicles[vehicleType].killedBy += 1 + + # road kill + if weapon == None and object != None: + attacker.stats.vehicles[vehicleType].roadKills += 1 + + + # kit stats + if attacker != None: + kit = attacker.getKit() + if kit != None: + kitTemplateName = kit.templateName + kitType = getKitType(kitTemplateName) + elif hasattr(attacker, 'lastKitType'): + kitType = attacker.lastKitType + else: + return + + attacker.stats.kits[kitType].kills += 1 + + # death stats are handled in onPlayerDeath. + + #omero, 2006-05-01 + if g_debug: print "STATS onPlayerKilled vctm=%s atkr=%s wepn=%s atkr_vehn=%s atkr_veht=%s" % ( vctm_name, atkr_name, wepn_name, atkr_vehn, atkr_veht ) + + collectBulletsFired(attacker) + + + +def onPlayerDeath(victim, vehicle): + + # vehicle is already exited, as this happens before actual death. That doesnt stop us from dying in it. + rootVehicle = bf2.objectManager.getRootParent(vehicle) + vehicleType = getVehicleType(rootVehicle.templateName) + + if g_debug: print "STATS onPlayerDeath %s rootVehicle=%s" % ( victim.getName(), rootVehicle.templateName ) + + stopSpawned(victim) + stopInSquad(victim) + stopAsSql(victim) + stopAsCmd(victim) + + if g_debug: print "STATS onPlayerDeath %s triggering ---> onExitVehicle(victim, victim.soldier)" % ( victim.getName() ) + onExitVehicle(victim, victim.soldier) + finalizeBulletsFired(victim) + clearBulletsFired(victim) + + # streaks + victim.stats.currentDeathStreak += 1 + if victim.stats.currentDeathStreak > victim.stats.longestDeathStreak: + victim.stats.longestDeathStreak = victim.stats.currentDeathStreak + + # end current kill streak + victim.stats.currentKillStreak = 0 + + victim.stats.vehicles[vehicleType].deaths += 1 + + # kit is already dropped, so we have to get the last kit used + victim.stats.kits[victim.stats.lastKitType].deaths += 1 + + # weapon is already dropped, so we gave to get the last weapon used + victim.stats.weapons[victim.stats.lastWeaponType].deaths += 1 + + + +# update accuracy on weapon, kit and vehicle +def collectBulletsFired(player): + if player == None: return + + # count bullets fired + bulletsFired = player.score.bulletsFired + totBulletsFired = 0 + kitBulletsFired = 0 + for b in bulletsFired: + templateName = b[0] + nr = b[1] + + weaponType = getWeaponType(templateName) + player.stats.weapons[weaponType].bulletsFiredTemp = nr + totBulletsFired += nr + + # only count kit stats for soldier-type weapons + if weaponType != WEAPON_TYPE_UNKNOWN: + kitBulletsFired += nr + + + # count bullets hit + bulletsHit = player.score.bulletsGivingDamage + totBulletsHit = 0 + kitBulletsHit = 0 + for b in bulletsHit: + templateName = b[0] + nr = b[1] + + weaponType = getWeaponType(templateName) + player.stats.weapons[weaponType].bulletsHitTemp = nr + totBulletsHit += nr + + # only count kit stats for soldier-type weapons + if weaponType != WEAPON_TYPE_UNKNOWN: + kitBulletsHit += nr + + + # dont bother giving kit stats if we're in a vehicle + kit = player.getKit() + if kit != None: + kitType = getKitType(kit.templateName) + player.stats.kits[kitType].bulletsFiredTemp = kitBulletsFired + player.stats.kits[kitType].bulletsHitTemp = kitBulletsHit + + vehicle = player.getVehicle() + if vehicle != None: + rootVehicle = bf2.objectManager.getRootParent(vehicle) + vehicleType = getVehicleType(rootVehicle.templateName) + + player.stats.vehicles[vehicleType].bulletsFiredTemp = totBulletsFired + player.stats.vehicles[vehicleType].bulletsHitTemp = totBulletsHit + + + +def clearBulletsFired(player): + +# Added by Chump - for fragalyzer + #bf2.stats.fragalyzer_log.dumpAccuracy(player) + + bulletsFired = player.score.bulletsFiredAndClear + bulletsHit = player.score.bulletsGivingDamageAndClear + + + +def finalizeBulletsFired(player): + for v in player.stats.vehicles.itervalues(): + v.bulletsFired += v.bulletsFiredTemp + v.bulletsHit += v.bulletsHitTemp + v.bulletsFiredTemp = 0 + v.bulletsHitTemp = 0 + for w in player.stats.weapons.itervalues(): + w.bulletsFired += w.bulletsFiredTemp + w.bulletsHit += w.bulletsHitTemp + player.stats.bulletsFired += w.bulletsFiredTemp + player.stats.bulletsHit += w.bulletsHitTemp + w.bulletsFiredTemp = 0 + w.bulletsHitTemp = 0 + for k in player.stats.kits.itervalues(): + k.bulletsFired += k.bulletsFiredTemp + k.bulletsHit += k.bulletsHitTemp + k.bulletsFiredTemp = 0 + k.bulletsHitTemp = 0 + + + +def startSpawned(player): + player.stats.spawnedAt = date() + player.stats.spawnedTeam = player.getTeam() + +def startInSquad(player): player.stats.joinedSquadAt = date() +def startAsSql(player): player.stats.becameSqlAt = date() +def startAsCmd(player): player.stats.becameCmdAt = date() + + + +def stopSpawned(player): + time = player.stats.timePlayed + player.stats.spawnedAt = 0 + player.stats.spawnedTeam = 3 + +def stopInSquad(player): + time = player.stats.timeInSquad + player.stats.joinedSquadAt = 0 + +def stopAsSql(player): + time = player.stats.timeAsSql + player.stats.becameSqlAt = 0 + +def stopAsCmd(player): + time = player.stats.timeAsCmd + player.stats.becameCmdAt = 0 + + +def onChangedCommander(team, oldCmd, newCmd): + if newCmd and newCmd.stats.spawnedAt != 0: startAsCmd(newCmd) + if oldCmd: stopAsCmd(oldCmd) + + if g_debug: print "STATS onChangeCommander team=%s oldCmd=%s newCmd=%s" % ( team, oldCmd.getName(), newCmd.getName() ) + +def onChangedSquadLeader(squad, oldSql, newSql): + if newSql and newSql.stats.spawnedAt != 0: startAsSql(newSql) + if oldSql: stopAsSql(oldSql) + + #This is only for debug info, so lets not do anything unless + # we are actually debugging. ;) + if g_debug: + osql_name = 'None' + oteam = 'None' + nsql_name = 'None' + nteam = 'None' + + if oldSql != None: + osql_name = oldSql.getName() + oteam = oldSql.getTeam() + + if newSql != None: + nsql_name = newSql.getName() + nteam = newSql.getTeam() + + if g_debug: print "STATS onChangeSquadLeader squad=%s oteam=%s oldSql=%s nteam=%s newSql=%s" % ( squad, oteam, osql_name, nteam, nsql_name ) + + +def onPlayerChangedSquad(player, oldSquad, newSquad): + + if g_debug: print "STATS onChangeSquad %s oldSqd=%s newSqd=%s" % ( player.getName(), oldSquad, newSquad ) + + if oldSquad == newSquad: + return + + if player.stats.spawnedAt == 0: + return + + if oldSquad == 0: startInSquad(player) + if newSquad == 0: + stopAsSql(player) + stopInSquad(player) + + + +def onPlayerBanned(player, time, type): + + # dont count round bans + if type == 2: return + + player.stats.timesBanned += 1 + + + +def onPlayerKicked(player): + player.stats.timesKicked += 1 diff --git a/src/python/bf2/stats/unlocks.py b/src/python/bf2/stats/unlocks.py new file mode 100644 index 00000000..d9cd6101 --- /dev/null +++ b/src/python/bf2/stats/unlocks.py @@ -0,0 +1,117 @@ +import host +import bf2.PlayerManager +from bf2.stats.constants import * +from bf2 import g_debug + +# ------------------------------------------------------------------------------ +# omero 2006-02-27 +# ------------------------------------------------------------------------------ +from bf2.BF2StatisticsConfig import http_backend_addr, http_backend_port +from bf2.stats.miniclient import miniclient, http_get + + + +# map gamespy item ids to kits +unlockItemMap = { + 11 : 0, + 22 : 1, + 33 : 2, + 44 : 3, + 55 : 4, + 66 : 5, + 77 : 6, + 88 : 1, + 99 : 2, + 111 : 3, + 222 : 4, + 333 : 5, + 444 : 0, + 555 : 6, + } + +sessionPlayerUnlockMap = {} + + + +def init(): + if g_debug: print "Initializing unlock module..." + # Events + host.registerHandler('PlayerConnect', onPlayerConnect, 1) + +# Added by Chump - for bf2statistics stats (plus de-indenting) + #if bf2.serverSettings.getUseGlobalUnlocks(): + host.registerHandler('PlayerUnlocksResponse', onUnlocksResponse, 1) + + # Connect already connected players if reinitializing + for p in bf2.playerManager.getPlayers(): + onPlayerConnect(p) + + if g_debug: print "Unlock module initialized" + + + +class UnlockSet: pass + + + +def onPlayerConnect(player): + + defaultUnlocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + host.pers_plrSetUnlocks(player.index, defaultUnlocks, defaultUnlocks) + + if g_debug: print "Unlock module: onPlayerConnect" + if not player.isAIPlayer(): + id = player.index + reconnect = id in sessionPlayerUnlockMap + + # always get new unlocks on reconnect/map restart/map change etc + if reconnect: + del sessionPlayerUnlockMap[id] + + newUnlockSet = UnlockSet() + + newUnlockSet.unlockLevel = {} + for i in range(0, NUM_KIT_TYPES): + newUnlockSet.unlockLevel[i] = 0 + + sessionPlayerUnlockMap[id] = newUnlockSet + player.unlocks = sessionPlayerUnlockMap[id] + +# Added by Chump - for bf2statistics stats (plus de-indenting) + #if bf2.serverSettings.getUseGlobalUnlocks(): + if player.getProfileId() > 2000: + # Added by ArmEagle needed to prevent servercrash on linux on offline account connect + # but host.pmgr_p_set logically raises an exception when called on an online account + if host.pmgr_p_get("profileid", player.index) == 0: + host.pmgr_p_set("profileid", player.index, player.getProfileId()) + + success = host.pers_plrRequestUnlocks(player.index, 1) + if not success: + if g_debug: print "Requesting unlocks: Failed" + else: + if g_debug: print "Requesting unlocks: Success" + + else: + if g_debug: print "Player %d had no profile id, can't request unlocks" % player.index + + if g_debug: print "Added player %d to unlock checking" % (player.index) + + + +def onUnlocksResponse(succeeded, player, unlocks): + if not succeeded: + print "Unlocks request failed for player %d (%s): %s" % (player.index, player.getName(), unlocks) + return + + if g_debug: print "Unlocks received for player %d (%s): %s" % (player.index, player.getName(), unlocks) + + # translate gamespy item vector into a kit-based unlock vector handled by game + kitUnlocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + for item in unlocks: + if item in unlockItemMap: + kitUnlocks[unlockItemMap[item]] = 1 + + if g_debug: print "Kit unlocks: ", kitUnlocks + #We do not yet support giving different unlocks to different teams + host.pers_plrSetUnlocks(player.index, kitUnlocks, kitUnlocks) +