Jump to content
Korean Random

Just.House

Newbie
  • Posts

    90
  • Joined

  • Days Won

    1

Posts posted by Just.House

  1. Что противоречивого я написал

     

    Ну прочитай свой пост:

     

    В итоге, если общий уровень громкости выкрутить на максимум, а "эффекты" понизить то звук лампы остается тем же.

     

    Т.е. ползунок эффектов выставлен в ноль, общий на максимум. До этого допустим ползунок на эффектах был на половине.

    Звук лампы не изменился, следственно изменение ползунка эффектов, если судить по этой фразе, ни на что не повлияло.

    А до этого утверждал что:

     

    отвечает не только "Общий уровень громкости", но и "Громкость -> Эффекты".
  2. Уважаемый @Ekspoint, на статистике за сессию:

    Версия с изменениями от: 25.02.2017

     

    Перестали добавляться расширенные данные в послебоевые сообщения в информационном канале:

     

    'Скриншот'

     

    post-36429-0-49409800-1488648622_thumb.png

     

     

    Логи: python.log


     

    Пока что откатился на версию от 02.01.2017

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import BigWorld
    import AccountCommands
    import ArenaType
    import codecs
    import datetime
    import json
    import math
    import os
    import re
    import ResMgr
    import threading
    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 *
    
    GENERAL = 0
    BY_TANK = 1
    
    #BattleResultsCache.clean = lambda *args: None
    
    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 = 6
            self.queue = Queue()
            self.loaded = False
            self.configIsValid = True
            self.battleStats = {}
            self.cache = {}
            self.gradient = {}
            self.palette = {}
            self.config = {}
            self.expectedValues = {}
            self.values = {}
            self.battles = []
            self.battleStatPatterns = []
            self.messageGeneral = ''
            self.messageByTank = ''
            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()
    
        def load(self):
            if self.loaded and self.playerName == BigWorld.player().name:
                return
            self.loaded = True
            self.battles = []
            self.playerName = BigWorld.player().name
            path = '/'.join(['.', 'res_mods', 'configs', 'wotstat']) 
            if os.path.isdir(path):
                self.configFilePath = '/'.join([path, 'config.json']) 
                self.statCacheFilePath = '/'.join([path, 'cache.json'])
                expectedValuesPath = '/'.join([path, 'expected_tank_values.json'])
            self.readConfig()
            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])
            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 = {}
            self.updateMessage()
    
        def readConfig(self):
            with codecs.open(self.configFilePath, '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: self.messageByTank
                }
            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']
            }
    #       if len(self.battles) and self.config.get('showStatByTank', True):
    #           buttonNames = {
    #               GENERAL: self.config.get('textGeneralPageButton', 'By tank'), 
    #               BY_TANK: self.config.get('textByTankPageButton', 'General')
    #           }
    #           message['message']['buttonsLayout'].append({
    #               'action': 'wotstatSwitchPage',
    #               'type': 'cancel',
    #               'label': buttonNames[self.page]
    #           })
    #       if len(self.battles) and self.config.get('showResetButton', False):
    #           message['message']['buttonsLayout'].append({
    #               'action': 'wotstatReset',
    #               'type': 'cancel',
    #               'label': self.config.get('textResetButton', 'Reset')
    #           })
            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
            if responseCode < 0:
                self.battleResultsBusy.release()
                return
            arenaTypeID = value['common']['arenaTypeID']
            arenaType = ArenaType.g_cache[arenaTypeID]
            personal = value['personal'].itervalues().next()
            vehicleCompDesc = personal['typeCompDescr']
            vt = vehiclesWG.getVehicleType(vehicleCompDesc)
            result = 1 if int(personal['team']) == int(value['common']['winnerTeam'])\
                else (0 if not int(value['common']['winnerTeam']) else -1)
            place = 1
            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
                    squadId = value['players'][vehicle[0]['accountDBID']]['prebattleID']
                    squadsTier[squadId] = max(squadsTier.get(squadId, 0), tier)
                if personal['team'] == vehicle[0]['team'] and \
                    personal['originalXP'] < vehicle[0]['xp']:
                    place += 1
            battleTier = 11 if max(squadsTier.values()) == 10 and min(squadsTier.values()) == 9 \
                else 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,
                'map': arenaType.geometryName,
                'vehicle': vt.name.replace(':', '-'),
                'tier': vt.level,
                'result': result,
                'damage': personal['damageDealt'],
                '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,
                'credits': proceeds,
                'gold': personal['gold'] - personal['autoEquipCost'][1] - personal['autoLoadCost'][1],
                'battleTier': battleTier,
                'assist': personal['damageAssistedRadio'] + personal['damageAssistedTrack'],
                'assistRadio': personal['damageAssistedRadio'],
                'assistTrack': personal['damageAssistedTrack']
            }
            extended = {
                'vehicle': battle['vehicle'],
                'map': battle['map'],
                'result': result,
                'autoRepair': personal['autoRepairCost'],
                'autoEquip': personal['autoEquipCost'][0],
                'autoLoad': personal['autoLoadCost'][0],
                'tmenXP': tmenXP
            }
            if self.config.get('dailyAutoReset', True) and self.startDate != stat.getWorkDate():
                self.reset()
            if value['common']['guiType'] 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()
    
        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']
                        else:
                            break
                else:
                    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 xeff(self, x):
            if x > 2300:
                return 100
            return int(max(0, min(100, x * (x * (x * (x * (x * (x * 6.449e-18 - 4.089e-14) + 8.302e-11) - 4.433e-08) - 4.82e-05) + 0.1257) - 40.42)))
    
        def xwn8(self, x):
            if x > 3800:
                return 100
            return int(max(0, min(100, x * (x * (x * (x * (x * (-x * 9.762e-20 + 1.6221e-15) - 1.007e-11) + 2.7916e-08) - 3.6982e-05) + 0.05577) - 1.3)))
            
        def calcWN8(self, battles):
            values = {}
            values['battlesCount'] = len(battles)
            totalTier = 0
            totalPlace = 0
            places = []
            totalBattleTier = 0
            valuesKeys = ['winsCount', 'defeatsCount', 'drawsCount', 'totalDmg', 'totalFrag', 'totalSpot',\
                'totalDef', 'totalCap', 'totalShots', 'totalHits', 'totalPierced', 'totalAssist',\
                'totalXP', 'totalOriginXP', 'totalFreeXP', 'credits', 'gold',\
                'totalAssistRadio', 'totalAssistTrack']
            for key in valuesKeys:
                values[key] = 0
            expKeys = ['expDamage', 'expFrag', 'expSpot', 'expDef', 'expWinRate']
            expValues = {}
            for key in expKeys:
                expValues['total_' + key] = 0.0
            resCounters = {-1: 'defeatsCount', 0: 'drawsCount', 1: 'winsCount'}
            for battle in battles:
                values[resCounters[battle['result']]] += 1
                values['totalDmg'] += battle['damage']
                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['totalOriginXP'] += battle['originalXP']
                values['totalFreeXP'] += battle['freeXP']
                values['credits'] += battle['credits']
                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 values['battlesCount'] > 0:
                values['avgWinRate'] = float(values['winsCount'])/values['battlesCount']*100
                values['avgDamage'] = float(values['totalDmg'])/values['battlesCount']
                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['totalOriginXP']/values['battlesCount'])
                values['avgPremXP'] = int(1.5*values['avgOriginalXP'])
                values['avgCredits'] = int(values['credits']/values['battlesCount'])
                values['avgTier'] = float(totalTier)/values['battlesCount']
                values['avgBattleTier'] = float(totalBattleTier)/values['battlesCount']
                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']
                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['avgWinRate'] - 35)* -0.134))) - 500)*0.45 + \
                    (6-min(values['avgTier'], 6))*-60))
                values['XWN6'] = 100 if values['WN6'] > 2300 \
                    else int(max(min(values['WN6']*(values['WN6']*(values['WN6']*(values['WN6']*\
                    (values['WN6']*(0.00000000000000000466*values['WN6'] - 0.000000000000032413) + \
                    0.00000000007524) - 0.00000006516) + 0.00001307) + 0.05153) - 3.9, 100), 0))
                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))
                values['XEFF'] = self.xeff(values['EFF'])
                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['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['avgWinRate'] - 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)) ))                
            else:
                for key in ['avgWinRate', 'avgDamage', 'avgFrag', 'avgSpot', 'avgDef', 'avgCap', 'avgHitsRate', \
                    'avgEffHitsRate', 'avgAssist', 'avgXP', 'avgOriginalXP', 'avgPremXP', 'avgCredits', 'avgTier', \
                    'avgBattleTier', 'medPlace', 'WN6', 'XWN6', 'EFF', 'XEFF', 'BR', 'WN7']:
                    values[key] = 0
                for key in expKeys:
                    values[key] = 1
            values['avgBattleTierDiff'] = values['avgBattleTier'] - values['avgTier']
            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['avgWinRate']/values['expWinRate']
            values['rWINc'] = max(0, (values['rWIN'] - 0.71)/(1 - 0.71))
            values['rDAMAGEc'] = max(0, (values['rDAMAGE'] - 0.22)/(1 - 0.22))
            values['rFRAGc'] = max(0, min(values['rDAMAGEc'] + 0.2, (values['rFRAG'] - 0.12)/(1 - 0.12)))
            values['rSPOTc'] = max(0, min(values['rDAMAGEc'] + 0.1, (values['rSPOT'] - 0.38)/(1 - 0.38)))
            values['rDEFc'] = max(0, min(values['rDAMAGEc'] + 0.1, (values['rDEF'] - 0.10)/(1 - 0.10)))
            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'])
            values['XWN8'] = self.xwn8(values['WN8'])
            values['WN8'] = int(values['WN8'])
            values['avgDamage'] = int(values['avgDamage'])
            (gradient, palette) = self.refreshColorMacros(values)
            return (values, gradient, palette)
            
        def applyMacros(self, val, prec = 2):
            if type(val) == str:
                return val
            if prec <= 0:
                return format(int(round(val)), ',d')
            sVal = format(val, ',.%sf' % prec) \
                if type(val) is float else format(val, ',d')
            sVal = sVal.replace(',', ' ')
            return sVal
    
        def formatString(self, text, values, gradient, palette):
            for key in values.keys():
                text = text.replace('{{%s}}' % key, self.applyMacros(values[key]))
                text = text.replace('{{%s:d}}' % key, self.applyMacros(values[key], 0))
                text = text.replace('{{%s:1f}}' % key, self.applyMacros(values[key], 1))
                text = text.replace('{{g:%s}}' % key, gradient[key])
                text = text.replace('{{c:%s}}' % key, palette[key])
            return text
    
        def updateMessage(self):
            if not self.configIsValid:
                self.message = 'stat_config.json is not valid'
                return
            self.values, self.gradient, self.palette = self.calcWN8(self.battles)
            bg = self.config.get('bgIcon', '')
            self.bgIcon = self.formatString(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.formatString(msg, self.values, self.gradient, self.palette)
            msg = msg.replace('{{ButtonTanks}}', self.config['Button']['Tanks']['format'] if self.config['Button']['Tanks']['enable'] else '')
            msg = msg.replace('{{ButtonReset}}', self.config['Button']['Reset']['format'] if self.config['Button']['Reset']['enable'] else '')
            msg = msg.replace('{{ButtonGeneral}}', self.config['Button']['General']['format'] if self.config['Button']['General']['enable'] else '')
            self.messageGeneral = msg
            rows = ''
            tankStat = {}
            for battle in self.battles:
                idNum = battle['idNum']
                if tankStat.has_key(idNum):
                    tankStat[idNum].append(battle)
                else:
                    tankStat[idNum] = [battle]
            for idNum in sorted(tankStat.keys(), key = lambda idNum: len(tankStat[idNum]), reverse = True):
                row = ''.join(self.config.get('TankStat', ''))
                values, gradient, palette = self.calcWN8(tankStat[idNum])
                vt = vehiclesWG.getVehicleType(idNum)
                row = row.replace('{{vehicle}}', vt.shortUserString)
                name = vt.name.replace(':', '-')
                row = row.replace('{{vehicle-name}}', name)
                row = self.formatString(row, values, gradient, palette)
                rows += '\n' + row 
                msg = '\n'.join(self.config.get('byTankRow',''))
                msg = self.formatString(msg, values, gradient, palette)
                msg = msg.replace('{{TankStat}}', rows)
                msg = msg.replace('{{ButtonTanks}}', self.config['Button']['Tanks']['format'] if self.config['Button']['Tanks']['enable'] else '')
                msg = msg.replace('{{ButtonReset}}', self.config['Button']['Reset']['format'] if self.config['Button']['Reset']['enable'] else '')
                msg = msg.replace('{{ButtonGeneral}}', self.config['Button']['General']['format'] if self.config['Button']['General']['enable'] else '')
                self.messageByTank = msg
    
        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']
            message = message + '\n<font color=\'#929290\'>' + battleStatText + '</font>'
            message = self.formatString(message, values, gradient, palette)
            return message
    
        def filterNotificationList(self, item):
            message = item['message'].get('message', '')
            msg = unicode(message, 'utf-8') if isinstance(message, str) \
                else message if isinstance(message, unicode) else None
            if msg:
                for pattern in self.config.get('hideMessagePatterns', []):
                    if re.search(pattern, msg, re.I):
                        return False
            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', '')
            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
    
    old_onBecomePlayer = Account.onBecomePlayer
    
    def new_onBecomePlayer(self):
        old_onBecomePlayer(self)
        stat.battleResultsAvailable.set()
        stat.load()
    
    Account.onBecomePlayer = new_onBecomePlayer
    
    
    old_onBecomeNonPlayer = Account.onBecomeNonPlayer
    
    def new_onBecomeNonPlayer(self):
        stat.battleResultsAvailable.clear()
        old_onBecomeNonPlayer(self)
    
    Account.onBecomeNonPlayer = new_onBecomeNonPlayer
    
    old_nlv_getMessagesList = NotificationListView._NotificationListView__getMessagesList
    
    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
        
        
    NotificationListView._NotificationListView__getMessagesList = new_nlv_getMessagesList
    
    from notification.settings import NOTIFICATION_GROUP
    
    
    old_nlv_setNotificationList = NotificationListView._NotificationListView__setNotificationList
    
    def new_nlv_setNotificationList(self):
        if stat.config.get('onlineReloadConfig', False):
            stat.readConfig()
            stat.updateMessage()
            stat.config['onlineReloadConfig'] = True
        formedList = self._NotificationListView__getMessagesList()
        if len(stat.config.get('hideMessagePatterns', [])):
            formedList = filter(stat.filterNotificationList, formedList)
        if stat.config.get('showStatForBattle', True):
            formedList = map(stat.expandStatNotificationList, formedList)
        self.as_setMessagesListS({'messages': formedList,
             'emptyListText': self._NotificationListView__getEmptyListMsg(len(formedList) > 0),
             'btnBarSelectedIdx': NOTIFICATION_GROUP.ALL.index(self._NotificationListView__currentGroup)})
        self._model.resetNotifiedMessagesCount(self._NotificationListView__currentGroup)
    
    
    NotificationListView._NotificationListView__setNotificationList = new_nlv_setNotificationList
    
    old_nlv_onClickAction = NotificationListView.onClickAction
    
    def new_onClickAction(self, typeID, entityID, action):
        if 'Page:' in action:
            if action.split(':')[1] == 'Tanks':
                stat.page = 1
            elif action.split(':')[1] == 'General':
                stat.page = 0
            elif action.split(':')[1] == 'Reset':
                stat.reset()
            self.as_updateMessageS(stat.createMessage())
        else:
            old_nlv_onClickAction(self, typeID, entityID, action)
    
    NotificationListView.onClickAction = new_onClickAction
    
    old_npuv_sendMessageForDisplay = NotificationPopUpViewer._NotificationPopUpViewer__sendMessageForDisplay
    
    def new_npuv_sendMessageForDisplay(self, notification):
        if stat.config.get('showPopUp', True):
            old_npuv_sendMessageForDisplay(self, notification)
    
    NotificationPopUpViewer._NotificationPopUpViewer__sendMessageForDisplay = new_npuv_sendMessageForDisplay
    
    old_brf_format = BattleResultsFormatter.format
    
    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}}', vt.userString)
                name = vt.name.replace(':', '-')
                battleEndedMessage = battleEndedMessage.replace('{{vehicle-name}}', 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)
                battleEndedMessage = battleEndedMessage.replace('{{map}}', arenaName)
                battleEndedMessage = battleEndedMessage.replace('{{map-name}}', arenaType.geometryName)
                battleEndedMessage = battleEndedMessage.replace('{{xp}}', str(xp))
                battleEndedMessage = battleEndedMessage.replace('{{credits}}', str(credits))
                MessengerEntry.g_instance.gui.addClientMessage(battleEndedMessage)
        return result
    
    BattleResultsFormatter.format = new_brf_format
    
    stat = SessionStatistic()
    

    • Upvote 1
  3. Подскажите какой эвент отвечает за сообщение когда противник засветился?

     

    Ой, боже ж ты мой. Читать так и не умеем...

    41a291f829a5.png

    'Для осмысления...'

     

    С таким вот подходом, а именно выпрашиванием я бы посоветовал отказаться от затеи сделать для себя звуковой мод (да и в принципе в любом другом начинании), ибо Ваша лень ставит жирный крест на всем. Нужно это прежде всего вам и никому более, уже вполне доходчиво давали нужное направление что и где искать:

     

    1) Искать по конфигурационным файлам клиента.

    2) Взять из готового проекта предоставленным разработчиками.

    3) Использовать встроенное логгирование событий из XVM-ма

    4) Тоже что и предыдущее, но отдельным скриптом на питоне.

     

    Сделаю акцент на втором пункт этого ответа. И я пиннок уже давал в нужное русло:

     

    Да и том проекте что разрабы дали так же есть полное описание к эвентам в игр

    post-36429-0-78332600-1486792433_thumb.png

     

  4. Человек спросил "почему работает через engine_config.xml и не работает через audio_mods.xml", я дал ему рабочий кейс почему такое может происходить.

     

    Вот мои файлы может где накосячил. Все делал по пунктам. Шины есть.

     

    res_mods (Just.House).zip

     

    Если добавляю инжен с прописанным банком то начинает грузиться, и громкость регулируется в настройках. Из нового файла работает нормально только реммапинг ивентов, а вот загрузка нет.

  5. Собирайте банку на базе предоставленного проекта и все заработает.

    Конкретно в этом случае у вас не хватает аудио шин.

     

    Я как раз собирал по данному проекту. Результат выше.

  6. и краткая инструкция по созданию звуковых модов

     

    Уважаемый ribbed, уточните пожалуйста у ваших коллег такут проблемку:

     

    Банк в вайсе собрали новый для тестового патча. Он подгружается клиентом только старым способом, если его прописать в engine_config.xml, новым способов записав его в audio_mods.xml в <banks> он не загружается клиентом. Хотя замена событий в этом же новом файле <events> работает.

     

    'Так загружает, engine_config.xml'

    <SFX_soundbanks_loadonce>
      <project>
        <name>example_mod.bnk</name>
      </project>
    </SFX_soundbanks_loadonce>
    

    'Так нет, audio_mods.xml'

    <banks>
      <bank> 
        <name>example_mod.bnk</name>
      </bank>
    </banks>
    

     

  7. помогите правильно назвать эвенты для озвучки событий. зарядил не пробил и т.д.

    или подскажите где их найти с расшифровкой

     

    Не в обиду конечно но это:

     

    post-36429-0-68930800-1486791740.jpg

     

     

    Вам все уже дали, расписали. Скачайте пример wwise_project_voiceover.zip из шапки там все расписано, описано.

    Это я называю ленью, если есть желание человек найдет в предоставленных ему данных что ему нужно. За вас каждую мелочь искать люди бесплатно не будут, не у всех есть свободное время и желание. Да и том проекте что разрабы дали так же есть полное описание к эвентам в игре:

     

    post-36429-0-78332600-1486792433_thumb.png

     

     

    Представь: Andre_V_Voice_Mod_with_incredibly_long_name_gun_reloaded, и таких ивентов 80 штук на проект о_О

     

    Можно как то по автору префиксы выбирать, например, Andre_V делает озвучку, добавляя к примеру: AV_gun_reloaded

    Тут в теме примеры описаны с приставкой: SM_gun_reloaded

    Громовые орудия: GO_gun_reloaded

    Ekspoint: Exp_gun_reloaded

    И т.п.

     


    Хочу между делом поблагодарить товарищей: @night_dragon_on и @Andre_V, за ваши инструкции и желание помочь людям, и Andre_V за множество его созданных озвучек для нас пользователей.

    • Upvote 3
  8. Эх, вообще ничего не понятно.

     

    Нужно не просто читать, а вникать и анализоровать прочитанное.

     

    Зачем скачивать? Я ведь свою хочу.

     

    Ну пропускай этот пункт.

     

    У меня даже такой папки нет

     

    В этой папке по умолчанию расположен банк (из примера).

  9. Если в бою средний урон у всех игроков на этом сервере на данной техники отдается - надо использовать его

     

    Зачем, тут как раз все нормально мы сравниваем свой средний урон по макросу {{tdb}} и относительно него и действуем в бою.

    Мы преодалеваем свой порог урона а не чей то там на сервере.

     

    опять не учитывает "хотелку" по размещению обоих значений (и урона и калибра) в одной строке/в одном поле. имхо для дефолта не годится

     

    Тут тоже как по мне (не в обиду конечно) суждение не верное, не нужно смешивать ваши хотелки с дефолтным вариантом, создавать такую планку что если для вашей реализации дефолт не подходит он не должен в таком виде присутствовать. Дефолт он на то и дефолт чтобы по нему брали пример и делали свой вариант. Вы своего добились уже и сделали для себя удобный код.

  10. да, надо добавить, и кучу других тоже. где время на все взять?

     

    Жаль конечно, но адекватные пользователи на этом форуме поймут что вы занимаетесь таким обширным модом в одиночку.

    Так что будем ждать как появится время на это :ok:

    • Upvote 1
  11. @sirmax, доброго времени суток.

     

    Используя наработки от @ktulho и @night_dragon_on в прошлом патче и предыдущей стабильной версии XVM-ма делал для себя минималистичную панель с информацией завязанную на питоне и battleLabels.

     

    'Питон'

    #Copy from:
    #http://www.koreanrandom.com/forum/topic/31856-
    #page-11
    #page-12
    
    import BigWorld
    
    def typeDescriptor():
        player = BigWorld.player()
        target = BigWorld.target()
        if target is not None:
            return target.typeDescriptor
        else:
            return player.getVehicleAttached().typeDescriptor
    
    @xvm.export('vehicle_name', deterministic=False)
    def vehicle_name(): 
        return typeDescriptor().type.userString
    
    @xvm.export('gun_reload', deterministic=False)
    def gun_reload():
        return "%.1f" % (typeDescriptor().gun['reloadTime'])
    
    @xvm.export('vision_radius', deterministic=False)
    def vision_radius():
        return "%i" % (typeDescriptor().turret['circularVisionRadius'])
    

    'battleLabels'

    "infoBattleLabels": {
      "enabled": true,
      //Hot key Alt
      "hotKeyCode": 56, 
      "onHold": true,
      ...
      "format": "Техника: {{py:vehicle_name()}}\nКд: {{py:gun_reload()}}\nОбзор: {{py:vision_radius()}}"
    }
    

     

    Так вот в прошлом патче при нажатии на клавишу и появлении поля информация обновлялась (пересчитывался "typeDescriptor").

    Сейчас в текущем релизе так же при нажатии на горячую кнопку уже обновления поля не происходит (видимо обновлялку вырезали при портировании XVM-ма под AS3).

     

    Возможно ли добавить новый "updateEvent" который бы обновлял поле по нажатии на горячую клавишу?

  12. Даже минимальной информации из стандартного конфига (только рейтинг) достаточно, чтобы понять, что подложку всё же лучше расширить.

     

    Для этого и вводят экстра поля.

     

    и её неподходящая ширина заметна.

     

    Тем более если растягивать стандартную подложку она будет выглядеть замыленно, что не есть гуд.

  13. [bug] Короткая подложка на экране загрузки

     

    Не хочу никого обидеть, но зачем в наименовании темы включать слово "баг", с чего вы это взяли?

    XVM никогда не изменял размеры подложки под свои нужды. Раз в клиенте размер такой же то и тут должен быть аналогичный. Да и к тому же это окно считается компактным и не должно по сути загромождаться тамим количеством данных, чтобы подложка по всей длинне была. О чем свидетельствует упрощенный набор параметров в дефолтном конфиге модификации.

     

    Заголовок с таким содержанием лишь лишний раз отвлечет Sirmax-са по пустяку, отвлекая его от более важных дел.

    • Upvote 1
  14. для начала, у тебя мод криво установлен

     

    Мало того что мод нормально не умеют ставить, да так и логи еще прикладывают в перемешку со сторонними модами.

    Таких сразу слать в это сообщение. Ибо поневоле бесполезно отвлекают по пустякам из-за своих же ошибок и некомпетентности.

     

    А у меня вообще не отображаются

     

    Сколько раз уже на форуме писали что в damageLog сейчас еще кривая флешка используется которая блочит XVM

     

     

     

    При описании проблемы с ночными билдами обязательно необходимо:

    • удостовериться, что проблема отсутствует в чистом клиенте и проявляется только с XVM (использование других модификаций для тестирования недопустимо)
    • указать номер используемого билда (на момент воспроизведения бага вы должны использовать последний доступный ночной билд)
    • прикрепить логи из корневой папки игры: файлы XVM.log и Python.log
    • архив папки конфига \res_mods\configs\xvm\ (полностью, а не отдельные файлы)
    • прикрепить скриншоты или видеозапись, если баг можно проиллюстрировать ими
    • прикрепить реплей, если баг воспроизводится на реплее

     

    • Upvote 2
  15. 'Строки в конфиге:'

    {
      "iconset": {
        "fullStatsLeftAtlas": "battleAtlas",
        "fullStatsRightAtlas": "battleAtlas"
      }
    }
    

     

    Никак не реагируют на настройки.

     

    'Код'

    {
      "iconset": {
        // Folder containing the icon set for Battle Loading Screen.
        // Набор иконок для экрана загрузки боя.
        "battleLoadingAlly": "contour/",
        "battleLoadingEnemy": "contour/",
        // Folder containing the icon set for the Players Panels.
        // Набор иконок для "ушей".
        "playersPanelLeftAtlas": "battleAtlasTest",
        "playersPanelRightAtlas": "battleAtlasTest",
        // Folder containing the icon set for Full Stats Form (pressing "Tab").
        // Набор иконок для формы подробной статистики (по Tab).
        "fullStatsLeftAtlas": "battleAtlasTest",
        "fullStatsRightAtlas": "battleAtlasTest",
        // Folder containing the icon set for the Over-target markers.
        // Набор иконок для маркеров над танками.
        "vehicleMarkerAllyAtlas": "vehicleMarkerAtlas",
        "vehicleMarkerEnemyAtlas": "vehicleMarkerAtlas"
      }
    }
    

    'В окне fullStats'

     

    post-36429-0-20450700-1469343959_thumb.png

     

    'Содержимое атласов'

     

    battleAtlas - post-36429-0-88354900-1469343995.png

    battleAtlasTest - post-36429-0-91958200-1469344005.png

     

     

    Т.е. независимо от вписанного параметра ищется атлас с наименованием "battleAtlas"

     

     


    Ну и второе что хотел спростить, зачем параметры:

    formatLeftFrags
    formatRightFrags
    

    В - battleLoading и battleLoadingTips, ведь они никогда не выведутся в этих окнах.

     


    Кстати, киньте ссылку на темы с атласами, подберу несколько для тестов.

     

    На нашем форуме

    Последняя сборка TankIconMaker

  16. Да

    Ну тогда будем пробовать как параметры появятся.

     

    Сделал elements. В AS3 не совсем так, как в AS2, но кому надо, надеюсь, разберутся.

    Я такая фишка как смещение координат от уже имеющихся стандартных значений как:

     

    'Сейчас в 0.9.15.0.1'

    "leftPanel": {
      "_x": "leftPanel._x",
      "_y": "leftPanel._y - 20"
    },
    "rightPanel": {
      "_x": "rightPanel._x",
      "_y": "rightPanel._y - 20"
    },
    "switcher_mc": {
      "_x": "switcher_mc._x",
      "_y": "switcher_mc._y - 18"
    },

     

    Не работает в новой версии:

     

    0.9.15.1

    "playersPanel": {
      "listLeft": {
        "x": "playersPanel.listLeft.x",
        "y": "playersPanel.listLeft.y - 20"
      },
    }

     

    Работают в новой версии только если мы задаем жесткие координаты:

    "listLeft": {
      "x": 0,
      "y": 45
    }

    и макрос {{ally}} не работает в ушах (5905). Может и тут "картоха смогла"?

    "bgColor": "{{c:system}}"

    И макрос {{c:system}} отдает только цвет для противников (уши, экстраполя), если макрос применяется на союзниках то окрашивает все равно под цвет противников. Версия та же 5905

     

    Починил, просто не успевало загружаться.

    У меня как не грузился атлас в панели по таб так и не грузится

     

    'xvm.log'

    2016-06-27 17:05:00: [X:044] 4
    2016-06-27 17:05:00: [X:045] onAtlasInitializedHandler: { // net.wg.infrastructure.events::AtlasEvent
    "type": "atlasInitializedEvent",
    "target": "[object Atlas]",
    "eventPhase": 2,
    "currentTarget": "[object Atlas]",
    "cancelable": false,
    "bubbles": false
    }
    

  17. вдруг, всем врагам захочется нарисовать рога, а союзникам нимбы? Или на оборот. (ИМХО)

     

    Как раз такое описание (наименование опций запутывает), лучше бы так было прописано:

    // Набор иконок для маркеров над танками.
    "vehicleMarkerAllyAtlas": "vehicleMarkerAtlas",
    "vehicleMarkerEnemyAtlas": "vehicleMarkerAtlas"
    
  18. У WG сейчас задана константа на длину танка в 65 пикселей, и я ее использую. Сначала попробовал 80, но слишком уж далеко уезжают мелкие танки при отключении зеркалирования. Если добавлю параметр для смещения иконки по X, это поможет?

     

    Думаю да, а от чего будет смещение, от начального ВГ -шного положения иконки?

     

    P.S: Всегда хотел спросить для чего для наборов иконок предназначенных для маркеров разделение на левые и правые (для ушей то понятно). Они же вроде всегда в одну сторону направлены.

    // Набор иконок для маркеров над танками.
    "vehicleMarkerLeftAtlas": "vehicleMarkerAtlas",
    "vehicleMarkerRightAtlas": "vehicleMarkerAtlas"
    
  19. большие уши зависят от ширины имени игроков, если в конфиге не заданы одинаковые значения min и max.

    если пишешь репорт, прикладывай скриншот, чтобы можно было понять о чем речь.

     

    'Код ушей'

      "battle": {
        "mirroredVehicleIcons": false,
      }
    
      "iconset": {
        "playersPanelLeftAtlas": "contour",
        "playersPanelRightAtlas": "contour",
      }
    
        "short": {
          "enabled": true,
          "standardFields": [ "frags" ],
          "expandAreaWidth": 25,
          "removeSquadIcon": false,
          "vehicleLevelAlpha": 100,
          "fragsWidth": 24,
          "fragsFormatLeft": "{{frags%2d|0}}",
          "fragsFormatRight": "{{frags%2d|0}}",
          "nickMinWidth": 0,
          "nickMaxWidth": 0,
          "nickFormatLeft": "",
          "nickFormatRight": "",
          "vehicleWidth": 0,
          "vehicleFormatLeft": "",
          "vehicleFormatRight": "",
          "extraFieldsLeft": [],
          "extraFieldsRight": []
        },
    

    'Скрин'

     

    post-36429-0-60917200-1466965319_thumb.png

     

    'Иконки - атлас'

     

    contour.xml

     

    post-36429-0-78215100-1466965363_thumb.png

     

  20. Не будет, и не надо. Есть экстраполя, их достаточно для переходного периода.

     

    Да в экстраполях нормально все подгружается, но если посоветовать вашему совету

     

    На самом деле атлас - хорошая штука в плане оптимизации, да и обмениваться иконками проще - всего 2 файла. Потенциал атласа еще долго будет раскрываться, но мне решение нравится.

     

    и сделать все иконки через атласы с помощью конвертора от ktulho - размером 80х24, подгрузить их и отключить зеркалирование то левые и правые уши получаются разной ширины.

  21. Мне пока не все нравится в твоем варианте - теряется интерактивность.

     

    Так функционал то не должен измениться если в дефолтном конфиге прописаны все фильтры будут, но у юзера будет возможность настройки под себя.

    Но я лишь предложил свой вариант, и вставил свои "пять копеек".

×
×
  • Create New...