Jump to content
Korean Random

Heliomalt

User
  • Content Count

    225
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by Heliomalt

  1. Game crash at client start, before hangar is loaded. Attached the python.log, xvm.log is empty. Clean install, no other mods. python.log
  2. Is something possible with XVM? http://forum.worldoftanks.eu/index.php?/topic/717770-17112019-12-10-vehicle-parameters-on-single-list-by-rajcel/
  3. For a long time now, after the battle in the hangar, I only see the WoT standard popup for the battle result. The battle result is displayed correctly in the notification center, the pop-up in the battle that shows the result of the last battle also works. Is there a solution? config.json mod_stat.py
  4. I get this error in python.log 2020-02-02 15:05:47.727: INFO: ============================= 2020-02-02 15:05:47.727: INFO: 2020-02-02 15:05:47: [ERROR] mods/xfw_libraries/xfw/events.pyc 2020-02-02 15:05:47.727: ERROR: Traceback (most recent call last): 2020-02-02 15:05:47.727: ERROR: File "./xfw/events.py", line 57, in __event_handler 2020-02-02 15:05:47.727: ERROR: File "./xfw/events.py", line 24, in fire 2020-02-02 15:05:47.727: ERROR: File "res_mods/configs/xvm/py_macro\safeShot.py", line 66, in handleKeyEvent 2020-02-02 15:05:47.728: ERROR: if not (safeShotConfig['enabled'] and player().isVehicleAlive and not isEventBattle and (safeShotConfig['disableKey'] == event.key) and not event.isRepeatedEvent() and not MessengerEntry.g_instance.gui.isFocused()): 2020-02-02 15:05:47.728: ERROR: AttributeError: 'PlayerAccount' object has no attribute 'isVehicleAlive' 2020-02-02 15:05:47.728: INFO: ============================= The old script work without error. Changed line 67 from last version: if not (safeShotConfig['enabled'] and not isEventBattle and (safeShotConfig['disableKey'] == event.key) and not event.isRepeatedEvent() and not MessengerEntry.g_instance.gui.isFocused()): Works without error in log, but not tested in game.
  5. @HEKPOMAHT watched the replay, chancePenetration.py is working as it should or I am blind. I have seen that you have deliberately swung back and forth towards the target, but the display of the values for armor and penetration has always disappeared if you have not aimed at the tank. Or do I get something wrong here?
  6. Simple solution: Do not use the anonymizer and benefit from all functions that XVM offers. Life can be so easy...
  7. I have the same problem. If you reactivate the service, the service on modxvm.com will be deactivated the next time you start the game. Deleting cache and temp folders does not help. XVM 8.2.4 (3 and 9) clean install Edit: Seems fixed, tried on two devices.
  8. @Slava7572 // Anonym Icon. "IsAnonym": { "enabled": true, "x": 128, "y": 5, "width": 25, "height": 16, "align": "center", "alpha": "{{py:IsAnonym('{{name}}')}}", "bindToIcon": true, "src": "img://gui/maps/icons/library/icon_eye.png" }, "extraFieldsLeft": [ ${"def.IsAnonym"} ], "extraFieldsRight": [ ${"def.IsAnonym"} ]
  9. Do you have a link to this updated rules? Thanks in advance.
  10. With Budyx69 script it works as it should, except that anonymous players see who else is anonymous.
  11. After some testing, I have to say that the code doesn't work 100%. If you have activated the playerstats at battle, then the icon for the anonymous players will be displayed. If you are anonymous yourself or have deactivated the playerstats at battle, then the icon is displayed for every player, even for themselves. What is missing is the detection of whether someone is really anonymous and then they are really only displayed, regardless of whether you have activated the playerstats at battle or not. If you are anonymous yourself, no icon should be displayed. Here is another way, but the same problem as described above. // Anonym Icon. "anon": { "enabled": true, "x": 128, "y": 5, "width": 25, "height": 16, "align": "center", "alpha": "{{r?0|100}}", "bindToIcon": true, "src": "img://gui/maps/icons/library/icon_eye.png" }, Is there a solution, or is it not possible to display the icon correctly if you are anonymous or have deactivated the statistics in battle?
  12. Found a solution: // Anonym Icon. "anon": { "enabled": true, "x": 128, "y": 5, "width": 25, "height": 16, "align": "center", "alpha": 100, "bindToIcon": true, "format": "{{r?| <img src='img://gui/maps/icons/library/icon_eye.png'>}}" }, add in extraFieldsLeft and extraFieldsRight: ${"def.anon"},
  13. I'm trying to show an icon, following the same principle as the Friend Icon, but nothing is displayed. "anon": { "enabled": true, "x": 128, "y": 5, "width": 12, "height": 18, "align": "center", "alpha": 100, "bindToIcon": true, "src": "xvm://res/icons/other/{{name?anon}}.png" And maybe someone knows the location of the vanilla crossed-out eye? Tested with replay, not live. playersPanel.xc
  14. @sirmax Yes, link in browser is working. Maybe something to do with that? Edit: Seems fixed now. Thanks for your effort!
  15. The wn8exp.json data download is working, but the xvmscales.json download is an empty file locally, no error, no data.
  16. Its not my script, its from Tomonik. see http://forum.worldoftanks.eu/index.php?/topic/572771-1610-session-statistics-and-battle-result-messages/#topmost # Python bytecode 2.7 (decompiled from Python 2.7) # Embedded file name: D:\Mods\World_of_Tanks\SessionStatistics\mod_stat.py # Compiled at: 2019-10-09 17:47:22 import BigWorld import AccountCommands import ArenaType import codecs import datetime import json import math import os import re import ResMgr import threading import nations import urllib from Account import Account from account_helpers import BattleResultsCache from items import vehicles as vehiclesWG from helpers import i18n from notification.NotificationListView import NotificationListView from notification.NotificationPopUpViewer import NotificationPopUpViewer from messenger import MessengerEntry from messenger.formatters.service_channel import BattleResultsFormatter from Queue import Queue from debug_utils import * from gui.Scaleform.daapi.view.meta.NotificationsListMeta import NotificationsListMeta from gui import SystemMessages from constants import ARENA_GUI_TYPE from gui.battle_results.components.common import RegularArenaFullNameItem from gui.battle_results.components.common import _ARENA_FULL_NAME_FORMAT, _ARENA_TYPE_FORMAT, _ARENA_TYPE_EXT_FORMAT from urllib2 import urlopen GENERAL = 0 BY_TANK_1 = 11 BY_TANK_2 = 12 BY_TANK_3 = 13 BY_TANK_4 = 14 BY_TANK_5 = 15 BY_TANK_6 = 16 BY_TANK_7 = 17 BY_TANK_8 = 18 BY_TANK_9 = 19 BY_TANK_10 = 20 BY_MAP_1 = 21 BY_MAP_2 = 22 BY_MAP_3 = 23 BY_MAP_4 = 24 BY_MAP_5 = 25 RESET = 30 def hexToRgb(hex): return [ int(hex[i:i + 2], 16) for i in range(1, 6, 2) ] def gradColor(startColor, endColor, val): start = hexToRgb(startColor) end = hexToRgb(endColor) grad = [] for i in [0, 1, 2]: grad.append(start[i] * (1.0 - val) + end[i] * val) return '#%02x%02x%02x' % (grad[0], grad[1], grad[2]) class SessionStatistic(object): def __init__(self): self.page = GENERAL self.cacheVersion = 7 self.queue = Queue() self.loaded = False self.configIsValid = True self.battleStats = {} self.cache = {} self.gradient = {} self.palette = {} self.config = {} self.arenaUniqueID = None self.expectedValues = {} self.expectedKTTCValues = {} self.xvmscales = {} self.values = {} self.battles = [] self.battleStatPatterns = [] self.messageGeneral = '' self.messageByTank = '' self.messageByMap = '' self.messageReset = '' self.tankSortingMacros = {} self.mapSortingMacros = {} self.playerName = '' self.bgIcon = '' self.startDate = None self.battleResultsAvailable = threading.Event() self.battleResultsAvailable.clear() self.battleResultsBusy = threading.Lock() self.thread = threading.Thread(target=self.mainLoop) self.thread.setDaemon(True) self.thread.start() self.path = '/'.join(['..', 'res_mods', 'configs', 'wotstat']) self.readConfig() return def load(self): if self.loaded and self.playerName == BigWorld.player().name: return self.loaded = True self.battles = [] self.playerName = BigWorld.player().name self.statCacheFilePath = '/'.join([self.path, 'cache.json']) invalidCache = True if os.path.isfile(self.statCacheFilePath): with open(self.statCacheFilePath) as jsonCache: self.cache = json.load(jsonCache) self.startDate = self.cache.get('date', self.getWorkDate()) if self.cache.get('version', 0) == self.cacheVersion and (self.startDate == self.getWorkDate() or not self.config.get('dailyAutoReset', True)) and not self.config.get('clientReloadReset', False): if self.cache.get('players', {}).has_key(self.playerName): self.battles = self.cache['players'][self.playerName]['battles'] invalidCache = False if invalidCache: self.cache = {} expectedValuesPath = '/'.join([self.path, 'data', 'expected_tank_values.json']) if self.config.get('onlineUpdateData', True): expectedTankValuesURL = self.config.get('expectedTankValuesURL', 'https://static.modxvm.com/wn8-data-exp/json/wn8exp.json') localExpectedTankValues = json.load(open(expectedValuesPath)) localVersionExpectedTankValues = json.dumps(localExpectedTankValues['header']['version']) updateExpectedOK = False try: newExpectedValuesPath = urlopen(expectedTankValuesURL).read() newExpectedTankValues = json.loads(newExpectedValuesPath) newVersionExpectedTankValues = json.dumps(newExpectedTankValues['header']['version']) if newVersionExpectedTankValues != localVersionExpectedTankValues: urllib.urlretrieve(expectedTankValuesURL, expectedValuesPath) updateExpectedOK = True except: pass if self.config.get('showExpectedTankValuesMessage', True): if updateExpectedOK: SystemMessages.pushMessage("<font color='#FFE6B3'>Session Statistics</font>\nExpected Tank Values updated to version: " + newVersionExpectedTankValues, type=SystemMessages.SM_TYPE.Information) else: SystemMessages.pushMessage("<font color='#FFE6B3'>Session Statistics</font>\nExpected Tank Values\nversion: " + localVersionExpectedTankValues, type=SystemMessages.SM_TYPE.Information) with open(expectedValuesPath) as origExpectedValuesJson: origExpectedValues = json.load(origExpectedValuesJson) for tankValues in origExpectedValues['data']: idNum = int(tankValues.pop('IDNum')) self.expectedValues[idNum] = {} for key in ['expDamage', 'expFrag', 'expSpot', 'expDef', 'expWinRate']: self.expectedValues[idNum][key] = float(tankValues[key]) expectedKTTCValuesPath = '/'.join([self.path, 'data', 'expected_kttc_tank_values.json']) with open(expectedKTTCValuesPath) as origExpectedKTTCValuesJson: origExpectedKTTCValues = json.load(origExpectedKTTCValuesJson) for tankValues in origExpectedKTTCValues['data']: idNum = int(tankValues.pop('IDNum')) self.expectedKTTCValues[idNum] = {} for key in ['expDamage', 'expFrag', 'expSpot', 'expDef', 'expWinRate']: self.expectedKTTCValues[idNum][key] = float(tankValues[key]) xvmScalesPath = '/'.join([self.path, 'data', 'xvmscales.json']) if self.config.get('onlineUpdateData', True): xvmScalesURL = 'https://static.modxvm.com/xvmscales.json' try: urllib.urlretrieve(xvmScalesURL, xvmScalesPath) except: pass with open(xvmScalesPath) as origXVMScaleJson: origXVMScale = json.load(origXVMScaleJson) for key in ['xeff', 'xwn8']: self.xvmscales[key] = origXVMScale[key] self.updateMessage() def readConfig(self): with codecs.open('/'.join([self.path, 'config.json']), 'r', 'utf-8-sig') as configFileJson: try: self.config = json.load(configFileJson) self.battleStatPatterns = [] for pattern in self.config.get('battleStatPatterns', []): try: condition = pattern.get('if', 'True') condition = re.sub('{{(\\w+)}}', "values['\\1']", condition) except: print '[wotstat] Invalid condition ' + pattern.get('if', '') continue try: compiled = re.compile(pattern.get('pattern', '')) self.battleStatPatterns.append({'condition': condition, 'pattern': compiled, 'repl': pattern.get('repl', '')}) except: print '[wotstat] Invalid pattern ' + pattern.get('pattern', '') continue self.configIsValid = True except: print '[wotstat] load stat_config.json has failed' self.config = {} self.configIsValid = False def getWorkDate(self): return datetime.date.today().strftime('%Y-%m-%d') if datetime.datetime.now().hour >= self.config.get('dailyAutoResetHour', 4) else (datetime.date.today() - datetime.timedelta(days=1)).strftime('%Y-%m-%d') def save(self): statCache = open(self.statCacheFilePath, 'w') self.cache['version'] = self.cacheVersion self.cache['date'] = self.startDate if not self.cache.has_key('players'): self.cache['players'] = {} if not self.cache['players'].has_key(self.playerName): self.cache['players'][self.playerName] = {} self.cache['players'][self.playerName]['battles'] = self.battles statCache.write(json.dumps(self.cache, sort_keys=True, indent=4, separators=(',', ': '))) statCache.close() def createMessage(self): messages = {GENERAL: self.messageGeneral, BY_TANK_1: self.messageByTank, BY_TANK_2: self.messageByTank, BY_TANK_3: self.messageByTank, BY_TANK_4: self.messageByTank, BY_TANK_5: self.messageByTank, BY_TANK_6: self.messageByTank, BY_TANK_7: self.messageByTank, BY_TANK_8: self.messageByTank, BY_TANK_9: self.messageByTank, BY_TANK_10: self.messageByTank, BY_MAP_1: self.messageByMap, BY_MAP_2: self.messageByMap, BY_MAP_3: self.messageByMap, BY_MAP_4: self.messageByMap, BY_MAP_5: self.messageByMap, RESET: self.messageReset} msg = messages[self.page] message = {'typeID': 1, 'message': {'bgIcon': self.bgIcon, 'defaultIcon': '', 'savedData': 0, 'timestamp': -1, 'filters': [], 'buttonsLayout': [], 'message': msg, 'type': 'cancel', 'icon': self.config.get('icon', '../maps/icons/library/BattleResultIcon-1.png')}, 'entityID': 99999, 'auxData': ['GameGreeting']} return message def battleResultsCallback(self, arenaUniqueID, responseCode, value=None, revision=0): if responseCode == AccountCommands.RES_NON_PLAYER or responseCode == AccountCommands.RES_COOLDOWN: BigWorld.callback(1.0, lambda : self.queue.put(arenaUniqueID)) self.battleResultsBusy.release() return elif responseCode < 0: self.battleResultsBusy.release() return else: arenaTypeID = value['common']['arenaTypeID'] arenaType = ArenaType.g_cache[arenaTypeID] personal = value['personal'].itervalues().next() vehicleCompDesc = personal['typeCompDescr'] arenaName = i18n.makeString(arenaType.name) vt = vehiclesWG.getVehicleType(vehicleCompDesc) countryID = vehicleCompDesc >> 4 & 15 result = 1 if int(personal['team']) == int(value['common']['winnerTeam']) else (0 if not int(value['common']['winnerTeam']) else -1) death = 1 if int(personal['deathReason']) > -1 else 0 if death == 0: survive = str(self.config.get('textSurvived', '')) else: survive = str(self.config.get('textDestroyed', '')) place = 1 arenaUniqueID = value['arenaUniqueID'] self.arenaUniqueID = value['arenaUniqueID'] squadsTier = {} vehicles = value['vehicles'] for vehicle in vehicles.values(): pTypeCompDescr = vehicle[0]['typeCompDescr'] if pTypeCompDescr is not None: pvt = vehiclesWG.getVehicleType(pTypeCompDescr) tier = pvt.level if set(vehiclesWG.VEHICLE_CLASS_TAGS.intersection(pvt.tags)).pop() == 'lightTank' and tier > 5: tier += 1 try: squadId = value['players'][vehicle[0]['accountDBID']]['prebattleID'] except: squadID = 0 squadsTier[squadId] = max(squadsTier.get(squadId, 0), tier) if personal['team'] == vehicle[0]['team'] and personal['originalXP'] < vehicle[0]['xp']: place += 1 battleTier = max(squadsTier.values()) proceeds = personal['credits'] - personal['autoRepairCost'] - personal['autoEquipCost'][0] - personal['autoLoadCost'][0] tmenXP = personal['tmenXP'] if 'premium' in vt.tags: tmenXP = int(1.5 * tmenXP) battle = {'idNum': vehicleCompDesc, 'arenaTypeID': arenaTypeID, 'map': arenaType.geometryName, 'vehicle': vt.name.replace(':', '-'), 'tier': vt.level, 'result': result, 'dailyXPFactor': personal['dailyXPFactor10'] / 10, 'damage': personal['damageDealt'], 'damageRec': personal['damageReceived'], 'potDamageRec': personal['potentialDamageReceived'], 'damageBlocked': personal['damageBlockedByArmor'], 'death': death, 'frag': personal['kills'], 'spot': personal['spotted'], 'def': personal['droppedCapturePoints'], 'cap': personal['capturePoints'], 'shots': personal['shots'], 'hits': personal['directHits'], 'pierced': personal['piercings'], 'xp': personal['xp'], 'originalXP': personal['originalXP'], 'freeXP': personal['freeXP'], 'place': place, 'autoRepairCost': personal['autoRepairCost'], 'autoLoadCost': personal['autoLoadCost'][0], 'autoEquipCost': personal['autoEquipCost'][0], 'autoServiceCost': personal['autoEquipCost'][0] + personal['autoLoadCost'][0] + personal['autoRepairCost'], 'grossCredits': personal['credits'], 'netCredits': proceeds, 'bonds': personal['crystal'], 'gold': personal['gold'] - personal['autoEquipCost'][1] - personal['autoLoadCost'][1], 'battleTier': battleTier, 'assist': personal['damageAssistedRadio'] + personal['damageAssistedTrack'], 'assistRadio': personal['damageAssistedRadio'], 'assistTrack': personal['damageAssistedTrack']} extended = {'vehicle-raw': battle['vehicle'], 'vehicle-short': vt.shortUserString, 'vehicle-long': vt.userString, 'vehicle-country': nations.NAMES[countryID], 'map-raw': battle['map'], 'map': arenaName, 'result': result, 'survive': survive, 'place': battle['place'], 'dailyXPFactor': battle['dailyXPFactor'], 'tmenXP': tmenXP} if self.config.get('dailyAutoReset', True) and self.startDate != stat.getWorkDate(): self.reset() if value['common']['bonusType'] not in self.config.get('ignoreBattleType', []): self.battles.append(battle) self.save() self.updateMessage() battleStat, gradient, palette = self.calcWN8([battle]) extGradient, extPalette = self.refreshColorMacros(extended) gradient.update(extGradient) palette.update(extPalette) self.battleStats[arenaUniqueID] = {} self.battleStats[arenaUniqueID]['values'] = battleStat self.battleStats[arenaUniqueID]['extendedValues'] = extended self.battleStats[arenaUniqueID]['gradient'] = gradient self.battleStats[arenaUniqueID]['palette'] = palette self.battleResultsBusy.release() return def reset(self): self.page = GENERAL self.startDate = self.getWorkDate() self.battles = [] self.save() self.updateMessage() def mainLoop(self): while True: arenaUniqueID = self.queue.get() self.battleResultsAvailable.wait() self.battleResultsBusy.acquire() BigWorld.player().battleResultsCache.get(arenaUniqueID, lambda resID, value: self.battleResultsCallback(arenaUniqueID, resID, value, None)) def refreshColorMacros(self, values): gradient = {} palette = {} if values.get('battlesCount', 1) == 0: for key in values.keys(): gradient[key] = '#FFFFFF' palette[key] = '#FFFFFF' return (gradient, palette) for key in values.keys(): if self.config.get('gradient', {}).has_key(key): colors = self.config.get('gradient', {})[key] if values[key] <= colors[0]['value']: gradient[key] = colors[0]['color'] elif values[key] >= colors[-1]['value']: gradient[key] = colors[-1]['color'] else: sVal = colors[0]['value'] eVal = colors[1]['value'] i = 1 while eVal < values[key]: sVal = colors[i]['value'] i += 1 eVal = colors[i]['value'] val = float(values[key] - sVal) / (eVal - sVal) gradient[key] = gradColor(colors[i - 1]['color'], colors[i]['color'], val) else: gradient[key] = '#FFFFFF' if self.config.get('palette', {}).has_key(key): colors = self.config.get('palette', {})[key] palette[key] = colors[-1]['color'] for item in reversed(colors): if values[key] < item['value']: palette[key] = item['color'] break palette[key] = '#FFFFFF' return (gradient, palette) def calcExpected(self, newIdNum): v = vehiclesWG.getVehicleType(newIdNum) newTier = v.level newType = set(vehiclesWG.VEHICLE_CLASS_TAGS.intersection(v.tags)).pop() if newTier < 1 or newTier > 10: newTier = 10 tierExpected = {} tierExpectedCount = 0.0 typeExpected = {} typeExpectedCount = 0.0 for idNum in self.expectedValues: try: vt = vehiclesWG.getVehicleType(idNum) except: continue if vt.level == newTier: tierExpectedCount += 1 vType = set(vehiclesWG.VEHICLE_CLASS_TAGS.intersection(vt.tags)).pop() if vType == newType: typeExpectedCount += 1 for key in self.expectedValues[idNum]: tierExpected[key] = tierExpected.get(key, 0) + self.expectedValues[idNum].get(key, 0.0) if vType == newType: typeExpected[key] = typeExpected.get(key, 0) + self.expectedValues[idNum].get(key, 0.0) if typeExpectedCount > 0: for key in typeExpected: typeExpected[key] /= typeExpectedCount self.expectedValues[newIdNum] = typeExpected.copy() return for key in tierExpected: tierExpected[key] /= tierExpectedCount self.expectedValues[newIdNum] = tierExpected.copy() def calcExpectedKTTC(self, newIdNum): v = vehiclesWG.getVehicleType(newIdNum) newTier = v.level newType = set(vehiclesWG.VEHICLE_CLASS_TAGS.intersection(v.tags)).pop() if newTier < 1 or newTier > 10: newTier = 10 tierExpected = {} tierExpectedCount = 0.0 typeExpected = {} typeExpectedCount = 0.0 for idNum in self.expectedKTTCValues: try: vt = vehiclesWG.getVehicleType(idNum) except: continue if vt.level == newTier: tierExpectedCount += 1 vType = set(vehiclesWG.VEHICLE_CLASS_TAGS.intersection(vt.tags)).pop() if vType == newType: typeExpectedCount += 1 for key in self.expectedKTTCValues[idNum]: tierExpected[key] = tierExpected.get(key, 0) + self.expectedKTTCValues[idNum].get(key, 0.0) if vType == newType: typeExpected[key] = typeExpected.get(key, 0) + self.expectedKTTCValues[idNum].get(key, 0.0) if typeExpectedCount > 0: for key in typeExpected: typeExpected[key] /= typeExpectedCount self.expectedKTTCValues[newIdNum] = typeExpected.copy() return for key in tierExpected: tierExpected[key] /= tierExpectedCount self.expectedKTTCValues[newIdNum] = tierExpected.copy() def calcWN8(self, battles): values = {} values['battlesCount'] = len(battles) totalTier = 0 totalPlace = 0 places = [] totalBattleTier = 0 valuesKeys = ['winsCount', 'defeatsCount', 'drawsCount', 'totalDmg', 'totalDmgRec', 'totalPotDmgRec', 'totalDamageBlocked', 'totalDeathsCount', 'totalSurvivesCount', 'totalFrag', 'totalSpot', 'totalDef', 'totalCap', 'totalShots', 'totalHits', 'totalPierced', 'totalAssist', 'totalXP', 'totalOriginalXP', 'totalFreeXP', 'autoRepairCost', 'autoLoadCost', 'autoEquipCost', 'autoServiceCost', 'grossCredits', 'netCredits', 'bonds', 'gold', 'totalAssistRadio', 'totalAssistTrack'] for key in valuesKeys: values[key] = 0 expKeys = ['expDamage', 'expFrag', 'expSpot', 'expDef', 'expWinRate'] expKTTCKeys = ['expKTTCDamage', 'expKTTCFrag', 'expKTTCSpot', 'expKTTCDef', 'expKTTCWinRate'] expValues = {} for key in expKeys: expValues['total_' + key] = 0.0 expKTTCValues = {} for key in expKTTCKeys: expKTTCValues['total_' + key] = 0.0 resCounters = {-1: 'defeatsCount', 0: 'drawsCount', 1: 'winsCount'} for battle in battles: values[resCounters[battle['result']]] += 1 values['winsToBattles'] = str(values['winsCount']) + '/' + str(values['battlesCount']) values['totalDmg'] += battle['damage'] values['totalDmgRec'] += battle['damageRec'] values['totalPotDmgRec'] += battle['potDamageRec'] values['totalDamageBlocked'] += battle['damageBlocked'] values['totalDeathsCount'] += battle['death'] values['totalSurvivesCount'] = values['battlesCount'] - values['totalDeathsCount'] values['totalFrag'] += battle['frag'] values['totalSpot'] += battle['spot'] values['totalDef'] += battle['def'] values['totalCap'] += battle['cap'] values['totalShots'] += battle['shots'] values['totalHits'] += battle['hits'] values['totalPierced'] += battle['pierced'] values['totalAssist'] += battle['assist'] values['totalAssistRadio'] += battle['assistRadio'] values['totalAssistTrack'] += battle['assistTrack'] values['totalXP'] += battle['xp'] values['totalOriginalXP'] += battle['originalXP'] values['totalFreeXP'] += battle['freeXP'] values['autoRepairCost'] += battle['autoRepairCost'] values['autoLoadCost'] += battle['autoLoadCost'] values['autoEquipCost'] += battle['autoEquipCost'] values['autoServiceCost'] += battle['autoServiceCost'] values['grossCredits'] += battle['grossCredits'] values['netCredits'] += battle['netCredits'] values['bonds'] += battle['bonds'] values['gold'] += battle['gold'] totalTier += battle['tier'] totalBattleTier += battle['battleTier'] totalPlace += battle['place'] places.append(battle['place']) idNum = battle['idNum'] if not self.expectedValues.has_key(idNum): self.calcExpected(idNum) expValues['total_expDamage'] += self.expectedValues[idNum]['expDamage'] expValues['total_expFrag'] += self.expectedValues[idNum]['expFrag'] expValues['total_expSpot'] += self.expectedValues[idNum]['expSpot'] expValues['total_expDef'] += self.expectedValues[idNum]['expDef'] expValues['total_expWinRate'] += self.expectedValues[idNum]['expWinRate'] if not self.expectedKTTCValues.has_key(idNum): self.calcExpectedKTTC(idNum) expKTTCValues['total_expKTTCDamage'] += self.expectedKTTCValues[idNum]['expDamage'] expKTTCValues['total_expKTTCFrag'] += self.expectedKTTCValues[idNum]['expFrag'] expKTTCValues['total_expKTTCSpot'] += self.expectedKTTCValues[idNum]['expSpot'] expKTTCValues['total_expKTTCDef'] += self.expectedKTTCValues[idNum]['expDef'] expKTTCValues['total_expKTTCWinRate'] += self.expectedKTTCValues[idNum]['expWinRate'] if values['battlesCount'] > 0: values['winRate'] = float(values['winsCount']) / values['battlesCount'] * 100 values['avgDamage'] = float(values['totalDmg']) / values['battlesCount'] values['avgDamageRec'] = int(values['totalDmgRec'] / values['battlesCount']) values['avgPotDmgRec'] = int(values['totalPotDmgRec'] / values['battlesCount']) values['avgDamageBlocked'] = int(values['totalDamageBlocked'] / values['battlesCount']) if values['totalDmgRec'] == 0: if values['totalDmg'] == 0: values['dmgDltRecRatio'] = 1 else: values['dmgDltRecRatio'] = min(1000, values['totalDmg']) else: values['dmgDltRecRatio'] = float(values['totalDmg']) / float(values['totalDmgRec']) values['deathsRate'] = 0 if values['totalDeathsCount'] < 1 else float(values['totalDeathsCount']) / values['battlesCount'] * 100 values['survivalRate'] = 100 if values['totalDeathsCount'] < 1 else abs(float(values['totalDeathsCount']) / values['battlesCount'] * 100 - 100) values['avgFrag'] = float(values['totalFrag']) / values['battlesCount'] values['avgSpot'] = float(values['totalSpot']) / values['battlesCount'] values['avgDef'] = float(values['totalDef']) / values['battlesCount'] values['avgCap'] = float(values['totalCap']) / values['battlesCount'] values['avgHitsRate'] = float(values['totalHits']) / max(1, values['totalShots']) * 100 values['avgEffHitsRate'] = float(values['totalPierced']) / max(1, values['totalHits']) * 100 values['avgAssist'] = int(values['totalAssist']) / values['battlesCount'] values['avgAssistRadio'] = int(values['totalAssistRadio']) / values['battlesCount'] values['avgAssistTrack'] = int(values['totalAssistTrack']) / values['battlesCount'] values['avgXP'] = int(values['totalXP'] / values['battlesCount']) values['avgOriginalXP'] = int(values['totalOriginalXP'] / values['battlesCount']) values['avgFreeXP'] = int(values['totalFreeXP'] / values['battlesCount']) values['avgPremXP'] = int(1.5 * values['avgOriginalXP']) values['avgGrossCredits'] = int(values['grossCredits'] / values['battlesCount']) values['avgNetCredits'] = int(values['netCredits'] / values['battlesCount']) values['avgBonds'] = int(values['bonds'] / values['battlesCount']) values['avgAutoServiceCost'] = int(values['autoServiceCost'] / values['battlesCount']) values['avgAutoRepairCost'] = int(values['autoRepairCost'] / values['battlesCount']) values['avgAutoLoadCost'] = int(values['autoLoadCost'] / values['battlesCount']) values['avgAutoEquipCost'] = int(values['autoEquipCost'] / values['battlesCount']) values['avgTier'] = float(totalTier) / values['battlesCount'] values['avgBattleTier'] = float(totalBattleTier) / values['battlesCount'] values['avgPlace'] = round(float(totalPlace) / values['battlesCount'], 1) places = sorted(places) length = len(places) values['medPlace'] = (places[length / 2] + places[length / 2 - 1]) / 2.0 if not length % 2 else float(places[length / 2]) for key in expKeys: values[key] = expValues['total_' + key] / values['battlesCount'] for key in expKTTCKeys: values[key] = expKTTCValues['total_' + key] / values['battlesCount'] values['EFF'] = max(0, int(values['avgDamage'] * (10 / (values['avgTier'] + 2)) * (0.23 + 2 * values['avgTier'] / 100) + values['avgFrag'] * 250 + values['avgSpot'] * 150 + math.log(values['avgCap'] + 1, 1.732) * 150 + values['avgDef'] * 150)) xeffScale = self.xvmscales.get('xeff', None) values['XEFF'] = next((i for i, v in enumerate(xeffScale) if v > values['EFF']), 100) values['BR'] = max(0, int(values['avgDamage'] * (0.2 + 1.5 / values['avgTier']) + values['avgFrag'] * (350 - values['avgTier'] * 20) + values['avgAssistRadio'] / 2 * (0.2 + 1.5 / values['avgTier']) + values['avgAssistTrack'] / 2 * (0.2 + 1.5 / values['avgTier']) + values['avgSpot'] * 200 + values['avgCap'] * 15 + values['avgDef'] * 15)) values['WN6'] = max(0, int((1240 - 1040 / min(values['avgTier'], 6) ** 0.164) * values['avgFrag'] + values['avgDamage'] * 530 / (184 * math.exp(0.24 * values['avgTier']) + 130) + values['avgSpot'] * 125 + min(values['avgDef'], 2.2) * 100 + (185 / (0.17 + math.exp((values['winRate'] - 35) * -0.134)) - 500) * 0.45 + (6 - min(values['avgTier'], 6)) * -60)) values['XWN6'] = 100 if values['WN6'] > 2350 else int(round(max(0, min(100, values['WN6'] * (values['WN6'] * (values['WN6'] * (values['WN6'] * (values['WN6'] * (-values['WN6'] * 8.52e-19 + 8.649e-15) - 3.9744e-11) + 8.406e-08) - 7.446e-05) + 0.06904) - 6.19)))) values['WN7'] = max(0, int((1240 - 1040 / min(values['avgTier'], 6) ** 0.164) * values['avgFrag'] + values['avgDamage'] * 530 / (184 * math.exp(0.24 * values['avgTier']) + 130) + values['avgSpot'] * 125 * min(values['avgTier'], 3) / 3 + min(values['avgDef'], 2.2) * 100 + (185 / (0.17 + math.exp((values['winRate'] - 35) * -0.134)) - 500) * 0.45 - (5 - min(values['avgTier'], 5)) * 125 / (1 + math.exp((values['avgTier'] - (values['battlesCount'] / 220) ** (3 / values['avgTier'])) * 1.5)))) values['XWN7'] = 100 if values['WN7'] > 2350 else int(round(max(0, min(100, values['WN7'] * (values['WN7'] * (values['WN7'] * (values['WN7'] * (values['WN7'] * (values['WN7'] * 1.641e-18 - 1.26e-14) + 3.223e-11) - 3.793e-08) + 3.139e-05) + 0.02747) - 1.92)))) else: for key in ['winRate', 'avgDamage', 'avgDamageRec', 'avgPotDmgRec', 'avgDamageBlocked', 'dmgDltRecRatio', 'deathsRate', 'survivalRate', 'avgFrag', 'avgSpot', 'avgDef', 'avgCap', 'avgHitsRate', 'avgEffHitsRate', 'avgAssist', 'avgXP', 'avgOriginalXP', 'avgFreeXP', 'avgPremXP', 'avgGrossCredits', 'avgNetCredits', 'avgBonds', 'avgAutoServiceCost', 'avgAutoRepairCost', 'avgAutoLoadCost', 'avgAutoEquipCost', 'avgTier', 'avgBattleTier', 'avgPlace', 'medPlace', 'WN6', 'XWN6', 'EFF', 'XEFF', 'BR', 'WN7', 'XWN7']: values[key] = 0 for key in expKeys: values[key] = 1 for key in expKTTCKeys: values[key] = 1 values['rDAMAGE'] = values['avgDamage'] / values['expDamage'] values['rSPOT'] = values['avgSpot'] / values['expSpot'] values['rFRAG'] = values['avgFrag'] / values['expFrag'] values['rDEF'] = values['avgDef'] / values['expDef'] values['rWIN'] = values['winRate'] / values['expWinRate'] values['rWINc'] = max(0, (values['rWIN'] - 0.71) / 0.29000000000000004) values['rDAMAGEc'] = max(0, (values['rDAMAGE'] - 0.22) / 0.78) values['rFRAGc'] = max(0, min(values['rDAMAGEc'] + 0.2, (values['rFRAG'] - 0.12) / 0.88)) values['rSPOTc'] = max(0, min(values['rDAMAGEc'] + 0.1, (values['rSPOT'] - 0.38) / 0.62)) values['rDEFc'] = max(0, min(values['rDAMAGEc'] + 0.1, (values['rDEF'] - 0.1) / 0.9)) values['WN8'] = 980 * values['rDAMAGEc'] + 210 * values['rDAMAGEc'] * values['rFRAGc'] + 155 * values['rFRAGc'] * values['rSPOTc'] + 75 * values['rDEFc'] * values['rFRAGc'] + 145 * min(1.8, values['rWINc']) xwn8Scale = self.xvmscales.get('xwn8', None) values['XWN8'] = next((i for i, v in enumerate(xwn8Scale) if v > values['WN8']), 100) values['rKTTCDAMAGE'] = values['avgDamage'] / values['expKTTCDamage'] values['rKTTCSPOT'] = values['avgSpot'] / values['expKTTCSpot'] values['rKTTCFRAG'] = values['avgFrag'] / values['expKTTCFrag'] values['rKTTCDEF'] = values['avgDef'] / values['expKTTCDef'] values['rKTTCWIN'] = values['winRate'] / values['expKTTCWinRate'] values['rKTTCWINc'] = max(0, (values['rKTTCWIN'] - 0.71) / 0.29000000000000004) values['rKTTCDAMAGEc'] = max(0, (values['rKTTCDAMAGE'] - 0.22) / 0.78) values['rKTTCFRAGc'] = max(0, min(values['rKTTCDAMAGEc'] + 0.2, (values['rKTTCFRAG'] - 0.12) / 0.88)) values['rKTTCSPOTc'] = max(0, min(values['rKTTCDAMAGEc'] + 0.1, (values['rKTTCSPOT'] - 0.38) / 0.62)) values['rKTTCDEFc'] = max(0, min(values['rKTTCDAMAGEc'] + 0.1, (values['rKTTCDEF'] - 0.1) / 0.9)) values['WN8KTTC'] = 980 * values['rKTTCDAMAGEc'] + 210 * values['rKTTCDAMAGEc'] * values['rKTTCFRAGc'] + 155 * values['rKTTCFRAGc'] * values['rKTTCSPOTc'] + 75 * values['rKTTCDEFc'] * values['rKTTCFRAGc'] + 145 * min(1.8, values['rKTTCWINc']) values['XWN8KTTC'] = next((i for i, v in enumerate(xwn8Scale) if v > values['WN8KTTC']), 100) xtosup = ['1.2', '1.5', '1.9', '2.5', '3.1', '3.8', '4.6', '5.5', '6.6', '7.7', '9.0', '10', '12', '14', '15', '17', '19', '21', '24', '26', '28', '31', '33', '36', '38', '41', '43', '46', '48', '51', '53', '56', '58', '60', '63', '65', '67', '69', '71', '73', '74', '76', '78', '79', '80.8', '82.2', '83.6', '84.8', '86.0', '87.1', '88.1', '89.0', '89.9', '90.8', '91.6', '92.3', '92.9', '93.6', '94.1', '94.7', '95.1', '95.6', '96.0', '96.4', '96.7', '97.0', '97.3', '97.6', '97.8', '98.0', '98.2', '98.4', '98.6', '98.7', '98.9', '99.0', '99.1', '99.2', '99.3', '99.37', '99.44', '99.51', '99.57', '99.62', '99.67', '99.71', '99.75', '99.78', '99.81', '99.84', '99.86', '99.88', '99.90', '99.92', '99.93', '99.95', '99.96', '99.97', '99.98', '99.99'] values['SUP'] = xtosup[max(0, min(100, values['XWN8'] - 1))] values['avgBattleTierDiff'] = values['avgBattleTier'] - values['avgTier'] values['WN8'] = int(round(values['WN8'])) values['WN8KTTC'] = int(round(values['WN8KTTC'])) values['avgDamage'] = int(values['avgDamage']) gradient, palette = self.refreshColorMacros(values) return (values, gradient, palette) def formatMacros(self, val, width=1, prec=2, sign=''): if type(val) == str: sStr = '{:>{w}}'.format(val, w=width) return sStr if sign != '+': sVal = '{:>{w},.{pr}f}'.format(val, w=width, pr=prec) if type(val) is float else '{:>{w},d}'.format(int(round(val)), w=width) else: sVal = '{:>+{w},.{pr}f}'.format(val, w=width, pr=prec) if type(val) is float else '{:>+{w},d}'.format(int(round(val)), w=width) separator = self.config.get('thousandSeparator', ' ') sVal = sVal.replace(',', separator) return sVal def applyMacros(self, text, values, gradient, palette): for key in values.keys(): text = text.replace('{{%s}}' % key, self.formatMacros(values[key])) text = text.replace('{{%s:d}}' % key, self.formatMacros(values[key], 1, 0)) text = text.replace('{{%s:+d}}' % key, self.formatMacros(values[key], 1, 0, '+')) for xx in xrange(1, 21): text = text.replace('{{%s:%d}}' % (key, xx), self.formatMacros(values[key], xx, 0)) text = text.replace('{{%s:+%d}}' % (key, xx), self.formatMacros(values[key], xx, 0, '+')) text = text.replace('{{%s:%d.1f}}' % (key, xx), self.formatMacros(values[key], xx, 1)) text = text.replace('{{%s:+%d.1f}}' % (key, xx), self.formatMacros(values[key], xx, 1, '+')) text = text.replace('{{%s:%d.2f}}' % (key, xx), self.formatMacros(values[key], xx, 2)) text = text.replace('{{%s:+%d.2f}}' % (key, xx), self.formatMacros(values[key], xx, 2, '+')) text = text.replace('{{g:%s}}' % key, gradient[key]) text = text.replace('{{c:%s}}' % key, palette[key]) return text def applyUserMacros(self, text): """Applying User Macros""" userMacros = self.config.get('userMacros', {}) for key in userMacros.keys(): text = text.replace('{{%s}}' % key, userMacros[key]) return text def formatButtons(self, msg, msgPage=''): if msgPage == 'Tanks': msg = msg.replace('{{ButtonGeneral}}', self.config['Button']['General']['format'] if self.config['Button']['General']['enable'] else '') msg = msg.replace('{{ButtonTanks}}', self.config['ButtonON']['Tanks'] if self.config['Button']['Tanks']['enable'] else '') msg = msg.replace('{{ButtonMaps}}', self.config['Button']['Maps']['format'] if self.config['enableStatisticsByMap'] and self.config['Button']['Maps']['enable'] else '') msg = msg.replace('{{ButtonReset}}', self.config['Button']['Reset']['format'] if self.config['Button']['Reset']['enable'] else '') msg = msg.replace('{{ButtonTankSortByMacro1}}', self.config['Button']['TankSortByMacro1']['format']) msg = msg.replace('{{ButtonTankSortByMacro2}}', self.config['Button']['TankSortByMacro2']['format']) msg = msg.replace('{{ButtonTankSortByMacro3}}', self.config['Button']['TankSortByMacro3']['format']) msg = msg.replace('{{ButtonTankSortByMacro4}}', self.config['Button']['TankSortByMacro4']['format']) msg = msg.replace('{{ButtonTankSortByMacro5}}', self.config['Button']['TankSortByMacro5']['format']) msg = msg.replace('{{ButtonTankSortByMacro6}}', self.config['Button']['TankSortByMacro6']['format']) msg = msg.replace('{{ButtonTankSortByMacro7}}', self.config['Button']['TankSortByMacro7']['format']) msg = msg.replace('{{ButtonTankSortByMacro8}}', self.config['Button']['TankSortByMacro8']['format']) msg = msg.replace('{{ButtonTankSortByMacro9}}', self.config['Button']['TankSortByMacro9']['format']) msg = msg.replace('{{ButtonTankSortByMacro10}}', self.config['Button']['TankSortByMacro10']['format']) elif msgPage == 'Maps': msg = msg.replace('{{ButtonGeneral}}', self.config['Button']['General']['format'] if self.config['Button']['General']['enable'] else '') msg = msg.replace('{{ButtonTanks}}', self.config['Button']['Tanks']['format'] if self.config['enableStatisticsByTank'] and self.config['Button']['Tanks']['enable'] else '') msg = msg.replace('{{ButtonMaps}}', self.config['ButtonON']['Maps'] if self.config['Button']['Maps']['enable'] else '') msg = msg.replace('{{ButtonReset}}', self.config['Button']['Reset']['format'] if self.config['Button']['Reset']['enable'] else '') msg = msg.replace('{{ButtonMapSortByMacro1}}', self.config['Button']['MapSortByMacro1']['format']) msg = msg.replace('{{ButtonMapSortByMacro2}}', self.config['Button']['MapSortByMacro2']['format']) msg = msg.replace('{{ButtonMapSortByMacro3}}', self.config['Button']['MapSortByMacro3']['format']) msg = msg.replace('{{ButtonMapSortByMacro4}}', self.config['Button']['MapSortByMacro4']['format']) msg = msg.replace('{{ButtonMapSortByMacro5}}', self.config['Button']['MapSortByMacro5']['format']) elif msgPage == 'Reset': msg = msg.replace('{{ButtonResetYes}}', self.config['Button']['ResetYes']['format']) msg = msg.replace('{{ButtonResetNo}}', self.config['Button']['ResetNo']['format']) else: msg = msg.replace('{{ButtonGeneral}}', self.config['ButtonON']['General'] if self.config['Button']['General']['enable'] and (self.config['enableStatisticsByTank'] or self.config['enableStatisticsByMap']) else '') msg = msg.replace('{{ButtonTanks}}', self.config['Button']['Tanks']['format'] if self.config['enableStatisticsByTank'] and self.config['Button']['Tanks']['enable'] else '') msg = msg.replace('{{ButtonMaps}}', self.config['Button']['Maps']['format'] if self.config['enableStatisticsByMap'] and self.config['Button']['Maps']['enable'] else '') msg = msg.replace('{{ButtonReset}}', self.config['Button']['Reset']['format'] if self.config['Button']['Reset']['enable'] else '') return msg def updateMessage(self): if not self.configIsValid: self.message = 'stat_config.json is not valid' return defaultTankSortingMacros = ({'tankSortingMacro1': 'battlesCount', 'tankSortingMacro2': 'WN8', 'tankSortingMacro3': 'winRate', 'tankSortingMacro4': 'netCredits', 'tankSortingMacro5': 'vehicle-short', 'tankSortingMacro6': 'avgDamage', 'tankSortingMacro7': 'avgFrag', 'tankSortingMacro8': 'totalDmg', 'tankSortingMacro9': 'totalFrag', 'tankSortingMacro10': 'totalXP'},) defaultMapSortingMacros = ({'mapSortingMacro1': 'map', 'mapSortingMacro2': 'winRate', 'mapSortingMacro3': 'WN8', 'mapSortingMacro4': 'battlesCount', 'mapSortingMacro5': 'netCredits'},) self.tankSortingMacros = self.config.get('tankSortingMacros', defaultTankSortingMacros) self.mapSortingMacros = self.config.get('mapSortingMacros', defaultMapSortingMacros) self.values, self.gradient, self.palette = self.calcWN8(self.battles) bg = self.config.get('bgIcon', '') self.bgIcon = self.applyMacros(bg, self.values, self.gradient, self.palette) if len(self.battles) < 1 and self.config.get('info', True): msg = '\n'.join(self.config.get('text', '')) else: msg = '\n'.join(self.config.get('template', '')) msg = self.applyUserMacros(msg) msg = self.applyMacros(msg, self.values, self.gradient, self.palette) msg = self.formatButtons(msg) self.messageGeneral = msg self.updateMessageTanks(self.tankSortingMacros['tankSortingMacro1']) self.updateMessageMaps(self.mapSortingMacros['mapSortingMacro1']) def updateMessageTanks(self, tankSortingMacro): """Statistics massage 'By Tank'.""" if self.config['enableStatisticsByTank']: msgPage = 'Tanks' rows = '' tankStat = {} for battle in self.battles: idNum = battle['idNum'] if tankStat.has_key(idNum): tankStat[idNum].append(battle) tankStat[idNum] = [battle] tankValues = {} tankGradient = {} tankPalette = {} tankSortReverse = self.config.get('tankSortReverse', True) for idNum in tankStat.keys(): values, gradient, palette = self.calcWN8(tankStat[idNum]) tankValues[idNum] = values tankGradient[idNum] = gradient tankPalette[idNum] = palette sortedTankIDs = [] if tankSortingMacro == 'vehicle-short': idTankNames = {} for idNum in tankStat.keys(): vt = vehiclesWG.getVehicleType(idNum) idTankNames[idNum] = vt.userString sortedTankIDs = sorted(idTankNames.keys(), key=lambda value: idTankNames[value]) else: sortedTankIDs = sorted(tankValues.keys(), key=lambda value: tankValues[value][tankSortingMacro], reverse=tankSortReverse) for idNum in sortedTankIDs: row = '\n'.join(self.config.get('ByTankRows', '')) row = self.applyUserMacros(row) vt = vehiclesWG.getVehicleType(idNum) countryID = idNum >> 4 & 15 row = row.replace('{{vehicle-long}}', vt.userString) row = row.replace('{{vehicle-short}}', vt.shortUserString) row = row.replace('{{vehicle-raw}}', vt.name.replace(':', '-')) row = row.replace('{{vehicle-country}}', str(nations.NAMES[countryID])) row = self.applyMacros(row, tankValues[idNum], tankGradient[idNum], tankPalette[idNum]) rows += row + '\n' msg = '\n'.join(self.config.get('byTankTemplate', '')) msg = msg.replace('{{ByTankRows}}', rows) msg = self.formatButtons(msg, msgPage) self.messageByTank = msg def updateMessageMaps(self, mapSortingMacro): """Statistics massage 'By Map'.""" if self.config['enableStatisticsByMap']: msgPage = 'Maps' rows = '' mapStat = {} for battle in self.battles: mapID = battle['arenaTypeID'] & 32767 if mapStat.has_key(mapID): mapStat[mapID].append(battle) mapStat[mapID] = [battle] mapValues = {} mapGradient = {} mapPalette = {} mapSortReverse = self.config.get('mapSortReverse', True) for mapID in mapStat.keys(): values, gradient, palette = self.calcWN8(mapStat[mapID]) mapValues[mapID] = values mapGradient[mapID] = gradient mapPalette[mapID] = palette sortedMapIDs = [] if mapSortingMacro == 'map': idMapNames = {} for mapID in mapStat.keys(): arenaTypeID = mapStat[mapID][0]['arenaTypeID'] arenaType = ArenaType.g_cache[arenaTypeID] arenaName = i18n.makeString(arenaType.name) idMapNames[mapID] = arenaName sortedMapIDs = sorted(idMapNames.keys(), key=lambda value: idMapNames[value]) else: sortedMapIDs = sorted(mapValues.keys(), key=lambda value: mapValues[value][mapSortingMacro], reverse=mapSortReverse) for mapID in sortedMapIDs: row = '\n'.join(self.config.get('ByMapRows', '')) row = self.applyUserMacros(row) arenaTypeID = mapStat[mapID][0]['arenaTypeID'] arenaType = ArenaType.g_cache[arenaTypeID] arenaName = i18n.makeString(arenaType.name) arenaNameDecoded = arenaName.decode('utf-8') row = row.replace('{{map}}', arenaName) row = row.replace('{{map-raw}}', arenaType.geometryName) for xx in xrange(5, 31): xxcut = xx - 2 row = row.replace('{{map:%d}}' % xx, '{:.{w}}'.format(arenaNameDecoded, w=xx) if len(arenaNameDecoded) <= xx else '{:.{w}}'.format(arenaNameDecoded, w=xxcut) + '..') row = row.encode('utf-8') row = self.applyMacros(row, mapValues[mapID], mapGradient[mapID], mapPalette[mapID]) rows += row + '\n' msg = '\n'.join(self.config.get('byMapTemplate', '')) msg = msg.replace('{{ByMapRows}}', rows) msg = self.formatButtons(msg, msgPage) self.messageByMap = msg def confirmResetMessage(self): """Reset confirmation message.""" if self.config.get('enableResetConfirmation', True): msgPage = 'Reset' msg = '\n'.join(self.config.get('resetConfirmationText', '')) msg = self.formatButtons(msg, msgPage) self.messageReset = msg else: self.reset() def replaceBattleResultMessage(self, message, arenaUniqueID): message = unicode(message, 'utf-8') if self.config.get('debugBattleResultMessage', False): LOG_NOTE(message) basicValues = self.battleStats[arenaUniqueID]['values'] extendedValues = self.battleStats[arenaUniqueID]['extendedValues'] values = basicValues values.update(extendedValues) for pattern in self.battleStatPatterns: try: if not eval(pattern.get('condition')): continue except: print '[wotstat] Invalid calculation condition ' + pattern.get('condition') continue message = re.sub(pattern.get('pattern', ''), pattern.get('repl', ''), message) battleStatText = '\n'.join(self.config.get('battleStatText', '')) gradient = self.battleStats[arenaUniqueID]['gradient'] palette = self.battleStats[arenaUniqueID]['palette'] battleStatText = self.applyUserMacros(battleStatText) message = message + "\n<font color='#929290'>" + battleStatText + '</font>' message = self.applyMacros(message, values, gradient, palette) return message def hideMessagePatterns(self, message): for element in stat.config.get('hideMessagePatterns', []): element = element.decode('utf-8').lower().encode('utf-8') if message.decode('utf-8').lower().encode('utf-8').find(element) != -1: return False return True def mod_popUpListViewer(self): try: import gui.mods.mod_PopUpListViewer return False except: return True def expandStatNotificationList(self, item): savedData = item['message'].get('savedData', -1) arenaUniqueID = -1 if isinstance(savedData, long): arenaUniqueID = int(savedData) elif isinstance(savedData, tuple): arenaUniqueID = int(savedData[0]) message = item['message'].get('message', '') self.arenaUniqueIDsss = arenaUniqueID if arenaUniqueID > 0 and self.battleStats.has_key(arenaUniqueID) and type(message) == str: message = self.replaceBattleResultMessage(message, arenaUniqueID) item['message']['message'] = message if self.config.get('overwriteBattleResultBgIcon', False): result = self.battleStats[arenaUniqueID]['extendedValues']['result'] bgIconKeys = {-1: 'bgIconDefeat', 0: 'bgIconDraw', 1: 'bgIconWin'} bgIconKey = bgIconKeys[result] bgIcon = self.config.get(bgIconKey, item['message']['bgIcon']) item['message']['bgIcon'] = bgIcon return item stat = SessionStatistic() def new_onBecomePlayer(self): old_onBecomePlayer(self) stat.battleResultsAvailable.set() stat.load() old_onBecomePlayer = Account.onBecomePlayer Account.onBecomePlayer = new_onBecomePlayer def new_onBecomeNonPlayer(self): stat.battleResultsAvailable.clear() old_onBecomeNonPlayer(self) old_onBecomeNonPlayer = Account.onBecomeNonPlayer Account.onBecomeNonPlayer = new_onBecomeNonPlayer def new_nlv_getMessagesList(self): result = old_nlv_getMessagesList(self) if stat.config.get('onlineReloadConfig', False): stat.readConfig() stat.updateMessage() stat.config['onlineReloadConfig'] = True if self._NotificationListView__currentGroup in 'info': result.append(stat.createMessage()) return result old_nlv_getMessagesList = NotificationListView._NotificationListView__getMessagesList NotificationListView._NotificationListView__getMessagesList = new_nlv_getMessagesList def new_notificationsListMeta_as_setMessagesListS(self, value): if stat.mod_popUpListViewer() and len(stat.config.get('hideMessagePatterns', [])): formed = [] for item in value['messages']: text = item['message']['message'] if stat.hideMessagePatterns(text): formed.append(item) value['messages'] = formed if stat.config.get('showStatForBattle', True): value['messages'] = map(stat.expandStatNotificationList, value['messages']) old_notificationsListMeta_as_setMessagesListS(self, {'messages': value['messages'], 'emptyListText': value['emptyListText'], 'btnBarSelectedIdx': value['btnBarSelectedIdx']}) old_notificationsListMeta_as_setMessagesListS = NotificationsListMeta.as_setMessagesListS NotificationsListMeta.as_setMessagesListS = new_notificationsListMeta_as_setMessagesListS def new_onClickAction(self, typeID, entityID, action): if 'statPage:' in action: if action.split(':')[1] == 'General': stat.page = 0 elif action.split(':')[1] == 'Tanks': stat.page = 11 elif action.split(':')[1] == 'Maps': stat.page = 21 elif action.split(':')[1] == 'TankSortByMacro1': stat.page = 11 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro1']) elif action.split(':')[1] == 'TankSortByMacro2': stat.page = 12 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro2']) elif action.split(':')[1] == 'TankSortByMacro3': stat.page = 13 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro3']) elif action.split(':')[1] == 'TankSortByMacro4': stat.page = 14 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro4']) elif action.split(':')[1] == 'TankSortByMacro5': stat.page = 15 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro5']) elif action.split(':')[1] == 'TankSortByMacro6': stat.page = 16 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro6']) elif action.split(':')[1] == 'TankSortByMacro7': stat.page = 17 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro7']) elif action.split(':')[1] == 'TankSortByMacro8': stat.page = 18 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro8']) elif action.split(':')[1] == 'TankSortByMacro9': stat.page = 19 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro9']) elif action.split(':')[1] == 'TankSortByMacro10': stat.page = 20 stat.updateMessageTanks(stat.tankSortingMacros['tankSortingMacro10']) elif action.split(':')[1] == 'MapSortByMacro1': stat.page = 21 stat.updateMessageMaps(stat.mapSortingMacros['mapSortingMacro1']) elif action.split(':')[1] == 'MapSortByMacro2': stat.page = 22 stat.updateMessageMaps(stat.mapSortingMacros['mapSortingMacro2']) elif action.split(':')[1] == 'MapSortByMacro3': stat.page = 23 stat.updateMessageMaps(stat.mapSortingMacros['mapSortingMacro3']) elif action.split(':')[1] == 'MapSortByMacro4': stat.page = 24 stat.updateMessageMaps(stat.mapSortingMacros['mapSortingMacro4']) elif action.split(':')[1] == 'MapSortByMacro5': stat.page = 25 stat.updateMessageMaps(stat.mapSortingMacros['mapSortingMacro5']) elif action.split(':')[1] == 'Reset': stat.page = 30 stat.confirmResetMessage() elif action.split(':')[1] == 'ResetYes': stat.reset() elif action.split(':')[1] == 'ResetNo': stat.page = 0 self.as_updateMessageS(stat.createMessage()) else: old_nlv_onClickAction(self, typeID, entityID, action) old_nlv_onClickAction = NotificationListView.onClickAction NotificationListView.onClickAction = new_onClickAction def new_npuv_sendMessageForDisplay(self, notification): if stat.config.get('showPopUp', True): old_npuv_sendMessageForDisplay(self, notification) old_npuv_sendMessageForDisplay = NotificationPopUpViewer._NotificationPopUpViewer__sendMessageForDisplay NotificationPopUpViewer._NotificationPopUpViewer__sendMessageForDisplay = new_npuv_sendMessageForDisplay def new_brf_format(self, message, *args): result = old_brf_format(self, message, *args) arenaUniqueID = message.data.get('arenaUniqueID', 0) stat.queue.put(arenaUniqueID) if stat.config.get('enableBattleEndedMessage', True) and hasattr(BigWorld.player(), 'arena'): if BigWorld.player().arena.arenaUniqueID != arenaUniqueID: isWinner = message.data.get('isWinner', 0) battleEndedMessage = '' if isWinner < 0: battleEndedMessage = stat.config.get('battleEndedMessageDefeat', '') elif isWinner > 0: battleEndedMessage = stat.config.get('battleEndedMessageWin', '') else: battleEndedMessage = stat.config.get('battleEndedMessageDraw', '') battleEndedMessage = battleEndedMessage.encode('utf-8') playerVehicles = message.data['playerVehicles'].itervalues().next() vehicleCompDesc = playerVehicles['vehTypeCompDescr'] vt = vehiclesWG.getVehicleType(vehicleCompDesc) battleEndedMessage = battleEndedMessage.replace('{{vehicle-long}}', vt.userString) battleEndedMessage = battleEndedMessage.replace('{{vehicle-short}}', vt.shortUserString) name = vt.name.replace(':', '-') battleEndedMessage = battleEndedMessage.replace('{{vehicle-raw}}', name) arenaTypeID = message.data.get('arenaTypeID', 0) arenaType = ArenaType.g_cache[arenaTypeID] arenaName = i18n.makeString(arenaType.name) xp = message.data.get('xp', 0) credits = message.data.get('credits', 0) separator = stat.config.get('thousandSeparator', ' ') sXp = format(xp, ',d') sCredits = format(credits, ',d') sXp = sXp.replace(',', separator) sCredits = sCredits.replace(',', separator) battleEndedMessage = battleEndedMessage.replace('{{map}}', arenaName) battleEndedMessage = battleEndedMessage.replace('{{map-raw}}', arenaType.geometryName) battleEndedMessage = battleEndedMessage.replace('{{totalXP}}', sXp) battleEndedMessage = battleEndedMessage.replace('{{grossCredits}}', sCredits) MessengerEntry.g_instance.gui.addClientMessage(battleEndedMessage) return result old_brf_format = BattleResultsFormatter.format BattleResultsFormatter.format = new_brf_format def new_regularArenaFullNameItem(self, record, reusable): arenaGuiType = reusable.common.arenaGuiType arenaType = reusable.common.arenaType if arenaGuiType == ARENA_GUI_TYPE.RANDOM: i18nKey = _ARENA_TYPE_FORMAT.format(arenaType.getGamePlayName()) else: i18nKey = _ARENA_TYPE_EXT_FORMAT.format(arenaGuiType) if stat.config['battleResultsWindow']['enable'] and stat.battleStats.has_key(reusable._ReusableInfo__arenaUniqueID): values = stat.battleStats[reusable._ReusableInfo__arenaUniqueID]['values'] values.update(stat.battleStats[reusable._ReusableInfo__arenaUniqueID]['extendedValues']) gradient = stat.battleStats[reusable._ReusableInfo__arenaUniqueID]['gradient'] palette = stat.battleStats[reusable._ReusableInfo__arenaUniqueID]['palette'] return stat.applyMacros(stat.config['battleResultsWindow']['format'].replace('{{arenaType}}', i18n.makeString(arenaType.getName())).replace('{{arenaGuiType}}', i18n.makeString(i18nKey)), values, gradient, palette) old_regularArenaFullNameItem(self, record, reusable) old_regularArenaFullNameItem = RegularArenaFullNameItem._convert RegularArenaFullNameItem._convert = new_regularArenaFullNameItem error in python.log 2019-12-09 19:18:22.276: INFO: ============================= 2019-12-09 19:18:22.276: INFO: 2019-12-09 19:18:22: [ERROR] mods/xfw_libraries/xfw/events.pyc 2019-12-09 19:18:22.276: ERROR: Traceback (most recent call last): 2019-12-09 19:18:22.276: ERROR: File "./xfw/events.py", line 56, in __event_handler 2019-12-09 19:18:22.276: ERROR: File "D:\Mods\World_of_Tanks\SessionStatistics\mod_stat.py", line 1169, in new_onBecomePlayer 2019-12-09 19:18:22.276: ERROR: File "D:\Mods\World_of_Tanks\SessionStatistics\mod_stat.py", line 128, in load 2019-12-09 19:18:22.276: ERROR: File "scripts/common/Lib/json/__init__.py", line 290, in load 2019-12-09 19:18:22.276: ERROR: File "scripts/common/Lib/json/__init__.py", line 338, in loads 2019-12-09 19:18:22.277: ERROR: File "scripts/common/Lib/json/decoder.py", line 366, in decode 2019-12-09 19:18:22.277: ERROR: File "scripts/common/Lib/json/decoder.py", line 384, in raw_decode 2019-12-09 19:18:22.277: ERROR: ValueError: No JSON object could be decoded 2019-12-09 19:18:22.277: INFO: ============================= mod_stat.pyc SessionStatistics&BattleResults_1.6.1.0_r01x.zip
  17. Since today, retrieving the wn8exp.json via a statistic Python script no longer works. Only the following entry is generated locally in the file: <html><body><h1>403 Forbidden</h1> Request forbidden by administrative rules. </body></html> The browser displays the wn8exp.json. What has changed in retrieving the data when it is done with a script?
  18. @ktulho OK, thanks for the tip. Is there a difference or advantage? I ask, because this example is working for me since month.
  19. @bes1 Example: // Friend icon. "friend": { "enabled": true, //"hotKeyCode": 56, "onHold": "true", "visibleOnHotKey": true, "x": 128, "y": 5, "width": 12, "height": 18, "align": "center", "alpha": 100, "bindToIcon": true, "src": "xvm://res/icons/friend/{{friend?friend}}.png" },
  20. Try this: "booster": { "enabled": true, //"layer": "top", "layer": "normal", // auskommentieren für Text "type": "extrafield", "formats": [ { "updateEvent": "ON_EVERY_SECOND", "screenHAlign": "center", // auskommentieren für Text //"x": 210, "x": -325, // auskommentieren für Text //"y": 0, "y": 87, // auskommentieren für Text "width": 400, "height": 80, "alpha": 100, // auskommentieren für Text //"textFormat": { "color": "0xA8A888", "size": 12}, "textFormat": { "color": "0xF9F1BC" }, // auskommentieren für Text //"format": "<textformat tabstops='[50]'>{{py:bst.leftTime(1)}}<tab>{{py:bst.name(1)}}</textformat>\n<textformat tabstops='[50]'>{{py:bst.leftTime(2)}}<tab>{{py:bst.name(2)}}</textformat>\n<textformat tabstops='[50]'>{{py:bst.leftTime(3)}}<tab>{{py:bst.name(3)}}</textformat>" "format": "<textformat tabstops='[0]'>{{py:bst.name(1)}} {{py:bst.name(2)}} {{py:bst.name(3)}}</textformat>" // auskommentieren für Text } ] }, "boosterTime": { "enabled": true, "layer": "normal", "type": "extrafield", "formats": [ { "updateEvent": "ON_EVERY_SECOND", "screenHAlign": "center", "x": -280, "y": 145, "width": 400, "height": 80, "alpha": 100, "textFormat": { "color": "0xF9F1BC", "bold": "true", "size": 15}, "format": "<textformat tabstops='[80,160]' leading='-9'><font color='{{py:bst.leftTimeMin(1)<11?#FFB841|}}'>{{py:bst.leftTimeHrMin(1)}}</font><tab><font color='{{py:bst.leftTimeMin(2)<11?#FFB841|}}'>{{py:bst.leftTimeHrMin(2)}}</font><tab><font color='{{py:bst.leftTimeMin(3)<11?#FFB841|}}'>{{py:bst.leftTimeHrMin(3)}}</font></textformat>" } ] }, "boosterCR": { "enabled": true, "layer": "normal", "type": "extrafield", "formats": [ { "updateEvent": "ON_EVERY_SECOND", "screenHAlign": "center", "x": -325, "y": 170, "width": 400, "height": 80, "alpha": 100, "textFormat": { "color": "0xF9F1BC" }, "format": "<textformat tabstops='[0]'>{{py:bst.leftTimeMinCR(1)>1?{{py:bst.nameCR(1)}}|<img src='img://gui/maps/icons/boosters/{{py:bst.typeCR(1)}}_medium.png' vspace='0'>}} {{py:bst.leftTimeMinCR(2)>1?{{py:bst.nameCR(2)}}|<img src='img://gui/maps/icons/boosters/{{py:bst.typeCR(2)}}_medium.png' vspace='0'>}}</textformat>" } ] }, "boosterTimeCR": { "enabled": true, "layer": "normal", "type": "extrafield", "formats": [ { "updateEvent": "ON_EVERY_SECOND", "screenHAlign": "center", "x": -280, "y": 228, "width": 400, "height": 80, "alpha": 100, "textFormat": { "color": "0xF9F1BC", "bold": "true", "size": 15}, "format": "<textformat tabstops='[80,160]' leading='-9'><font color='{{py:bst.leftTimeMinCR(1)<11?#FFB841|}}'>{{py:bst.leftTimeHrMinCR(1)}}</font><tab><font color='{{py:bst.leftTimeMinCR(2)<11?#FFB841|}}'>{{py:bst.leftTimeHrMinCR(2)}}</font></textformat>" } ] } boosters.py
  21. Don't ask for ETA, it's done when it's done.
×
×
  • Create New...