Ejemplo n.º 1
0
class LootBoxNotification(object):
    _settingsCore = dependency.descriptor(ISettingsCore)
    _itemsCache = dependency.descriptor(IItemsCache)
    _temp_storage = defaultdict(dict)

    @classmethod
    def hasNewBox(cls, boxType, category=''):
        count = cls.__getInventoryCount(boxType, category)
        settingsCount = cls.__getNewCount(boxType, category)
        return count > settingsCount

    @classmethod
    def hasDeliveredBox(cls, category):
        count = cls.__getInventoryCount(NewYearLootBoxes.PREMIUM, category)
        settingsCount = cls.__getCategoryDeliveredCount(category)
        return count > settingsCount

    @classmethod
    def setCategoryNewCount(cls, boxType, category=''):
        count = cls.__getInventoryCount(boxType, category)
        cls.__setCategoryNewCount(boxType, category, count)

    @classmethod
    def setCategoryDeliveredCount(cls, category):
        count = cls.__getInventoryCount(NewYearLootBoxes.PREMIUM, category)
        cls.__setCategoryDeliveredCount(category, count)

    @classmethod
    def setTotalLootBoxesCount(cls, count):
        cls._temp_storage[SETTINGS_SECTIONS.LOOT_BOX_VIEWED]['count'] = count

    @classmethod
    def saveSettings(cls):
        for section, settings in cls._temp_storage.iteritems():
            cls._settingsCore.serverSettings.setSectionSettings(
                section, settings)

        cls.__resetTempStorage()

    @classmethod
    def __resetTempStorage(cls):
        cls._temp_storage.clear()

    @classmethod
    def __getInventoryCount(cls, boxType, category=''):
        count = 0
        for lootBox in cls._itemsCache.items.tokens.getLootBoxes().itervalues(
        ):
            if lootBox.getCategory() == category and lootBox.getType(
            ) == boxType:
                count += lootBox.getInventoryCount()

        return count

    @classmethod
    def __getNewCount(cls, boxType, category=''):
        if boxType == NewYearLootBoxes.PREMIUM:
            return cls.__getCategorySettingCount(
                category, NYLootBoxesStorageKeys.NEW_COUNT)
        return cls.__getCategorySettingCount(
            NewYearLootBoxes.COMMON, NYLootBoxesStorageKeys.NEW_COUNT
        ) if boxType == NewYearLootBoxes.COMMON else None

    @classmethod
    def __getCategoryDeliveredCount(cls, category):
        return cls.__getCategorySettingCount(
            category, NYLootBoxesStorageKeys.DELIVERED_COUNT)

    @classmethod
    def __getCategorySettingCount(cls, category, settingKey):
        settingName = _SETTINGS_MAP.get(category)
        if settingName is None:
            _logger.error(
                'Failed to get serverSettings: [%s] for lootboxes category: [%s]',
                settingKey, category)
            return 0
        else:
            categorySettings = cls._temp_storage[settingName]
            if settingKey not in categorySettings:
                count = cls._settingsCore.serverSettings.getSectionSettings(
                    settingName, settingKey, 0)
                categorySettings[settingKey] = count
            return cls._temp_storage[settingName][settingKey]

    @classmethod
    def __setCategoryNewCount(cls, boxType, category, count):
        if boxType == NewYearLootBoxes.PREMIUM:
            cls.__setCategorySettingCount(category,
                                          NYLootBoxesStorageKeys.NEW_COUNT,
                                          count)
        elif boxType == NewYearLootBoxes.COMMON:
            cls.__setCategorySettingCount(NewYearLootBoxes.COMMON,
                                          NYLootBoxesStorageKeys.NEW_COUNT,
                                          count)

    @classmethod
    def __setCategoryDeliveredCount(cls, category, count):
        cls.__setCategorySettingCount(category,
                                      NYLootBoxesStorageKeys.DELIVERED_COUNT,
                                      count)

    @classmethod
    def __setCategorySettingCount(cls, category, settingKey, count):
        settingName = _SETTINGS_MAP.get(category)
        if settingName is not None:
            cls._temp_storage[settingName][settingKey] = count
        else:
            _logger.error(
                'Failed to set serverSettings: [%s] for lootboxes category: [%s]',
                settingKey, category)
        return
Ejemplo n.º 2
0
class VehicleModulesWindow(VehicleModulesWindowMeta):
    comparisonBasket = dependency.descriptor(IVehicleComparisonBasket)

    def __init__(self, ctx=None):
        super(VehicleModulesWindow, self).__init__()
        self.__vehIntCD = ctx['vehCD']
        self.__vehIndex = ctx['index']
        self.__nodes = None
        self.__vehicle = None
        self.__nodeDataGenerator = None
        self.__currentModulesType = None
        return

    def _populate(self):
        super(VehicleModulesWindow, self)._populate()
        basketVehicle = self.comparisonBasket.getVehicleAt(self.__vehIndex)
        self.__initialize(basketVehicle.getVehicleStrCD(),
                          basketVehicle.getModulesType())
        self.as_setAttentionVisibleS(basketVehicle.isInInventory()
                                     and not basketVehicle.isActualModules())
        stockVehicle = Vehicle(basketVehicle.getStockVehStrCD())
        self.__modulesInstaller = _ModulesInstaller(
            getInstalledModulesCDs(stockVehicle))
        self.comparisonBasket.onSwitchChange += self.onWindowClose
        self.as_setInitDataS({
            'windowTitle':
            _ms(VEH_COMPARE.MODULESVIEW_WINDOWTITLE,
                vehName=stockVehicle.userName),
            'description':
            text_styles.main(_ms(VEH_COMPARE.MODULESVIEW_DESCRIPTION)),
            'resetBtnLabel':
            VEH_COMPARE.MODULESVIEW_RESETBTNLABEL,
            'closeBtnLabel':
            VEH_COMPARE.MODULESVIEW_CLOSEBTNLABEL,
            'compareBtnLabel':
            VEH_COMPARE.MODULESVIEW_COMPAREBTNLABEL,
            'resetBtnTooltip':
            VEH_COMPARE.MODULESVIEW_RESETBTNLABEL_TOOLTIP,
            'closeBtnTooltip':
            VEH_COMPARE.MODULESVIEW_CLOSEBTNLABEL_TOOLTIP,
            'compareBtnTooltip':
            VEH_COMPARE.MODULESVIEW_COMPAREBTNLABEL_TOOLTIP
        })

    def _dispose(self):
        self.comparisonBasket.onSwitchChange -= self.onWindowClose
        self.__vehicle = None
        self.__modulesInstaller.dispose()
        self.__modulesInstaller = None
        if self.__nodeDataGenerator:
            self.__nodeDataGenerator.clear(True)
            self.__nodeDataGenerator = None
        super(VehicleModulesWindow, self)._dispose()
        return

    def onWindowClose(self):
        self.destroy()

    def onResetBtnBtnClick(self):
        def __logModuleWarning():
            LOG_WARNING(
                'Unable to apply the following modules type: {}'.format(
                    self.__currentModulesType))

        def __logModuleError():
            LOG_ERROR('Attempt to apply unsupported modules type: {}'.format(
                self.__currentModulesType))

        basketVehicle = self.comparisonBasket.getVehicleAt(self.__vehIndex)
        if basketVehicle.isInInventory():
            if self.__currentModulesType == MODULES_TYPES.CUSTOM or self.__currentModulesType == MODULES_TYPES.BASIC:
                self.__initialize(basketVehicle.getInvVehStrCD(),
                                  MODULES_TYPES.CURRENT)
            elif self.__currentModulesType == MODULES_TYPES.CURRENT:
                __logModuleWarning()
            else:
                __logModuleError()
        elif self.__currentModulesType == MODULES_TYPES.CUSTOM:
            self.__initialize(basketVehicle.getStockVehStrCD(),
                              MODULES_TYPES.BASIC)
        elif self.__currentModulesType == MODULES_TYPES.BASIC:
            __logModuleWarning()
        else:
            __logModuleError()

    def onCompareBtnClick(self):
        self.comparisonBasket.applyModulesFromVehicle(self.__vehIndex,
                                                      self.__vehicle)
        self.destroy()

    def onModuleHover(self, moduleId):
        moduleId = int(moduleId)
        if moduleId:
            allConflicted = self.__modulesInstaller.updateConflicted(
                moduleId, self.__vehicle)
            changedNodesStates = []
            for modulesByType in allConflicted:
                for conflictedIntCD in modulesByType:
                    for mData in self.__nodes:
                        if mData['id'] == conflictedIntCD:
                            mData['state'] |= NODE_STATE_FLAGS.DASHED
                            changedNodesStates.append(
                                (conflictedIntCD, mData['state']))

            if changedNodesStates:
                self.as_setNodesStatesS(changedNodesStates)
        else:
            allConflicted = self.__modulesInstaller.getConflictedModules()
            if allConflicted:
                changedNodesStates = []
                for modulesByType in allConflicted:
                    for conflictedIntCD in modulesByType:
                        for mData in self.__nodes:
                            if mData['id'] == conflictedIntCD:
                                mData['state'] &= ~NODE_STATE_FLAGS.DASHED
                                changedNodesStates.append(
                                    (conflictedIntCD, mData['state']))

                self.__modulesInstaller.clearConflictedModules()
                self.as_setNodesStatesS(changedNodesStates)

    @process
    def onModuleClick(self, moduleId):
        moduleId = int(moduleId)
        newComponentItem = _getModule(moduleId)
        isMainFit, mainReason = newComponentItem.mayInstall(self.__vehicle)
        if isMainFit:
            yield getPreviewInstallerProcessor(self.__vehicle,
                                               newComponentItem).request()
        conflictedModules = self.__modulesInstaller.getConflictedModules()
        if self.__modulesInstaller.hasConflicted():
            for modulesByType in conflictedModules:
                for moduleCD in modulesByType:
                    conflictedModule = _getModule(moduleCD)
                    yield getPreviewInstallerProcessor(
                        self.__vehicle, conflictedModule).request()

        if not isMainFit:
            yield getPreviewInstallerProcessor(self.__vehicle,
                                               newComponentItem).request()
        self.__updateChangedSlots()
        self.__updateModulesType(
            self.comparisonBasket.getVehicleAt(self.__vehIndex).getModulesType(
                strCD=self.__vehicle.descriptor.makeCompactDescr()))

    def __initialize(self, strCD, modulesType):
        self.__vehicle = Vehicle(strCD)
        if self.__nodeDataGenerator is not None:
            self.__nodeDataGenerator.setVehicle(vehicle=self.__vehicle)
        else:
            if USE_XML_DUMPING and IS_DEVELOPMENT:
                dumper = dumpers.ResearchItemsXMLDumper()
            else:
                dumper = dumpers.ResearchBaseDumper()
            self.__nodeDataGenerator = _PreviewItemsData(
                dumper, self.__vehicle)
        self.__updateModulesData()
        self.as_setItemS(AVAILABLE_NAMES[self.__vehicle.nationID],
                         self.__nodes)
        self.__updateModulesType(modulesType)
        return

    def __updateChangedSlots(self):
        def __extractData(targetList):
            return dict(
                map(lambda moduleData: (moduleData['id'], moduleData['state']),
                    targetList))

        oldModulesData = __extractData(self.__nodes)
        self.__updateModulesData()
        newModulesData = __extractData(self.__nodes)
        changedSlots = []
        for k, v in newModulesData.iteritems():
            if v != oldModulesData[k]:
                changedSlots.append((k, v))

        self.as_setNodesStatesS(changedSlots)

    def __updateModulesData(self):
        self.__nodeDataGenerator.load()
        dump = self.__nodeDataGenerator.dump()
        self.__nodes = dump['nodes']

    def __updateModulesType(self, modulesType):
        self.__currentModulesType = modulesType
        basketVehicle = self.comparisonBasket.getVehicleAt(self.__vehIndex)
        if basketVehicle.isInInventory():
            btnEnabled = modulesType != MODULES_TYPES.CURRENT
        else:
            btnEnabled = modulesType != MODULES_TYPES.BASIC
        self.as_setStateS(stateText=text_styles.neutral(
            _ms('#veh_compare:modulesView/moduleSet/{}'.format(modulesType))),
                          stateEnabled=btnEnabled)
Ejemplo n.º 3
0
class InternalLinksHandler(IInternalLinksController):
    browserCtrl = dependency.descriptor(IBrowserController)

    def __init__(self):
        super(InternalLinksHandler, self).__init__()
        self.__urlMarcos = None
        self._browserID = None
        return

    def init(self):
        self.__urlMarcos = URLMarcos()
        addListener = g_eventBus.addListener
        for eventType, handlerName in _LISTENERS.iteritems():
            handler = getattr(self, handlerName, None)
            if not handler:
                LOG_ERROR('Handler is not found', eventType, handlerName)
                continue
            if not callable(handler):
                LOG_ERROR('Handler is invalid', eventType, handlerName,
                          handler)
                continue
            addListener(eventType, handler)

        return

    def fini(self):
        if self.__urlMarcos is not None:
            self.__urlMarcos.clear()
            self.__urlMarcos = None
        self._browserID = None
        removeListener = g_eventBus.removeListener
        for eventType, handlerName in _LISTENERS.iteritems():
            handler = getattr(self, handlerName, None)
            if handler:
                removeListener(eventType, handler)

        super(InternalLinksHandler, self).fini()
        return

    @async
    @process
    def getURL(self, name, callback):
        urlSettings = GUI_SETTINGS.lookup(name)
        if urlSettings:
            url = yield self.__urlMarcos.parse(str(urlSettings))
        else:
            url = yield lambda callback: callback('')
        callback(url)

    @process
    def __openInternalBrowse(self,
                             urlName,
                             title='',
                             browserSize=None,
                             showActionBtn=True,
                             showCloseBtn=False):
        parsedUrl = yield self.getURL(urlName)
        if parsedUrl:
            self._browserID = yield self.browserCtrl.load(
                parsedUrl,
                browserID=self._browserID,
                title=title,
                browserSize=browserSize,
                showActionBtn=showActionBtn,
                showCloseBtn=showCloseBtn)
Ejemplo n.º 4
0
class PersonalMissionDetailsContainerView(
        LobbySubView, PersonalMissionDetailsContainerViewMeta):
    eventsCache = dependency.descriptor(IEventsCache)
    __metaclass__ = event_bus_handlers.EventBusListener

    def __init__(self, ctx=None):
        super(PersonalMissionDetailsContainerView, self).__init__(ctx)
        self.__selectedQuestID = 0
        self._initialize(ctx)
        self.__quests = self.__getQuests()
        quest = self.__quests.get(self.__selectedQuestID)
        mayPawn = self.eventsCache.random.getFreeTokensCount(
        ) >= quest.getPawnCost() and quest.canBePawned()
        self.__storage = getTutorialGlobalStorage()
        if self.__storage:
            self.__storage.setValue(MAY_PAWN_PERSONAL_MISSION, mayPawn)

    def closeView(self):
        self.destroy()

    def useSheet(self, eventID):
        self._pawnMission(eventID)

    def startMission(self, eventID):
        self._processMission(eventID)

    def obtainAward(self, eventID):
        LOG_ERROR(
            'Award obtain from personal mission details view is not available.'
        )

    def onChangePage(self, eventID):
        self.__selectedQuestID = int(eventID)
        quest = self.__quests.get(self.__selectedQuestID)
        mayPawn = self.eventsCache.random.getFreeTokensCount(
        ) >= quest.getPawnCost() and quest.canBePawned()
        if self.__storage:
            self.__storage.setValue(MAY_PAWN_PERSONAL_MISSION, mayPawn)
        vehicleSelector = self.components.get(
            QUESTS_ALIASES.PERSONAL_MISSIONS_VEHICLE_SELECTOR_ALIAS)
        criteria, extraConditions = getDetailedMissionData(
            quest).getVehicleRequirementsCriteria()
        vehicleSelector.as_closeS()
        vehicleSelector.setSelectedQuest(self.__selectedQuestID)
        if criteria and quest.isInProgress() and quest.isAvailable()[0]:
            vehicleSelector.setCriteria(criteria, extraConditions)
        else:
            vehicleSelector.as_hideSelectedVehicleS()

    def declineMission(self, eventID):
        self._declineMission(eventID)

    def retryMission(self, eventID):
        self._processMission(eventID)

    def _initialize(self, ctx=None):
        ctx = ctx or {}
        self.__selectedQuestID = int(ctx.get('eventID', 0))

    @decorators.process('updating')
    def _processMission(self, eventID):
        quest = events_helpers.getPersonalMissionsCache().getQuests()[int(
            eventID)]
        result = yield events_helpers.getPersonalMissionsSelectProcessor()(
            quest, events_helpers.getPersonalMissionsCache()).request()
        if result and result.userMsg:
            SystemMessages.pushMessage(result.userMsg, type=result.sysMsgType)

    @decorators.process('updating')
    def _declineMission(self, eventID):
        result = yield events_helpers.getPersonalMissionsRefuseProcessor()(
            events_helpers.getPersonalMissionsCache().getQuests()[int(
                eventID)],
            events_helpers.getPersonalMissionsCache()).request()
        if result.userMsg:
            SystemMessages.pushMessage(result.userMsg, type=result.sysMsgType)

    @decorators.process('updating')
    def _pawnMission(self, eventID):
        quest = events_helpers.getPersonalMissionsCache().getQuests()[int(
            eventID)]
        result = yield events_helpers.getPersonalMissionsPawnProcessor()(
            quest).request()
        if result and result.userMsg:
            SystemMessages.pushMessage(result.userMsg, type=result.sysMsgType)

    def _populate(self):
        super(PersonalMissionDetailsContainerView, self)._populate()
        self.eventsCache.onSyncCompleted += self.__setData
        self.eventsCache.onProgressUpdated += self._onProgressUpdated
        self.__setData()

    def _invalidate(self, ctx=None):
        self._initialize(ctx)
        self.__setData()

    def _dispose(self):
        super(PersonalMissionDetailsContainerView, self)._dispose()
        self.eventsCache.onSyncCompleted -= self.__setData
        self.eventsCache.onProgressUpdated -= self._onProgressUpdated
        self.__storage = None
        self.__quests = None
        return

    def _onProgressUpdated(self, _):
        self.__quests = self.__getQuests()
        self.__setData()

    @event_bus_handlers.eventBusHandler(
        events.HideWindowEvent.HIDE_PERSONAL_MISSION_DETAILS_VIEW,
        EVENT_BUS_SCOPE.LOBBY)
    def __handleDetailsClose(self, _):
        self.closeView()

    def __getQuests(self):
        selectedQuest = self.eventsCache.personalMissions.getQuests().get(
            self.__selectedQuestID, None)
        tile = self.eventsCache.personalMissions.getOperations()[
            selectedQuest.getOperationID()]
        quests = tile.getQuestsByFilter(lambda q: bool(
            selectedQuest.getVehicleClasses() & q.getVehicleClasses()))
        return quests

    def __setData(self):
        datailedList = []
        for _, q in enumerate(
                sorted(self.__quests.itervalues(), key=methodcaller('getID'))):
            datailedList.append(getDetailedMissionData(q).getInfo())

        pages = map(
            lambda (i, mission): {
                'buttonsGroup': 'MissionDetailsPageGroup',
                'pageIndex': i,
                'label': '%i' % (i + 1),
                'tooltip': {
                    'isSpecial': True,
                    'specialAlias': TOOLTIPS_CONSTANTS.
                    PERSONAL_MISSIONS_MAP_REGION,
                    'specialArgs': [int(mission.get('eventID')), 0]
                },
                'status': mission.get('status'),
                'selected': self.__selectedQuestID == int(
                    mission.get('eventID'))
            }, enumerate(datailedList))
        self.as_setInitDataS({
            'title': 'Title',
            'missions': datailedList,
            'pages': pages
        })
Ejemplo n.º 5
0
class ChannelsCarouselHandler(object):
    __platoonCtrl = dependency.descriptor(IPlatoonController)

    def __init__(self, guiEntry):
        super(ChannelsCarouselHandler, self).__init__()
        self.__guiEntry = guiEntry
        self.__channelsDP = None
        self.__preBattleChannelsDP = None
        self.__handlers = {}
        self.__showByReqs = {}
        self.__notifiedMessages = {}
        return

    @sf_lobby
    def app(self):
        return None

    def init(self):
        self.__channelsDP = ChannelsDataProvider()
        self.__preBattleChannelsDP = ChannelsDataProvider()
        add = g_eventBus.addListener
        add(ChannelManagementEvent.REQUEST_TO_ADD,
            self.__handleRequestToAdd,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(PreBattleChannelEvent.REQUEST_TO_ADD_PRE_BATTLE_CHANNEL,
            self.__handleRequestToAddPrebattle,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(PreBattleChannelEvent.REQUEST_TO_REMOVE_PRE_BATTLE_CHANNEL,
            self.__handleRequestToRemovePreBattle,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelManagementEvent.REQUEST_TO_REMOVE,
            self.__handleRequestToRemove,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelManagementEvent.REQUEST_TO_CHANGE,
            self.__handleRequestToChange,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelManagementEvent.REQUEST_TO_SHOW,
            self.__handleRequestToShow,
            scope=EVENT_BUS_SCOPE.LOBBY)

    def clear(self):
        self.__guiEntry = None
        self.__handlers.clear()
        self.__notifiedMessages.clear()
        if self.__channelsDP is not None:
            self.__channelsDP.clear()
            self.__channelsDP.finiGUI()
            self.__channelsDP = None
        if self.__preBattleChannelsDP is not None:
            self.__preBattleChannelsDP.clear()
            self.__preBattleChannelsDP.finiGUI()
            self.__preBattleChannelsDP = None
        remove = g_eventBus.removeListener
        remove(ChannelManagementEvent.REQUEST_TO_ADD,
               self.__handleRequestToAdd,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(PreBattleChannelEvent.REQUEST_TO_ADD_PRE_BATTLE_CHANNEL,
               self.__handleRequestToAddPrebattle,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(PreBattleChannelEvent.REQUEST_TO_REMOVE_PRE_BATTLE_CHANNEL,
               self.__handleRequestToRemovePreBattle,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelManagementEvent.REQUEST_TO_REMOVE,
               self.__handleRequestToRemove,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelManagementEvent.REQUEST_TO_CHANGE,
               self.__handleRequestToChange,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelManagementEvent.REQUEST_TO_SHOW,
               self.__handleRequestToShow,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelCarouselEvent.CAROUSEL_DESTROYED,
               self.__handleCarouselDestroyed,
               scope=EVENT_BUS_SCOPE.LOBBY)
        return

    def start(self):
        add = g_eventBus.addListener
        add(ChannelCarouselEvent.CAROUSEL_INITED,
            self.__handleCarouselInited,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelCarouselEvent.OPEN_BUTTON_CLICK,
            self.__handleOpenButtonClick,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelCarouselEvent.MINIMIZE_ALL_CHANNELS,
            self.__handlerMinimizeAll,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelCarouselEvent.CLOSE_ALL_EXCEPT_CURRENT,
            self.__handlerCloseAllExceptCurrent,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelCarouselEvent.CLOSE_BUTTON_CLICK,
            self.__handleCloseButtonClick,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelCarouselEvent.ON_WINDOW_CHANGE_FOCUS,
            self.__handleOnWindowChangeFocus,
            scope=EVENT_BUS_SCOPE.LOBBY)
        add(ChannelCarouselEvent.ON_WINDOW_CHANGE_OPEN_STATE,
            self.__handleOnWindowChangeOpenState,
            scope=EVENT_BUS_SCOPE.LOBBY)

    def stop(self):
        remove = g_eventBus.removeListener
        remove(ChannelCarouselEvent.CAROUSEL_INITED,
               self.__handleCarouselInited,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelCarouselEvent.OPEN_BUTTON_CLICK,
               self.__handleOpenButtonClick,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelCarouselEvent.MINIMIZE_ALL_CHANNELS,
               self.__handlerMinimizeAll,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelCarouselEvent.CLOSE_ALL_EXCEPT_CURRENT,
               self.__handlerCloseAllExceptCurrent,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelCarouselEvent.CLOSE_BUTTON_CLICK,
               self.__handleCloseButtonClick,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelCarouselEvent.ON_WINDOW_CHANGE_FOCUS,
               self.__handleOnWindowChangeFocus,
               scope=EVENT_BUS_SCOPE.LOBBY)
        remove(ChannelCarouselEvent.ON_WINDOW_CHANGE_OPEN_STATE,
               self.__handleOnWindowChangeOpenState,
               scope=EVENT_BUS_SCOPE.LOBBY)
        self.__showByReqs.clear()

    def addChannel(self, channel, lazy=False, isNotified=False):
        clientID = channel.getClientID()
        isSystem = channel.isSystem()
        if lazy:
            order = channel_num_gen.getOrder4LazyChannel(channel.getName())
            openHandler = lambda: events_dispatcher.showLazyChannelWindow(
                clientID)
        else:
            order = channel_num_gen.genOrder4Channel(channel)
            openHandler = lambda: events_dispatcher.showLobbyChannelWindow(
                clientID)
        self.__handlers[clientID] = (ChannelFindCriteria(clientID),
                                     openHandler, WindowLayer.WINDOW)
        self.__channelsDP.addItem(
            clientID, {
                'label': channel.getFullName(),
                'canClose': not isSystem,
                'isNotified': isNotified,
                'icon': None,
                'order': order,
                'isInProgress': False
            })
        return

    def removeChannel(self, channel):
        clientID = channel.getClientID()
        if clientID in self.__handlers:
            criteria, _, layer = self.__handlers.pop(clientID)
            window = None
            app = self.app
            if app is not None and app.containerManager is not None:
                window = app.containerManager.getView(layer, criteria)
            if window is not None:
                window.destroy()
        self.__channelsDP.removeItem(clientID)
        return

    def notifyChannel(self, channel, message):
        clientID = channel.getClientID()
        self.__setItemField(clientID, 'isNotified', True)
        if clientID not in self.__notifiedMessages:
            self.__notifiedMessages[clientID] = []
        notifiedMessages = self.__notifiedMessages[clientID]
        notifiedMessages.append(message)

    def __setItemField(self, clientID, key, value):
        result = self.__preBattleChannelsDP.setItemField(clientID, key, value)
        if not result:
            result = self.__channelsDP.setItemField(clientID, key, value)
        return result

    def updateChannel(self, channel):
        self.__setItemField(channel.getClientID(), 'label',
                            channel.getFullName())

    def removeChannels(self):
        if self.__channelsDP is not None:
            self.__channelsDP.clear()
        if self.__preBattleChannelsDP is not None:
            self.__preBattleChannelsDP.clear()
        self.__handlers.clear()
        self.__showByReqs.clear()
        self.__notifiedMessages.clear()
        return

    def __handleCarouselInited(self, event):
        carousel = event.target
        if isinstance(carousel, ChannelCarouselMeta):
            self.__channelsDP.initGUI(carousel.as_getDataProviderS())
            self.__preBattleChannelsDP.initGUI(
                carousel.as_getBattlesDataProviderS())
            g_eventBus.addListener(ChannelCarouselEvent.CAROUSEL_DESTROYED,
                                   self.__handleCarouselDestroyed,
                                   scope=EVENT_BUS_SCOPE.LOBBY)
        else:
            LOG_ERROR('Channel carousel must be extends ChannelCarouselMeta',
                      carousel)

    def __handleCarouselDestroyed(self, _):
        self.__channelsDP.finiGUI()
        self.__preBattleChannelsDP.finiGUI()
        g_eventBus.removeListener(ChannelCarouselEvent.CAROUSEL_DESTROYED,
                                  self.__handleCarouselDestroyed,
                                  scope=EVENT_BUS_SCOPE.LOBBY)

    def __handleRequestToAddPrebattle(self, event):
        self.__adjustAndAddChannel(event, self.__preBattleChannelsDP)

    def __handleRequestToAdd(self, event):
        self.__adjustAndAddChannel(event, self.__channelsDP)

    def __adjustAndAddChannel(self, event, targetList):
        ctx = event.ctx
        label = ctx.get('label')
        if label is None:
            LOG_ERROR('Label is not defined', event.ctx)
            return
        else:
            criteria = ctx.get('criteria')
            if criteria is None:
                LOG_ERROR('Criteria is not defined', event.ctx)
                return
            openHandler = ctx.get('openHandler')
            if openHandler is None:
                LOG_ERROR('Open handler is not defined', event.ctx)
                return
            layer = ctx.get('layer')
            if layer is None:
                LOG_ERROR('View type is not defined', event.ctx)
                return
            clientID = event.clientID
            if clientID not in self.__handlers:
                self.__handlers[clientID] = (criteria, openHandler, layer)
                targetList.addItem(clientID, ctx)
            return

    def __handleRequestToRemovePreBattle(self, event):
        self.__removeChannelFromList(event, self.__preBattleChannelsDP)

    def __handleRequestToRemove(self, event):
        self.__removeChannelFromList(event, self.__channelsDP)

    def __removeChannelFromList(self, event, targetList):
        clientID = event.clientID
        if clientID in self.__handlers:
            criteria, _, layer = self.__handlers.pop(clientID)
            if event.ctx.get('closeWindow', True) and self.app is not None:
                window = self.app.containerManager.getView(layer, criteria)
                if window is not None:
                    window.destroy()
            targetList.removeItem(clientID)
            self.__showByReqs.pop(clientID, None)
        return

    def __handleRequestToChange(self, event):
        ctx = event.ctx
        key = ctx.get('key')
        if key is None:
            LOG_ERROR('Key of item field is not defined', ctx)
            return
        else:
            value = ctx.get('value')
            if value is None:
                LOG_ERROR('Value of item field is not defined', ctx)
                return
            clientID = event.clientID
            if 'isShowByReq' in ctx and ctx['isShowByReq'] is True:
                self.__showByReqs[clientID] = (key, value)
                isShow = ctx.get('showIfClosed', False)
                if isShow:
                    if clientID not in self.__handlers:
                        return
                    criteria, _, layer = self.__handlers[clientID]
                    window = self.app.containerManager.getView(layer, criteria)
                    if window is None:
                        if not self.__setItemField(clientID, key, value):
                            self.__showByReqs.pop(clientID)
            else:
                self.__setItemField(clientID, key, value)
                self.__showByReqs.pop(clientID, None)
            return

    def __handleRequestToShow(self, event):
        ctx = event.ctx
        show = ctx.get('show')
        if show is None:
            LOG_ERROR('Flag "show" is not defined', ctx)
            return
        else:
            clientID = event.clientID
            if not clientID:
                return
            if clientID in self.__showByReqs:
                key, value = self.__showByReqs[clientID]
                if show:
                    if not self.__setItemField(clientID, key, value):
                        self.__showByReqs.pop(clientID)
                elif not self.__channelsDP.clearItemField(clientID, key):
                    if not self.__preBattleChannelsDP.clearItemField(
                            clientID, key):
                        self.__showByReqs.pop(clientID)
            return

    def __handleOpenButtonClick(self, event):
        clientID = event.clientID
        if not clientID:
            return
        elif clientID not in self.__handlers:
            return
        else:
            criteria, openHandler, layer = self.__handlers[clientID]
            viewContainer = self.app.containerManager
            if layer == WindowLayer.WINDOW:
                window = viewContainer.getView(layer, criteria)
                if window is not None:
                    wName = window.uniqueName
                    isOnTop = viewContainer.as_isOnTopS(
                        WindowLayer.WINDOW, wName)
                    if not isOnTop:
                        viewContainer.as_bringToFrontS(WindowLayer.WINDOW,
                                                       wName)
                    else:
                        window.onWindowMinimize()
                    return
            elif layer == WindowLayer.SUB_VIEW:
                view = viewContainer.getView(layer, criteria)
                if hasattr(view, 'onWindowMinimize') and callable(
                        getattr(view, 'onWindowMinimize')):
                    view.onWindowMinimize()
                    return
            fields = {'isNotified': False, 'isInProgress': False}
            if not self.__channelsDP.setItemFields(clientID, fields):
                self.__preBattleChannelsDP.setItemFields(clientID, fields)
            if clientID in self.__notifiedMessages:
                notifiedMessages = self.__notifiedMessages[clientID]
                channel = self.__guiEntry.channelsCtrl.getController(
                    clientID).getChannel()
                for message in notifiedMessages:
                    channel.setMessageShown(message)

            openHandler()
            return

    def __handlerMinimizeAll(self, _):
        for criteria, _, layer in self.__handlers.itervalues():
            viewContainer = self.app.containerManager
            if isinstance(criteria, ChannelFindCriteria):
                window = viewContainer.getView(layer, criteria)
                if window is not None:
                    window.onWindowMinimize()

        return

    def __handlerCloseAllExceptCurrent(self, event):
        self.__closeExcept(event.clientID)

    def __closeExcept(self, clientID):
        clientIDs = self.__handlers.keys()
        for key in clientIDs:
            if key != clientID:
                cntrler = self.__guiEntry.channelsCtrl.getController(key)
                if cntrler is not None:
                    channel = cntrler.getChannel()
                    if not channel.isSystem():
                        self.__closeChannel(key)

        return

    def __handleCloseButtonClick(self, event):
        clientID = event.clientID
        channel = self.__guiEntry.channelsCtrl.getController(
            clientID).getChannel()
        if not channel.isSystem():
            self.__closeChannel(clientID)

    def __handleOnWindowChangeFocus(self, event):
        self.__updateItemField(event.clientID, event.wndType,
                               'isWindowFocused', event.flag)

    def __handleOnWindowChangeOpenState(self, event):
        self.__updateItemField(event.clientID, event.wndType, 'isWindowOpened',
                               event.flag)

    def __updateItemField(self, clientID, wndType, key, flag):
        if wndType is not None:
            if wndType == MESSENGER_CHANNEL_CAROUSEL_ITEM_TYPES.CHANNEL_CAROUSEL_ITEM_TYPE_MESSENGER:
                self.__channelsDP.setItemField(clientID, key, flag)
            elif wndType == MESSENGER_CHANNEL_CAROUSEL_ITEM_TYPES.CHANNEL_CAROUSEL_ITEM_TYPE_PREBATTLE:
                self.__preBattleChannelsDP.setItemField(clientID, key, flag)
        return

    def __closeChannel(self, clientID):
        if not clientID:
            return
        elif clientID not in self.__handlers:
            return
        else:
            self.__showByReqs.pop(clientID, None)
            viewContainer = self.app.containerManager
            criteria, _, layer = self.__handlers[clientID]
            if layer == WindowLayer.WINDOW:
                window = viewContainer.getView(layer, criteria)
                if window is not None:
                    window.onWindowClose()
                    return
            if self.__guiEntry:
                controller = self.__guiEntry.channelsCtrl.getController(
                    clientID)
                if controller:
                    controller.exit()
            return
Ejemplo n.º 6
0
class VehicleAnchorsUpdater(object):
    __hangarSpace = dependency.descriptor(IHangarSpace)
    __service = dependency.descriptor(ICustomizationService)
    __settingsCore = dependency.descriptor(ISettingsCore)

    def __init__(self, ctx):
        self.__ctx = ctx
        self.__vehicleCustomizationAnchors = None
        self.__processedAnchors = {}
        self.__menuSlotId = None
        self.__changedStates = {}
        self.__closeGroups = DisjointSet()
        return

    def startUpdater(self):
        if self.__vehicleCustomizationAnchors is None:
            interfaceScale = self.__settingsCore.interfaceScale.get()
            self.__vehicleCustomizationAnchors = GUI.WGVehicleCustomizationAnchors(
                interfaceScale)
            self.__ctx.events.onPropertySheetHidden += self.__onPropertySheetHidden
            self.__ctx.events.onPropertySheetShown += self.__onPropertySheetShown
            self.__ctx.events.onItemSelected += self.__onCarouselItemSelected
            self.__ctx.events.onItemUnselected += self.__onCarouselItemUnselected
            self.__ctx.events.onItemInstalled += self.__onItemInstalled
            self.__ctx.events.onItemsRemoved += self.__onItemsRemoved
            self.__ctx.events.onChangesCanceled += self.__onChangesCanceled
            self.__ctx.events.onSeasonChanged += self.__onSeasonChanged
            self.__ctx.events.onAnchorHovered += self.__onAnchorHovered
            self.__ctx.events.onAnchorUnhovered += self.__onAnchorUnhovered
            self.__settingsCore.interfaceScale.onScaleExactlyChanged += self.__onInterfaceScaleChanged
            entity = self.__hangarSpace.getVehicleEntity()
            if entity is not None and entity.appearance is not None:
                entity.appearance.loadState.subscribe(
                    self.__onVehicleLoadFinished, self.__onVehicleLoadStarted)
        return

    def stopUpdater(self):
        if self.__vehicleCustomizationAnchors is not None:
            self.__ctx.events.onPropertySheetHidden -= self.__onPropertySheetHidden
            self.__ctx.events.onPropertySheetShown -= self.__onPropertySheetShown
            self.__ctx.events.onItemSelected -= self.__onCarouselItemSelected
            self.__ctx.events.onItemUnselected -= self.__onCarouselItemUnselected
            self.__ctx.events.onItemInstalled -= self.__onItemInstalled
            self.__ctx.events.onItemsRemoved -= self.__onItemsRemoved
            self.__ctx.events.onChangesCanceled -= self.__onChangesCanceled
            self.__ctx.events.onSeasonChanged -= self.__onSeasonChanged
            self.__ctx.events.onAnchorHovered -= self.__onAnchorHovered
            self.__ctx.events.onAnchorUnhovered -= self.__onAnchorUnhovered
            self.__settingsCore.interfaceScale.onScaleExactlyChanged -= self.__onInterfaceScaleChanged
            entity = self.__hangarSpace.getVehicleEntity()
            if entity is not None and entity.appearance is not None:
                entity.appearance.loadState.unsubscribe(
                    self.__onVehicleLoadFinished, self.__onVehicleLoadStarted)
            self.__delAllAnchors()
            self.__vehicleCustomizationAnchors = None
        return

    def setAnchors(self, displayObjects):
        if self.__vehicleCustomizationAnchors is None:
            _logger.error('Missing WGVehicleCustomizationAnchors.')
            return
        else:
            self.__delAllAnchors()
            modeId = self.__ctx.modeId
            tabId = self.__ctx.mode.tabId
            styleSlot = C11nId(areaId=Area.MISC,
                               slotType=GUI_ITEM_TYPE.STYLE,
                               regionIdx=0)
            styleAnchorParams = self.__ctx.mode.getAnchorParams(styleSlot)
            for displayObject in displayObjects:
                if not hasattr(displayObject, 'slotData'):
                    _logger.error(
                        'Incorrect anchor displayObject. Missing slotData section. %s',
                        displayObject)
                    continue
                slotData = displayObject.slotData
                slotId = C11nId(areaId=slotData.slotId.areaId,
                                slotType=slotData.slotId.slotType,
                                regionIdx=slotData.slotId.regionIdx)
                anchorParams = self.__ctx.mode.getAnchorParams(slotId)
                if anchorParams is None:
                    _logger.error('Failed to get anchor params for slotId: %s',
                                  slotId)
                    continue
                if modeId == CustomizationModes.EDITABLE_STYLE and slotId.slotType in EDITABLE_STYLE_APPLY_TO_ALL_AREAS_TYPES:
                    location = styleAnchorParams.location
                else:
                    location = anchorParams.location
                linesPosition = copy(location.position)
                slotWidth = 0.0
                if tabId in (CustomizationTabs.EMBLEMS,
                             CustomizationTabs.INSCRIPTIONS):
                    slotWidth = anchorParams.descriptor.size
                    slotHeight = slotWidth * SLOT_ASPECT_RATIO[slotId.slotType]
                    linesShift = slotHeight * _LINES_SHIFT
                    linesPosition -= location.up * linesShift
                position = location.position
                direction = location.normal
                uid = self.__vehicleCustomizationAnchors.addAnchor(
                    position, direction, linesPosition, slotWidth,
                    displayObject, True, True, False, True)
                anchor = Anchor(slotId, uid, position, direction)
                if slotId.slotType == GUI_ITEM_TYPE.PROJECTION_DECAL:
                    self.__closeGroups.add(slotId)
                    for aId, a in self.__processedAnchors.iteritems():
                        dist = (a.position - anchor.position).length
                        if dist < _MIN_PROJECTION_DECAL_ANCHORS_DIST:
                            self.__closeGroups.union(aId, slotId)

                self.__processedAnchors[slotId] = anchor
                anchor.setup()

            self.__changeAnchorsStates()
            self.__updateAnchorsVisability()
            return

    def setCollisions(self):
        entity = self.__hangarSpace.getVehicleEntity()
        if entity and entity.appearance and entity.appearance.isLoaded():
            collisions = entity.appearance.collisions
            if collisions is not None:
                self.__vehicleCustomizationAnchors.setCollisions(collisions)
            else:
                _logger.error(
                    'Collision component for current vehicle is missing.')
        else:
            _logger.error('Vehicle entity is not loaded/exist.')
        return

    def updateAnchorPositionAndNormal(self, slotId, position, normal):
        if slotId in self.__processedAnchors:
            anchor = self.__processedAnchors[slotId]
            self.__vehicleCustomizationAnchors.updateAnchorPositionAndNormal(
                anchor.uid, position, normal)

    def setAnchorShift(self, slotId, shift):
        if slotId in self.__processedAnchors:
            anchor = self.__processedAnchors[slotId]
            self.__vehicleCustomizationAnchors.setAnchorShift(
                anchor.uid, shift)

    def changeAnchorParams(self,
                           slotId,
                           isDisplayed,
                           isAutoScalable,
                           isCollidable=False,
                           isActive=True):
        if slotId in self.__processedAnchors:
            anchor = self.__processedAnchors[slotId]
            self.__vehicleCustomizationAnchors.changeAnchorParams(
                anchor.uid, isDisplayed, isAutoScalable, isCollidable,
                isActive)

    def setMenuParams(self, menuDisplayObject, menuWidth, menuHeight,
                      menuCenterX, menuCenterY):
        self.__vehicleCustomizationAnchors.setMenuParams(
            menuDisplayObject, menuWidth, menuHeight, menuCenterX, menuCenterY)

    def displayMenu(self, display):
        self.__vehicleCustomizationAnchors.displayMenu(display)

    def displayLine(self, display):
        self.__vehicleCustomizationAnchors.displayLine(display)

    def attachMenuToAnchor(self, slotId):
        if slotId in self.__processedAnchors:
            anchor = self.__processedAnchors[slotId]
            self.__vehicleCustomizationAnchors.attachMenuToAnchor(anchor.uid)

    def setMainView(self, displayObject):
        return self.__vehicleCustomizationAnchors.setMainView(displayObject)

    def hideAllAnchors(self):
        if self.__vehicleCustomizationAnchors is not None:
            for slotId in self.__processedAnchors:
                self.changeAnchorParams(slotId,
                                        isDisplayed=False,
                                        isAutoScalable=False)

        return

    def registerInscriptionController(self, inscriptionController, inputLines):
        self.__vehicleCustomizationAnchors.registerInscriptionController(
            inscriptionController, inputLines)

    def __delAllAnchors(self):
        if self.__vehicleCustomizationAnchors is not None:
            for anchor in self.__processedAnchors.itervalues():
                self.__vehicleCustomizationAnchors.delAnchor(anchor.uid)
                anchor.destroy()

            self.__processedAnchors.clear()
            self.__closeGroups.clear()
        return

    def __updateAnchorsVisability(self):
        if self.__ctx.mode.isRegion:
            self.__updateRegionsAnchorsVisability()
        elif self.__ctx.mode.tabId in (CustomizationTabs.EMBLEMS,
                                       CustomizationTabs.INSCRIPTIONS):
            self.__updateDecalAnchorsVisability()
        elif self.__ctx.mode.tabId == CustomizationTabs.PROJECTION_DECALS:
            self.__updateProjectionDecalAnchorsVisability()

    def __updateRegionsAnchorsVisability(self):
        outfit = self.__ctx.mode.currentOutfit
        for slotId in self.__processedAnchors:
            isDisplayed = isSlotFilled(outfit, slotId)
            isAutoScalable = self.__menuSlotId != slotId
            self.changeAnchorParams(slotId,
                                    isDisplayed=isDisplayed,
                                    isAutoScalable=isAutoScalable)

    def __updateDecalAnchorsVisability(self):
        for slotId in self.__processedAnchors:
            isDisplayed = slotId != self.__menuSlotId
            self.changeAnchorParams(slotId,
                                    isDisplayed=isDisplayed,
                                    isAutoScalable=True)

    def __updateProjectionDecalAnchorsVisability(self):
        formfactor = None
        item = self.__ctx.mode.selectedItem
        if item is not None:
            formfactor = item.formfactor
        visibleAnchors = defaultdict(set)
        outfit = self.__ctx.mode.currentOutfit
        for slotId in self.__processedAnchors:
            if isSlotFilled(outfit, slotId):
                isDisplayed = self.__menuSlotId != slotId
                self.changeAnchorParams(slotId,
                                        isDisplayed=isDisplayed,
                                        isAutoScalable=True)
                root = self.__closeGroups.find(slotId)
                if root is not None:
                    visibleAnchors[root].add(slotId)
                continue
            if formfactor is not None:
                anchor = g_currentVehicle.item.getAnchorBySlotId(
                    slotId.slotType, slotId.areaId, slotId.regionIdx)
                if anchor.isFitForFormfactor(formfactor):
                    self.changeAnchorParams(slotId,
                                            isDisplayed=True,
                                            isAutoScalable=True,
                                            isCollidable=True)
                    root = self.__closeGroups.find(slotId)
                    if root is not None:
                        visibleAnchors[root].add(slotId)
                    continue
            self.changeAnchorParams(slotId,
                                    isDisplayed=False,
                                    isAutoScalable=False)

        self.__spreadAnchorsApart(visibleAnchors)
        return

    def __spreadAnchorsApart(self, visibleAnchors):
        for slotIds in visibleAnchors.itervalues():
            anchorsCount = len(slotIds)
            if anchorsCount > 1:
                radius = _MIN_PROJECTION_DECAL_ANCHORS_DIST * 0.5 / math.sin(
                    math.pi / anchorsCount)
                position = sum(
                    (self.__processedAnchors[slotId].position
                     for slotId in slotIds), Vector3()) / anchorsCount
                direction = sum(
                    (self.__processedAnchors[slotId].direction
                     for slotId in slotIds), Vector3()) / anchorsCount
                transformMatrix = Math.Matrix()
                transformMatrix.lookAt(position, direction, (0, 1, 0))
                transformMatrix.invert()
                shift = Vector3(0, radius, 0)
                angle = 2 * math.pi / anchorsCount
                rotor = Math.Matrix()
                rotor.setRotateZ(angle)
                for slotId in sorted(slotIds, key=getProjectionSlotFormfactor):
                    anchor = self.__processedAnchors[slotId]
                    newPosition = transformMatrix.applyPoint(shift)
                    anchor.setShift(newPosition - anchor.position)
                    self.setAnchorShift(slotId, anchor.shift)
                    shift = rotor.applyPoint(shift)

            slotId = slotIds.pop()
            self.setAnchorShift(slotId, Vector3())

    def __onPropertySheetHidden(self):
        self.__menuSlotId = None
        self.__updateAnchorsVisability()
        return

    def __onPropertySheetShown(self, slotId):
        self.__menuSlotId = slotId
        self.__updateAnchorsVisability()

    def __onCarouselItemSelected(self, *_, **__):
        if self.__ctx.mode.tabId == CustomizationTabs.PROJECTION_DECALS:
            self.__updateAnchorsVisability()

    def __onCarouselItemUnselected(self, *_, **__):
        if self.__ctx.mode.tabId == CustomizationTabs.PROJECTION_DECALS:
            for anchor in self.__processedAnchors.itervalues():
                anchor.state.onItemUnselected()

            self.__changeAnchorsStates()
            self.__updateAnchorsVisability()

    def __onItemInstalled(self, item, slotId, season, component):
        anchor = self.__processedAnchors.get(slotId)
        if anchor is not None:
            anchor.state.onItemInstalled()
        outfit = self.__ctx.mode.currentOutfit
        if isItemsQuantityLimitReached(outfit, slotId.slotType):
            for anchor in self.__processedAnchors.itervalues():
                anchor.state.onLocked()

        self.__changeAnchorsStates()
        self.__updateAnchorsVisability()
        return

    def __onItemsRemoved(self, *_, **__):
        self.__updateAnchorsState()
        self.__updateAnchorsVisability()

    def __onChangesCanceled(self, *_, **__):
        self.__updateAnchorsState()
        self.__updateAnchorsVisability()

    def __onSeasonChanged(self, *_, **__):
        self.__updateAnchorsState()
        self.__updateAnchorsVisability()

    def __onAnchorHovered(self, slotId):
        if self.__ctx.mode.tabId != CustomizationTabs.PROJECTION_DECALS:
            return
        elif self.__ctx.mode.selectedItem is None:
            return
        else:
            anchor = self.__processedAnchors.get(slotId)
            if anchor is not None:
                item = self.__ctx.mode.getItemFromSlot(slotId)
                if item is not None and item.intCD == self.__ctx.mode.selectedItem.intCD:
                    return
                anchor.state.onHovered()
            self.__changeAnchorsStates()
            return

    def __onAnchorUnhovered(self, slotId):
        if self.__ctx.mode.tabId != CustomizationTabs.PROJECTION_DECALS:
            return
        elif self.__ctx.mode.selectedItem is None:
            return
        else:
            anchor = self.__processedAnchors.get(slotId)
            if anchor is not None:
                anchor.state.onUnhovered()
            self.__changeAnchorsStates()
            return

    def __updateAnchorsState(self):
        for anchor in self.__processedAnchors.itervalues():
            anchor.updateState()

        self.__changeAnchorsStates()

    def onAnchorStateChanged(self, uid, state):
        if state is not None:
            self.__changedStates[uid] = state
        return

    def onCameraLocated(self, locatedSlotId=None):
        for slotId, anchor in self.__processedAnchors.iteritems():
            if slotId == locatedSlotId:
                anchor.state.onSelected()
            anchor.state.onUnselected()

        self.__changeAnchorsStates()

    def getAnchorState(self, slotId):
        if slotId in self.__processedAnchors:
            anchor = self.__processedAnchors[slotId]
            return anchor.stateID

    def __changeAnchorsStates(self):
        if self.__changedStates:
            self.__ctx.events.onAnchorsStateChanged(self.__changedStates)
            self.__changedStates.clear()

    def __onVehicleChanged(self):
        self.setCollisions()

    def __onVehicleLoadStarted(self):
        pass

    def __onVehicleLoadFinished(self):
        self.setCollisions()

    def __onInterfaceScaleChanged(self, scale):
        self.__vehicleCustomizationAnchors.setInterfaceScale(scale)

    def getProcessedAnchor(self, slotId):
        return self.__processedAnchors[
            slotId] if slotId in self.__processedAnchors else None
Ejemplo n.º 7
0
class _VehicleCompareCartDataProvider(SortableDAAPIDataProvider):
    itemsCache = dependency.descriptor(IItemsCache)
    comparisonBasket = dependency.descriptor(IVehicleComparisonBasket)

    def __init__(self):
        super(_VehicleCompareCartDataProvider, self).__init__()
        self._list = []
        self._listMapping = {}
        self.__mapping = {}
        self.__selectedID = None
        return

    @property
    def collection(self):
        return self._list

    def emptyItem(self):
        return None

    def clear(self):
        self._list = []
        self._listMapping.clear()
        self.__mapping.clear()
        self.__selectedID = None
        return

    def fini(self):
        self.comparisonBasket.onChange -= self.__basketChanged
        self.comparisonBasket.onSwitchChange -= self.__basketChanged
        self.clear()
        self.destroy()

    def getSelectedIdx(self):
        return self.__mapping[self.__selectedID] if self.__selectedID in self.__mapping else -1

    def setSelectedID(self, selId):
        self.__selectedID = selId

    def setFlashObject(self, movieClip, autoPopulate=True, setScript=True):
        self.comparisonBasket.onChange += self.__basketChanged
        self.comparisonBasket.onSwitchChange += self.__basketChanged
        return super(_VehicleCompareCartDataProvider, self).setFlashObject(movieClip, autoPopulate, setScript)

    def getVO(self, index):
        vo = None
        if index > -1:
            try:
                vo = self.sortedCollection[index]
            except IndexError:
                LOG_ERROR('Item not found', index)

        return vo

    def buildList(self, changedVehsCDs):
        self.clear()
        for idx, vehCD in enumerate(changedVehsCDs):
            self._list.append(self._makeVO(vehCD, idx))

    def rebuildList(self, cache):
        self.buildList(cache)
        self.refresh()

    def pyGetSelectedIdx(self):
        return self.getSelectedIdx()

    def refreshRandomItems(self, indexes, items):
        self.flashObject.invalidateItems(indexes, items)

    def refreshSingleItem(self, index, item):
        self.flashObject.invalidateItem(index, item)

    def _makeVO(self, vehicleCD, index):
        vehicle = self.itemsCache.items.getItemByCD(vehicleCD)
        complectation = _ms(VEH_COMPARE.cartpopover_configurationtype(self.comparisonBasket.getVehicleAt(index).getConfigurationType()))
        basketLocked = self.comparisonBasket.isLocked
        return {'id': vehicleCD,
         'index': index,
         'vehicleName': text_styles.main(vehicle.shortUserName),
         'complectation': complectation,
         'nation': getNationsFilterAssetPath(AVAILABLE_NAMES[vehicle.nationID]),
         'level': vehicle.level,
         'typeStr': getTypeSmallIconPath(vehicle.type, vehicle.isPremium),
         'smallIconPath': vehicle.iconSmall,
         'removeBtnTooltip': VEH_COMPARE.CARTPOPOVER_REMOVELOCKEDBTN_TOOLTIP if basketLocked else VEH_COMPARE.CARTPOPOVER_REMOVEBTN_TOOLTIP,
         'removeBtnEnabled': not basketLocked}

    def __basketChanged(self, *args):
        self.rebuildList(self.comparisonBasket.getVehiclesCDs())
class TankmanCurrentVehicleAttrField(ToolTipAttrField):
    itemsCache = dependency.descriptor(IItemsCache)

    def _getItem(self):
        tankman = self._tooltip.item
        return self.itemsCache.items.getVehicle(tankman.vehicleInvID) if tankman and tankman.isInTank else None
class TankmanNativeVehicleAttrField(ToolTipAttrField):
    itemsCache = dependency.descriptor(IItemsCache)

    def _getItem(self):
        tankman = self._tooltip.item
        return self.itemsCache.items.getItemByCD(tankman.vehicleNativeDescr.type.compactDescr)
class Customization(FittingItem):
    __slots__ = ('_boundVehicles', '_bonus', '_installedVehicles',
                 '__noveltyData', '__progressingData', '__installedCount',
                 '__boundInventoryCount', '__fullInventoryCount',
                 '__fullCount')
    eventsCache = dependency.descriptor(IEventsCache)

    def __init__(self, intCompactDescr, proxy=None):
        super(Customization, self).__init__(intCompactDescr, proxy)
        self._inventoryCount = 0
        self._bonus = None
        self._boundVehicles = {}
        self._installedVehicles = {}
        self.__noveltyData = []
        self.__progressingData = {}
        self.__installedCount = None
        self.__boundInventoryCount = None
        self.__fullInventoryCount = None
        self.__fullCount = None
        if proxy is not None and proxy.inventory.isSynced():
            installedVehicles = proxy.inventory.getC11nItemAppliedVehicles(
                self.intCD)
            invCount = proxy.inventory.getItems(GUI_ITEM_TYPE.CUSTOMIZATION,
                                                self.intCD)
            for vehicleCD in installedVehicles:
                self._installedVehicles[
                    vehicleCD] = proxy.inventory.getC11nItemAppliedOnVehicleCount(
                        self.intCD, vehicleCD)

            for vehIntCD, count in invCount.iteritems():
                self._boundVehicles[vehIntCD] = count

            self._inventoryCount = self._boundVehicles.pop(UNBOUND_VEH_KEY, 0)
            self.__noveltyData = proxy.inventory.getC11nItemNoveltyData(
                intCompactDescr)
            self.__progressingData = proxy.inventory.getC11nProgressionDataForItem(
                intCompactDescr)
        self._isUnlocked = True
        return

    def __cmp__(self, other):
        return cmp(self.userName, other.userName) if isinstance(
            other, Customization) else -1

    def __repr__(self):
        return '{}<intCD:{}, id:{}>'.format(self.__class__.__name__,
                                            self.intCD, self.id)

    @property
    def id(self):
        return self.descriptor.id

    @property
    def itemTypeName(self):
        return GUI_ITEM_TYPE_NAMES[self.itemTypeID]

    @property
    def itemFullTypeName(self):
        return self.itemTypeName

    @property
    def groupID(self):
        return self.descriptor.parentGroup.itemPrototype.userKey

    @property
    def groupUserName(self):
        return self.descriptor.parentGroup.itemPrototype.userString

    @property
    def userTypeID(self):
        return R.strings.item_types.customization.dyn(self.itemFullTypeName)()

    @property
    def userType(self):
        return backport.text(self.userTypeID)

    @property
    def tags(self):
        return self.descriptor.tags

    @property
    def season(self):
        return self.descriptor.season

    @property
    def seasons(self):
        return [
            season for season in SeasonType.SEASONS if season & self.season
        ]

    @property
    def requiredToken(self):
        return self.descriptor.requiredToken

    @property
    def priceGroup(self):
        return self.descriptor.priceGroup

    @property
    def priceGroupTags(self):
        return self.descriptor.priceGroupTags

    @property
    def bonus(self):
        return self._bonus

    @property
    def texture(self):
        return self.descriptor.texture

    @property
    def icon(self):
        return self.descriptor.texture.replace('gui/', '../', 1)

    @property
    def iconUrl(self):
        return getTextureLinkByID(self.texture)

    @property
    def isVehicleBound(self):
        return ItemTags.VEHICLE_BOUND in self.tags

    @property
    def isLimited(self):
        return self.descriptor.maxNumber > 0

    @property
    def isStyleOnly(self):
        return self.descriptor.isStyleOnly

    @property
    def inventoryCount(self):
        return self._inventoryCount

    def getBonusIcon(self, size='small'):
        return RES_ICONS.getBonusIcon(size, self.itemTypeName)

    def boundInventoryCount(self, vehicleIntCD=None):
        if vehicleIntCD is not None:
            if vehicleIntCD in self._boundVehicles:
                return self._boundVehicles[vehicleIntCD]
            return 0
        else:
            if self.__boundInventoryCount is None:
                self.__boundInventoryCount = sum(
                    self._boundVehicles.itervalues())
            return self.__boundInventoryCount

    def fullInventoryCount(self, vehicleIntCD=None):
        if vehicleIntCD is not None:
            return self.inventoryCount + self.boundInventoryCount(vehicleIntCD)
        else:
            if self.__fullInventoryCount is None:
                self.__fullInventoryCount = self.inventoryCount + self.boundInventoryCount(
                )
            return self.__fullInventoryCount

    def installedCount(self, vehicleIntCD=None):
        if vehicleIntCD is not None:
            if vehicleIntCD in self._installedVehicles:
                return self._installedVehicles[vehicleIntCD]
            return 0
        else:
            if self.__installedCount is None:
                self.__installedCount = sum(
                    self._installedVehicles.itervalues())
            return self.__installedCount

    def fullCount(self, vehicleIntCD=None):
        if vehicleIntCD is not None:
            return self.fullInventoryCount(vehicleIntCD) + self.installedCount(
                vehicleIntCD)
        else:
            if self.__fullCount is None:
                self.__fullCount = self.fullInventoryCount(
                ) + self.installedCount()
            return self.__fullCount

    @property
    def buyCount(self):
        if self.isHidden:
            return 0
        return max(self.descriptor.maxNumber -
                   self.fullCount(), 0) if self.isLimited else float('inf')

    @property
    def mayApply(self):
        return self.inventoryCount > 0 or self.buyCount > 0

    @property
    def specialEventTag(self):
        eventTags = (tag for tag in self.tags if tag in SpecialEvents.ALL)
        return first(eventTags)

    @property
    def specialEventIcon(self):
        return SpecialEvents.ICONS.get(self.specialEventTag, '')

    @property
    def specialEventName(self):
        return SpecialEvents.NAMES.get(self.specialEventTag, '')

    @property
    def isProgressive(self):
        return self.descriptor.progression is not None

    @property
    def isProgressionAutoBound(self):
        return self.descriptor.progression.autobound if self.isProgressive else False

    @property
    def progressionConditions(self):
        return self.descriptor.progression.levels if self.isProgressive else None

    @property
    def isProgressionRewindEnabled(self):
        return ItemTags.PROGRESSION_REWIND_ENABLED in self.tags

    def getIconApplied(self, component):
        return self.icon

    def getInstalledVehicles(self, vehicles=None):
        return set(self._installedVehicles)

    def getBoundVehicles(self):
        return set(self._boundVehicles)

    def customizationDisplayType(self):
        return self.descriptor.customizationDisplayType

    def isDim(self):
        return ItemTags.DIM in self.tags

    def isSummer(self):
        return self.season & SeasonType.SUMMER

    def isWinter(self):
        return self.season & SeasonType.WINTER

    def isDesert(self):
        return self.season & SeasonType.DESERT

    def isAllSeason(self):
        return self.season == SeasonType.ALL

    def isEvent(self):
        return self.season & SeasonType.EVENT

    def mayInstall(self, vehicle, _=None):
        if not self._matchVehicleTags(vehicle):
            return False
        else:
            itemFilter = self._descriptor.filter
            return itemFilter is None or itemFilter.matchVehicleType(
                vehicle.descriptor.type)

    def isWide(self):
        return False

    def isUnlocked(self):
        return bool(
            self.eventsCache.questsProgress.getTokenCount(
                self.requiredToken)) if self.requiredToken else True

    def isRare(self):
        return self.descriptor.isRare()

    def isHiddenInUI(self):
        return not self._matchVehicleTags(
            g_currentVehicle.item) or self.descriptor.isHiddenInUI()

    def getGUIEmblemID(self):
        pass

    def isNew(self):
        return bool(self.__noveltyData)

    def getNoveltyCounter(self, vehicle):
        if not self.mayInstall(vehicle):
            return 0
        return sum([
            self.__noveltyData.get(key, 0)
            for key in (UNBOUND_VEH_KEY, vehicle.intCD)
        ])

    @staticmethod
    def getSpecialArgs(component):
        return None

    def getMaxProgressionLevel(self):
        return len(
            self.descriptor.progression.levels) if self.isProgressive else -1

    def getLatestOpenedProgressionLevel(self, vehicle):
        vehProgressData = self.getCurrentProgressionDataForVehicle(vehicle)
        if vehProgressData is not None:
            return vehProgressData.currentLevel
        else:
            return self.descriptor.progression.defaultLvl if self.isProgressive and self.descriptor.progression else -1

    def getCurrentProgressOnCurrentLevel(self, vehicle, conditionPath=None):
        if self.isProgressive:
            vehProgressData = self.getCurrentProgressionDataForVehicle(vehicle)
            if vehProgressData is not None:
                if conditionPath is not None:
                    return vehProgressData.currentProgressOnLevel.get(
                        conditionPath, 0)
                if vehProgressData.currentProgressOnLevel.values():
                    return vehProgressData.currentProgressOnLevel.values()[0]
            return 0
        else:
            return -1

    def getMaxProgressOnCurrentLevel(self, vehicle, conditionPath=None):
        vehProgressData = self.getCurrentProgressionDataForVehicle(vehicle)
        if vehProgressData is not None:
            if conditionPath is not None:
                return vehProgressData.maxProgressOnLevel.get(
                    conditionPath, -1)
            if vehProgressData.maxProgressOnLevel.values():
                return vehProgressData.maxProgressOnLevel.values()[0]
        return -1

    @staticmethod
    def getTextureByProgressionLevel(baseTexture, progressionLevel):
        path, name = os.path.split(baseTexture)
        name, ext = os.path.splitext(name)
        basePart, delimiter, _ = name.rpartition('_')
        if not basePart:
            _logger.error(
                'Wrong name of texture for progression customization item (texture name is "%s" )',
                baseTexture)
            return ''
        name = basePart + delimiter + str(progressionLevel)
        texture = path + '/' + name + ext
        if not ResMgr.isFile(texture):
            _logger.error(
                'Failed to get texture by progression level. Base texture %s; level: %s',
                baseTexture, progressionLevel)
            return ''
        return texture

    def getUsedProgressionLevel(self, component, vehicle=None):
        if self.isProgressive and component:
            progressionLevel = component.progressionLevel
            if progressionLevel == 0:
                progressionLevel = self.getLatestOpenedProgressionLevel(
                    g_currentVehicle.item if vehicle is None else vehicle)
            return progressionLevel
        else:
            return -1

    def iconByProgressionLevel(self, progressionLevel):
        return self.getTextureByProgressionLevel(
            self.texture, progressionLevel).replace(
                'gui/', '../', 1) if self.isProgressive else None

    def iconUrlByProgressionLevel(self, progressionLevel):
        return getTextureLinkByID(
            self.getTextureByProgressionLevel(
                self.texture,
                progressionLevel)) if self.isProgressive else None

    def iconResourceByProgressionLevel(self, progressionLevel):
        return getImageResourceFromPath(
            self.getTextureByProgressionLevel(
                self.texture,
                progressionLevel)) if self.isProgressive else None

    def availableForPurchaseProgressive(self, vehicle):
        if self.isHidden:
            return 0
        elif self.isProgressionAutoBound and vehicle is not None:
            availableSlotsCount = cc.getAvailableSlotsCount(
                self.descriptor, vehicle.descriptor) * len(
                    SeasonType.COMMON_SEASONS)
            installed = self.installedCount(vehicle.intCD)
            bounded = self.boundInventoryCount(vehicle.intCD)
            availableToBuy = availableSlotsCount - installed - bounded
            return max(0, availableToBuy)
        else:
            return float('inf')

    def getProgressionLevel(self, vehicle=None):
        progress = None
        if self.isProgressive and self.__progressingData is not None:
            vehicleCD = UNBOUND_VEH_KEY
            if vehicle is not None:
                if not self.mayInstall(vehicle):
                    return -1
                vehicleCD = vehicle.intCD if self.isProgressionAutoBound else vehicleCD
            progress = self.__progressingData.get(vehicleCD)
        return progress.currentLevel if progress is not None else -1

    def getCurrentProgressionDataForVehicle(self, vehicle):
        if self.isProgressive and self.__progressingData is not None:
            if vehicle.intCD in self.__progressingData:
                return self.__progressingData[vehicle.intCD]
            if UNBOUND_VEH_KEY in self.__progressingData and self.mayInstall(
                    vehicle):
                return self.__progressingData[UNBOUND_VEH_KEY]
        return

    def _matchVehicleTags(self, vehicle):
        return not (vehicle and vehicle.isProgressionDecalsOnly)
class TankmanTooltipDataBlock(BlocksTooltipData):
    _itemsCache = dependency.descriptor(IItemsCache)
    _lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self, context):
        super(TankmanTooltipDataBlock, self).__init__(context, TOOLTIP_TYPE.SKILL)
        self._setWidth(320)
        self.item = None
        return

    def _packBlocks(self, *args, **kwargs):
        items = super(TankmanTooltipDataBlock, self)._packBlocks()
        item = self.context.buildItem(*args, **kwargs)
        self.item = item
        vehicle = None
        if item.isInTank:
            vehicle = self._itemsCache.items.getVehicle(item.vehicleInvID)
        fullUserName = self._getFullUserName(item)
        items.append(formatters.packImageTextBlockData(title=text_styles.highTitle(fullUserName), desc=text_styles.main(self._getTankmanDescription(item))))
        innerBlock = []
        if vehicle:
            self._createLabel(innerBlock)
            self._createVehicleBlock(innerBlock, vehicle)
        if innerBlock:
            items.append(formatters.packBuildUpBlockData(innerBlock, padding=formatters.packPadding(left=0, right=50, top=-5, bottom=0), linkage=BLOCKS_TOOLTIP_TYPES.TOOLTIP_BUILDUP_BLOCK_WHITE_BG_LINKAGE))
        commonStatsBlock = [formatters.packTextBlockData(text=makeHtmlString('html_templates:lobby/textStyle', 'grayTitle', {'message': makeString(TOOLTIPS.HANGAR_CREW_SPECIALTY_SKILLS)}))]
        penalty = self._getBonusValue(item, [TankmanRoleBonusesField.BONUSES.PENALTY])
        addition = self._getBonusValue(item, [TankmanRoleBonusesField.BONUSES.COMMANDER,
         TankmanRoleBonusesField.BONUSES.EQUIPMENTS,
         TankmanRoleBonusesField.BONUSES.DEVICES,
         TankmanRoleBonusesField.BONUSES.BROTHERHOOD])
        addition_ = '' if addition == 0 else self._getSign(addition) + str(addition)
        penalty_ = '' if penalty == 0 else self._getSign(penalty) + str(penalty)
        if penalty != 0 or addition != 0:
            addRoleLevels = ' (' + str(item.roleLevel) + addition_ + penalty_ + ')'
        else:
            addRoleLevels = ''
        commonStatsBlock.append(formatters.packTextParameterBlockData(self._makeRoleName(item), text_styles.stats(str(item.roleLevel + penalty + addition) + '%' + addRoleLevels), valueWidth=90, padding=formatters.packPadding(left=0, right=0, top=5, bottom=0)))
        field = self._getSkillList()
        _, value = field.buildData()
        skills = value or []
        maxPopUpBlocks = 14
        for skill in skills[:maxPopUpBlocks]:
            commonStatsBlock.append(formatters.packTextParameterBlockData(text_styles.main(skill['label']), text_styles.stats(str(skill['level']) + '%'), valueWidth=90))

        if len(skills) > maxPopUpBlocks:
            diff = str(len(skills) - maxPopUpBlocks)
            commonStatsBlock.append(formatters.packAlignedTextBlockData(text=text_styles.middleTitle(makeString(TOOLTIPS.HANGAR_CREW_MORESKILLS, skill_cnt=diff)), align=BLOCKS_TOOLTIP_TYPES.ALIGN_CENTER))
        items.append(formatters.packBuildUpBlockData(commonStatsBlock, gap=5))
        self._createBlockForNewSkills(items)
        self._createMoreInfoBlock(items)
        return items

    def _makeRoleName(self, item):
        vehicle = None
        nativeVehicle = self._itemsCache.items.getItemByCD(item.vehicleNativeDescr.type.compactDescr)
        if item.isInTank:
            vehicle = self._itemsCache.items.getVehicle(item.vehicleInvID)
            vehicleName = self._getVehicleName(vehicle, nativeVehicle)
            return text_styles.main(item.roleUserName + ' ') + vehicleName
        else:
            return text_styles.main(item.roleUserName)

    def _getSign(self, val):
        return '' if val < 0 else '+'

    def _getBonusValue(self, tankman, ids):
        result = 0
        if tankman:
            _, roleBonuses = tankman.realRoleLevel
            for idx in ids:
                result += roleBonuses[idx]

        return int(result)

    def _getFullUserName(self, item):
        if item.skinID != NO_CREW_SKIN_ID and self._lobbyContext.getServerSettings().isCrewSkinsEnabled():
            skinItem = self._itemsCache.items.getCrewSkin(item.skinID)
            return localizedFullName(skinItem)
        return item.fullUserName

    def _getTankmanDescription(self, item):
        return item.rankUserName

    def _getVehicleName(self, vehicle=None, nativeVehicle=None):
        return text_styles.main(nativeVehicle.shortUserName) if not vehicle or nativeVehicle.shortUserName == vehicle.shortUserName else text_styles.critical(nativeVehicle.shortUserName)

    def _getSkillList(self):
        return TankmanSkillListField(self, 'skills')

    def _createLabel(self, innerBlock):
        innerBlock.append(formatters.packTextBlockData(text=makeHtmlString('html_templates:lobby/textStyle', 'grayTitle', {'message': backport.text(R.strings.tooltips.hangar.crew.assignedTo())})))

    def _createVehicleBlock(self, innerBlock, vehicle):
        vehicleType = vehicle.type.replace('-', '_')
        innerBlock.append(formatters.packImageTextBlockData(img=vehicle.iconContour, txtGap=-4, padding=formatters.packPadding(bottom=0, top=10, left=0), title=text_styles.stats(vehicle.shortUserName), desc=text_styles.stats(backport.text(R.strings.menu.header.vehicleType.dyn(vehicleType)())), flipHorizontal=True))

    def _createBlockForNewSkills(self, items):
        field = TankmanNewSkillCountField(self, '')
        _, newSkillCount = field.buildData()
        return items.append(formatters.packImageTextBlockData(img='../maps/icons/tankmen/skills/small/new_skill.png', txtOffset=20, padding=formatters.packPadding(bottom=0, top=5, left=0), imgPadding=formatters.packPadding(left=0, top=3), title=makeHtmlString('html_templates:lobby/textStyle', 'goldTextTitle', {'message': backport.text(R.strings.tooltips.hangar.crew.new_skill_available.header())}), desc=makeHtmlString('html_templates:lobby/textStyle', 'goldTextField', {'message': backport.text(R.strings.tooltips.hangar.crew.new_skill_available.text())}))) if newSkillCount > 0 else None

    def _createMoreInfoBlock(self, items):
        field = TankmanStatusField(self, '')
        _, value = field.buildData()
        status = value or {}
        if 'header' in status and status['header'] != '':
            items.append(formatters.packImageTextBlockData(title=text_styles.warning(status['header']), desc=makeHtmlString('html_templates:lobby/textStyle', 'statusWarningField', {'message': status['text']})))
class Style(Customization):
    __slots__ = ('_changableTypes', '_service', '_itemsCache', '__outfits',
                 '__dependenciesByIntCD', '__serialNumber')
    _service = dependency.descriptor(ICustomizationService)
    _itemsCache = dependency.descriptor(IItemsCache)

    def __init__(self, intCompactDescr, proxy=None):
        super(Style, self).__init__(intCompactDescr, proxy)
        self.itemTypeID = GUI_ITEM_TYPE.STYLE
        self._changableTypes = None
        self.__outfits = {}
        self.__dependenciesByIntCD = None
        self.__serialNumber = None
        if proxy is not None and proxy.isSynced():
            self.__serialNumber = proxy.inventory.getC11nSerialNumber(
                intCompactDescr)
        return

    @property
    def isProgressive(self):
        return bool(self.descriptor.styleProgressions)

    @property
    def isEditable(self):
        return self.descriptor.isEditable

    @property
    def isRentable(self):
        return self.descriptor.isRent

    @property
    def isRented(self):
        return False if not self.isRentable else bool(
            self.boundInventoryCount())

    @property
    def isProgressionRequired(self):
        return ItemTags.PROGRESSION_REQUIRED in self.tags

    @property
    def isProgression(self):
        return ItemTags.STYLE_PROGRESSION in self.tags

    @property
    def isWithSerialNumber(self):
        return ItemTags.STYLE_SERIAL_NUMBER in self.tags

    @property
    def is3D(self):
        return bool(self.modelsSet)

    @property
    def rentCount(self):
        return self.descriptor.rentCount if self.isRentable else 0

    @property
    def modelsSet(self):
        return self.descriptor.modelsSet

    @property
    def userTypeID(self):
        return getStyleGroupNameResourceID(self.groupID)

    @property
    def userType(self):
        return backport.text(self.userTypeID)

    @property
    def alternateItems(self):
        items = []
        for itemType, ids in self.descriptor.alternateItems.iteritems():
            for itemId in ids:
                compactDescr = makeIntCompactDescrByID('customizationItem',
                                                       itemType, itemId)
                items.append(self._service.getItemByCD(compactDescr))

        return items

    @property
    def changeableSlotTypes(self):
        return self.descriptor.changeableSlotTypes

    @property
    def maxProgressionLevel(self):
        return len(self.descriptor.styleProgressions)

    @property
    def serialNumber(self):
        return self.__serialNumber

    def getDescription(self):
        return self.longDescriptionSpecial or self.fullDescription or self.shortDescriptionSpecial or self.shortDescription

    def getUpgradePrice(self, currentLvl, targetLvl):
        def _getLevelPrice(level):
            levelDescr = self.descriptor.progression.levels.get(level)
            if levelDescr:
                price = Money(**levelDescr['price'])
                return ItemPrice(price=price, defPrice=price)
            return ITEM_PRICE_EMPTY

        return sum((_getLevelPrice(lvl)
                    for lvl in xrange(currentLvl + 1, targetLvl + 1)),
                   ITEM_PRICE_EMPTY)

    def getRentInfo(self, vehicle):
        if not self.isRentable:
            return RentalInfoProvider()
        battlesLeft = self.boundInventoryCount(vehicle.intCD)
        return RentalInfoProvider(battles=battlesLeft)

    def getOutfit(self, season, vehicleCD='', diff=None):
        if diff is not None:
            return self.__createOutfit(season, vehicleCD, diff)
        else:
            if season not in self.__outfits or self.__outfits[
                    season].vehicleCD != vehicleCD:
                self.__outfits[season] = self.__createOutfit(season, vehicleCD)
            return self.__outfits[season].copy()

    def getDependenciesIntCDs(self):
        if self.__dependenciesByIntCD is None:
            self.__dependenciesByIntCD = {}
            makeCD = makeIntCompactDescrByID
            for ancestorID, dependentData in self.descriptor.dependencies.iteritems(
            ):
                dependentIntCDs = []
                for iType, iIds in dependentData.iteritems():
                    dependentIntCDs.extend([
                        makeCD('customizationItem', iType, iId) for iId in iIds
                    ])

                dependentIntCDs = tuple(dependentIntCDs)
                self.__dependenciesByIntCD[makeCD(
                    'customizationItem', CustomizationType.CAMOUFLAGE,
                    ancestorID)] = dependentIntCDs

        return self.__dependenciesByIntCD

    def isWide(self):
        return True

    def isProgressionPurchasable(self, progressionLevel):
        styleDescr = self._descriptor.compactDescr
        lockedLevels = self._service.itemsCache.items.shop.getNotInShopProgressionLvlItems(
        ).get(styleDescr, [])
        return progressionLevel not in lockedLevels

    def canBeEditedForVehicle(self, vehicleIntCD):
        if not self.isEditable:
            return EditingStyleReason(EDITING_STYLE_REASONS.NOT_EDITABLE)
        else:
            ctx = self._service.getCtx()
            if ctx is not None and self.isProgression:
                season = ctx.mode.season
                diff = ctx.stylesDiffsCache.getDiff(self, season)
                if diff is not None:
                    vehicleItem = self._service.itemsCache.items.getItemByCD(
                        vehicleIntCD)
                    diffOutfit = parseOutfitDescr(outfitDescr=diff)
                    modifiedProgression = diffOutfit.styleProgressionLevel
                    progressionChanged = modifiedProgression != self.getLatestOpenedProgressionLevel(
                        vehicleItem)
                    if progressionChanged and not self.isProgressionPurchasable(
                            modifiedProgression):
                        return EditingStyleReason(
                            EDITING_STYLE_REASONS.NOT_REACHED_LEVEL)
            if not self.isProgressionRequired:
                return EditingStyleReason(EDITING_STYLE_REASONS.IS_EDITABLE)
            progressionStorage = self._itemsCache.items.inventory.getC11nProgressionDataForVehicle(
                vehicleIntCD)
            for itemIntCD, progressionData in progressionStorage.iteritems():
                if not progressionData.currentLevel:
                    continue
                item = self._service.getItemByCD(itemIntCD)
                if self.descriptor.isItemInstallable(item.descriptor):
                    return EditingStyleReason(
                        EDITING_STYLE_REASONS.IS_EDITABLE)

            return EditingStyleReason(
                EDITING_STYLE_REASONS.NOT_HAVE_ANY_PROGRESIIVE_DECALS)

    def isProgressionRequiredCanBeEdited(self, vehicleIntCD):
        return self.isProgressionRequired and self.canBeEditedForVehicle(
            vehicleIntCD)

    def isItemInstallable(self, item):
        return self.descriptor.isItemInstallable(item.descriptor)

    def isEditedForVehicle(self, vehicleIntCD):
        c11nCtx = self._service.getCtx()
        if c11nCtx is not None and vehicleIntCD == g_currentVehicle.item.intCD:
            diffs = c11nCtx.stylesDiffsCache.getDiffs(self)
            for diff in diffs.itervalues():
                if diff is not None and isEditedStyle(parseCompDescr(diff)):
                    return True

        else:
            outfitsPool = self._itemsCache.items.inventory.getC11nOutfitsFromPool(
                vehicleIntCD)
            for styleId, _ in outfitsPool:
                if styleId == self.id:
                    return True

        return False

    def iconByProgressionLevel(self, _):
        return self.getIconApplied(component=None)

    def iconUrlByProgressionLevel(self, _):
        return self.getIconApplied(component=None)

    def getAdditionalOutfit(self, level, season, vehicleCD):
        additionalOutfit = self.descriptor.styleProgressions.get(
            level, {}).get('additionalOutfit', {})
        return Outfit(
            strCompactDescr=additionalOutfit.get(season).makeCompDescr(),
            vehicleCD=vehicleCD
        ) if additionalOutfit and additionalOutfit.get(season) else None

    def __createOutfit(self, season, vehicleCD='', diff=None):
        component = deepcopy(self.descriptor.outfits[season])
        vehDescr = None
        if vehicleCD:
            vehDescr = VehicleDescr(vehicleCD)
        if vehDescr and ItemTags.ADD_NATIONAL_EMBLEM in self.tags:
            emblems = createNationalEmblemComponents(vehDescr)
            component.decals.extend(emblems)
        if vehDescr and self.isProgressive:
            vehicle = self._itemsCache.items.getItemByCD(
                vehDescr.type.compactDescr)
            component.styleProgressionLevel = self.getLatestOpenedProgressionLevel(
                vehicle)
            if self.isProgressionRewindEnabled:
                component.styleProgressionLevel = self.maxProgressionLevel
                styleOutfitData = self._itemsCache.items.inventory.getOutfitData(
                    vehDescr.type.compactDescr, SeasonType.ALL)
                if styleOutfitData:
                    styledOutfitComponent = parseCompDescr(styleOutfitData)
                    outfitLvl = styledOutfitComponent.styleProgressionLevel
                    component.styleProgressionLevel = outfitLvl if outfitLvl else 1
        if self.isWithSerialNumber and self.serialNumber is not None:
            component.serial_number = self.serialNumber
        if diff is not None:
            diffComponent = parseCompDescr(diff)
            if component.styleId != diffComponent.styleId:
                _logger.error(
                    'Merging outfits of different styles is not allowed. ID1: %s ID2: %s',
                    component.styleId, diffComponent.styleId)
            else:
                component = component.applyDiff(diffComponent)
        return self.itemsFactory.createOutfit(component=component,
                                              vehicleCD=vehicleCD)
class BattlePassVotingConfirmView(FullScreenDialogView):
    __slots__ = ('__data',)
    __battlePassController = dependency.descriptor(IBattlePassController)
    __settingsCore = dependency.descriptor(ISettingsCore)
    __itemsCache = dependency.descriptor(IItemsCache)

    def __init__(self, data):
        settings = ViewSettings(R.views.lobby.battle_pass.BattlePassVotingConfirmView())
        settings.flags = ViewFlags.OVERLAY_VIEW
        settings.model = BattlePassVotingConfirmViewModel()
        self.__data = data
        super(BattlePassVotingConfirmView, self).__init__(settings)

    @property
    def viewModel(self):
        return self.getViewModel()

    def _setBaseParams(self, model):
        reward = self.__data.get('finalReward')
        vehicle = self.__itemsCache.items.getItemByCD(reward.getVehicleCD())
        model.setVehicleName(vehicle.name.split(':')[1])
        model.setVehicleCD(reward.getVehicleCD())
        model.setStyleName(reward.getStyleName())
        model.setRecruitName(reward.getRecruitName())
        model.setIsBattlePassBought(self.__battlePassController.isBought())

    def _initialize(self):
        super(BattlePassVotingConfirmView, self)._initialize()
        self.__battlePassController.onBattlePassSettingsChange += self.__onSettingsChange
        switchHangarOverlaySoundFilter(on=True)

    def _finalize(self):
        super(BattlePassVotingConfirmView, self)._finalize()
        self.__battlePassController.onBattlePassSettingsChange -= self.__onSettingsChange
        switchHangarOverlaySoundFilter(on=False)

    def _addListeners(self):
        self.viewModel.onVoteClick += self.__onVoteClick

    def _removeListeners(self):
        self.viewModel.onVoteClick -= self.__onVoteClick

    def _blurBackGround(self):
        pass

    def __onVoteClick(self, args):
        vehicleCD = int(args.get('vehicleCD'))
        self.__chooseFinalReward(vehicleCD, self.__battlePassController.getSeasonID())

    def __setVotedWithBoughtBP(self):
        self.__settingsCore.serverSettings.saveInBPStorage({BattlePassStorageKeys.VOTED_WITH_BOUGHT_BP: self.__battlePassController.isBought()})

    @decorators.process('chooseFinalReward')
    def __chooseFinalReward(self, rewardID, seasonID):
        result = yield ChooseFinalBattlePassReward(rewardID, seasonID).request()
        if result.userMsg:
            SystemMessages.pushMessage(result.userMsg, type=result.sysMsgType)
        if result.success:
            self.__setVotedWithBoughtBP()
            super(BattlePassVotingConfirmView, self)._onAcceptClicked()

    def __onSettingsChange(self, *_):
        if not self.__battlePassController.isVisible() or self.__battlePassController.isPaused():
            self.destroyWindow()
Ejemplo n.º 14
0
class SandboxEntity(PreQueueEntity):
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self):
        super(SandboxEntity, self).__init__(FUNCTIONAL_FLAG.SANDBOX,
                                            QUEUE_TYPE.SANDBOX,
                                            PreQueueSubscriber())
        self.__watcher = None
        self.storage = prequeue_storage_getter(QUEUE_TYPE.SANDBOX)()
        return

    def init(self, ctx=None):
        self.storage.release()
        self.__watcher = SandboxVehiclesWatcher()
        self.__watcher.start()
        self.lobbyContext.getServerSettings(
        ).onServerSettingsChange += self.__onServerSettingChanged
        return super(SandboxEntity, self).init(ctx)

    def fini(self, ctx=None, woEvents=False):
        if self.__watcher is not None:
            self.__watcher.stop()
            self.__watcher = None
        self.lobbyContext.getServerSettings(
        ).onServerSettingsChange -= self.__onServerSettingChanged
        return super(SandboxEntity, self).fini(ctx=ctx, woEvents=woEvents)

    def leave(self, ctx, callback=None):
        if not ctx.hasFlags(FUNCTIONAL_FLAG.TUTORIAL) and not ctx.hasFlags(
                FUNCTIONAL_FLAG.SANDBOX):
            self.storage.suspend()
        super(SandboxEntity, self).leave(ctx, callback)

    @vehicleAmmoCheck
    def queue(self, ctx, callback=None):
        super(SandboxEntity, self).queue(ctx, callback=callback)

    def doSelectAction(self, action):
        return SelectResult(
            True
        ) if action.actionName == PREBATTLE_ACTION_NAME.SANDBOX else super(
            SandboxEntity, self).doSelectAction(action)

    def getConfirmDialogMeta(self, ctx):
        if not self.hasLockedState() and not ctx.hasFlags(
                FUNCTIONAL_FLAG.TUTORIAL) and AccountSettings.getSettings(
                    DEFAULT_QUEUE) == QUEUE_TYPE.SANDBOX:
            meta = rally_dialog_meta.createLeavePreQueueMeta(
                ctx, self.getQueueType(), self.canSwitch(ctx))
        else:
            meta = super(SandboxEntity, self).getConfirmDialogMeta(ctx)
        return meta

    def _createActionsValidator(self):
        return SandboxActionsValidator(self)

    def _doQueue(self, ctx):
        BigWorld.player().enqueueSandbox(ctx.getVehicleInventoryID())
        LOG_DEBUG('Sends request on queuing to the PvE tutorial battle', ctx)

    def _doDequeue(self, ctx):
        BigWorld.player().dequeueSandbox()
        LOG_DEBUG('Sends request on dequeuing from the PvE tutorial battle')

    def _makeQueueCtxByAction(self, action=None):
        invID = g_currentVehicle.invID
        if not invID:
            raise SoftException('Inventory ID of vehicle can not be zero')
        return SandboxQueueCtx(invID, waitingID='prebattle/join')

    def _goToQueueUI(self):
        g_eventDispatcher.loadSandboxQueue()
        return FUNCTIONAL_FLAG.LOAD_WINDOW

    def _exitFromQueueUI(self):
        g_eventDispatcher.unloadSandboxQueue()

    def __onServerSettingChanged(self, diff):
        if not self.lobbyContext.getServerSettings().isSandboxEnabled():

            def __leave(_=True):
                g_prbCtrlEvents.onPreQueueLeft()

            if self.isInQueue():
                self.dequeue(DequeueCtx(waitingID='prebattle/leave'),
                             callback=__leave)
            else:
                __leave()
Ejemplo n.º 15
0
class GlobalVarsManager(GlobalVarsMgrMeta):
    _isLoginLoadInfoRequested = False
    itemsCache = dependency.descriptor(IItemsCache)
    wallet = dependency.descriptor(IWalletController)
    tradeIn = dependency.descriptor(ITradeInController)
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self):
        super(GlobalVarsManager, self).__init__()

    def isDevelopment(self):
        return constants.IS_DEVELOPMENT

    def isShowLangaugeBar(self):
        return GUI_SETTINGS.isShowLanguageBar

    def isShowServerStats(self):
        return constants.IS_SHOW_SERVER_STATS

    def isChina(self):
        return constants.IS_CHINA

    def isKorea(self):
        return constants.IS_KOREA

    def isTutorialRunning(self, tutorialID):
        try:
            from tutorial.loader import isTutorialRunning
        except:

            def isTutorialRunning(_):
                return False

        return isTutorialRunning(tutorialID)

    def isFreeXpToTankman(self):
        return self.itemsCache.items.shop.freeXPToTManXPRate > 0

    def getLocaleOverride(self):
        return getClientOverride()

    def isRoamingEnabled(self):
        return self.lobbyContext.getServerSettings().roaming.isEnabled()

    def isInRoaming(self):
        return self.lobbyContext.getServerSettings().roaming.isInRoaming()

    def isWalletAvailable(self):
        if self.wallet:
            return self.wallet.isAvailable
        else:
            return False

    def isShowLoginRssFeed(self):
        return GUI_SETTINGS.loginRssFeed.show

    def isShowTicker(self):
        return constants.IS_CHINA and GUI_SETTINGS.movingText.show

    def isRentalsEnabled(self):
        return constants.IS_RENTALS_ENABLED

    def isPotapovQuestEnabled(self):
        return self.lobbyContext.getServerSettings().isPotapovQuestEnabled()

    def isLoginLoadedAtFirstTime(self):
        if GlobalVarsManager._isLoginLoadInfoRequested:
            return False
        else:
            GlobalVarsManager._isLoginLoadInfoRequested = True
            return True

    def isVehicleRestoreEnabled(self):
        return self.lobbyContext.getServerSettings().isVehicleRestoreEnabled()

    def isTradeInEnabled(self):
        return self.tradeIn.isEnabled()

    def isBootcampFinished(self):
        return g_bootcamp.isFinished()
class _NodeContainer(object):
    itemsCache = dependency.descriptor(IItemsCache)
    goodiesCache = dependency.descriptor(IGoodiesCache)

    def __init__(self, childCount, itemTypeOrGroup, nextNode=None):
        super(_NodeContainer, self).__init__()
        self._maxChildCount = childCount
        self._nextNode = nextNode
        self._children = []
        self._itemTypeOrGroup = itemTypeOrGroup

    def getVO(self):
        items = []
        self._sortChildren()
        for i, child in enumerate(self._children):
            items.append(
                _createItemVO(child, self.itemsCache, self.goodiesCache, i))

        return self.wrapVO(items)

    def getNextNode(self):
        return self._nextNode

    def destroy(self):
        self._nextNode = None
        return

    def addItem(self, item, vehicle, vehicleGroupId):
        if _checkItemType(
                item.type,
                self._itemTypeOrGroup) and item.groupID == vehicleGroupId:
            slotIdx = len(self._children)
            if slotIdx < self._maxChildCount:
                mayInstall, counterLimit = self._install(
                    item, vehicle, slotIdx)
                if mayInstall:
                    itemsCount = item.count
                    if counterLimit == _UNLIMITED_ITEMS_COUNT or itemsCount <= counterLimit:
                        self._children.append(item)
                        return
                    self._children.append(item.replace({'count':
                                                        counterLimit}))
                    itemsLeft = itemsCount - counterLimit
                    item = item.replace({'count': itemsLeft})
        self._addItemToNextNode(item, vehicle, vehicleGroupId)

    @staticmethod
    def wrapVO(items):
        result = {}
        if items:
            result = {
                'items': items,
                'isEnabled': True,
                'topTitle': '',
                'topTitleSmall': ''
            }
        return result

    def _install(self, item, vehicle, slotIdx):
        for child in self._children:
            if child.id == item.id:
                return (False, 1)

        return (True, 1)

    def _addItemToNextNode(self, item, vehicle, vehicleGroupId):
        if self._nextNode:
            self._nextNode.addItem(item, vehicle, vehicleGroupId)

    def _sortChildren(self):
        pass
class QuestProgressController(IArenaPeriodController,
                              IArenaVehiclesController):
    eventsCache = dependency.descriptor(IEventsCache)
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self):
        super(QuestProgressController, self).__init__()
        self._period = ARENA_PERIOD.IDLE
        self._endTime = 0
        self._length = 0
        self._callbackID = None
        self.__storage = {}
        self.__selectedQuest = None
        self.__eManager = EventManager()
        self.__battleCtx = None
        self.__isInited = False
        self.__inProgressQuests = {}
        self.onConditionProgressUpdate = Event(self.__eManager)
        self.onHeaderProgressesUpdate = Event(self.__eManager)
        self.onFullConditionsUpdate = Event(self.__eManager)
        self.onQuestProgressInited = Event(self.__eManager)
        return

    def getInProgressQuests(self):
        return self.__inProgressQuests

    def hasQuestsToPerform(self):
        return bool(self.__inProgressQuests)

    def getSelectedQuest(self):
        return self.__selectedQuest

    def isInited(self):
        return self.__isInited

    def selectQuest(self, missionID):
        self.__selectedQuest = self.__inProgressQuests.get(missionID)
        self.onFullConditionsUpdate()

    def invalidateArenaInfo(self):
        isPersonalMissionsEnabled = self.lobbyContext.getServerSettings(
        ).isPersonalMissionsEnabled
        if not self.__isInited:
            personalMissions = self.eventsCache.getPersonalMissions()
            selectedMissionsIDs = self.__battleCtx.getSelectedQuestIDs()
            selectedMissionsInfo = self.__battleCtx.getSelectedQuestInfo(
            ) or {}
            if selectedMissionsIDs:
                missions = personalMissions.getAllQuests()
                for missionID in selectedMissionsIDs:
                    mission = missions.get(missionID)
                    if mission and not mission.isDisabled(
                    ) and isPersonalMissionsEnabled(mission.getQuestBranch()):
                        pqState = selectedMissionsInfo.get(
                            missionID, (0, PM_STATE.NONE))[1]
                        mission.updatePqStateInBattle(pqState)
                        self.__inProgressQuests[missionID] = mission
                        if mission.hasBattleProgress():
                            generalQuestID = mission.getGeneralQuestID()
                            self.__selectedQuest = mission
                            self.__storage[
                                generalQuestID] = BattleProgressStorage(
                                    generalQuestID,
                                    mission.getConditionsConfig(),
                                    mission.getConditionsProgress())

                if self.__selectedQuest is None:
                    self.__selectedQuest = first(
                        self.__inProgressQuests.itervalues())
                self.__updateTimerConditions(sendDiff=False)
            self.__isInited = True
            self.onQuestProgressInited()
        return

    def startControl(self, battleCtx, arenaVisitor):
        self.__battleCtx = battleCtx

    def areQuestsEnabledForArena(self):
        return self.__battleCtx.areQuestsEnabledForArena()

    def stopControl(self):
        self._period = ARENA_PERIOD.IDLE
        self._endTime = 0
        self._length = 0
        self.__selectedQuest = None
        self.__battleCtx = None
        self.__storage.clear()
        self.__eManager.clear()
        self.__clearCallback()
        self.__inProgressQuests.clear()
        self.__isInited = False
        return

    def setPeriodInfo(self, period, endTime, length, additionalInfo, soundID):
        self.__updatePeriodInfo(period, endTime, length)

    def invalidatePeriodInfo(self, period, endTime, length, additionalInfo):
        self.__updatePeriodInfo(period, endTime, length)

    def getQuestFullData(self):
        selectedQuest = self.__selectedQuest
        if selectedQuest:
            formatter = self.__getFormatter(selectedQuest)
            return {
                'questName':
                selectedQuest.getUserName(),
                'questID':
                selectedQuest.getID(),
                'questIndexStr':
                str(selectedQuest.getInternalID()),
                'questIcon':
                RES_ICONS.getAllianceGoldIcon(selectedQuest.getMajorTag()),
                'headerProgress':
                formatter.headerFormat(),
                'bodyProgress':
                formatter.bodyFormat()
            }
        return {}

    def getQuestHeaderProgresses(self):
        formatter = self.__getFormatter(self.__selectedQuest)
        return formatter.headerFormat()

    def updateQuestProgress(self, questID, info):
        if questID in self.__storage:
            self.__storage[questID].update(info)
        else:
            _logger.error('Storage for quest:%s is not found.', questID)
        selectedQuest = self.__selectedQuest
        if selectedQuest is not None and selectedQuest.hasBattleProgress():
            storage = self.__storage[selectedQuest.getGeneralQuestID()]
            needHeaderResync = False
            for headerProgress in storage.getHeaderProgresses().itervalues():
                if headerProgress.isChanged():
                    needHeaderResync = True
                    headerProgress.markAsVisited()

            if needHeaderResync:
                self.onHeaderProgressesUpdate()
            for progressID, condProgress in storage.getChangedConditions(
            ).iteritems():
                condProgress.markAsVisited()
                self.onConditionProgressUpdate(progressID,
                                               condProgress.getProgress())

        return

    def getControllerID(self):
        return BATTLE_CTRL_ID.QUEST_PROGRESS

    def getCtrlScope(self):
        return _SCOPE.PERIOD | _SCOPE.VEHICLES

    def __updatePeriodInfo(self, period, endTime, length):
        self._period = period
        self._endTime = endTime
        self._length = length
        self.__clearCallback()
        if self._period == ARENA_PERIOD.BATTLE:
            self.__setCallback()

    def __setCallback(self):
        self._callbackID = None
        battleEndLeftTime = self._endTime - BigWorld.serverTime()
        tickInterval = 1 if battleEndLeftTime > 1 else 0
        self.__updateTimerConditions()
        self._callbackID = BigWorld.callback(tickInterval, self.__setCallback)
        return

    def __clearCallback(self):
        if self._callbackID is not None:
            BigWorld.cancelCallback(self._callbackID)
            self._callbackID = None
        return

    def __updateTimerConditions(self, sendDiff=True):
        selectedQuest = self.__selectedQuest
        hasProgress = selectedQuest and selectedQuest.hasBattleProgress()
        if self._period == ARENA_PERIOD.BATTLE and hasProgress:
            startTime = self._endTime - self._length
            timesGoneFromStart = BigWorld.serverTime() - startTime
            timerConditions = self.__storage[
                selectedQuest.getGeneralQuestID()].getTimerConditions()
            for progressID, condProgress in timerConditions.iteritems():
                secondsLeft = max(
                    condProgress.getCountDown() - timesGoneFromStart, 0)
                isChanged = condProgress.setTimeLeft(secondsLeft)
                if isChanged and sendDiff:
                    self.onConditionProgressUpdate(progressID,
                                                   condProgress.getProgress())

    def __getFormatter(self, selectedQuest):
        return DetailedProgressFormatter(
            self.__storage.get(selectedQuest.getGeneralQuestID()),
            selectedQuest) if selectedQuest.hasBattleProgress(
            ) else PM1BattleConditionsFormatterAdapter(selectedQuest)
Ejemplo n.º 18
0
class CarouselEnvironment(CarouselEnvironmentMeta, IGlobalListener,
                          ICarouselEnvironment):
    rentals = dependency.descriptor(IRentalsController)
    igrCtrl = dependency.descriptor(IIGRController)
    clanLock = dependency.descriptor(IClanLockController)
    settingsCore = dependency.descriptor(ISettingsCore)
    itemsCache = dependency.descriptor(IItemsCache)
    epicController = dependency.descriptor(IEpicBattleMetaGameController)
    rankedController = dependency.descriptor(IRankedBattlesController)
    lobbyContext = dependency.descriptor(ILobbyContext)
    __battleSession = dependency.descriptor(IBattleSessionProvider)

    def __init__(self):
        super(CarouselEnvironment, self).__init__()
        self._usedFilters = self._getFilters()
        self._carouselDPConfig = {
            'carouselFilter': None,
            'itemsCache': None,
            'currentVehicle': None
        }
        self._carouselDPCls = CarouselDataProvider
        self._carouselFilterCls = CarouselFilter
        self._carouselDP = None
        self._currentVehicle = None
        self.__filterPopoverRemoveCallback = None
        return

    def setPopoverCallback(self, callback=None):
        self.__filterPopoverRemoveCallback = callback

    def onPlayerStateChanged(self, entity, roster, accountInfo):
        if accountInfo.isCurrentPlayer():
            self.updateAviability()

    def onUnitPlayerStateChanged(self, pInfo):
        if pInfo.isCurrentPlayer():
            self.updateAviability()

    def onPrbEntitySwitched(self):
        self.updateAviability()

    def onEnqueued(self, queueType, *args):
        self.updateAviability()

    def onDequeued(self, queueType, *args):
        self.updateAviability()

    def onUnitAutoSearchStarted(self, timeLeft):
        self.updateAviability()

    def onUnitAutoSearchFinished(self):
        self.updateAviability()

    @property
    def filter(self):
        return self._carouselDP.filter if self._carouselDP is not None else None

    def getTotalVehiclesCount(self):
        return self._carouselDP.getTotalVehiclesCount()

    def getCurrentVehiclesCount(self):
        return self._carouselDP.getCurrentVehiclesCount()

    def hasRentedVehicles(self):
        return self._carouselDP.hasRentedVehicles()

    def hasEventVehicles(self):
        return self._carouselDP.hasEventVehicles()

    def resetFilters(self):
        self.filter.reset()
        self.applyFilter()

    def applyFilter(self):
        self._carouselDP.applyFilter()
        if not self.filter.isDefault():
            drawAttention = self._carouselDP.getCurrentVehiclesCount() == 0
            self.as_showCounterS(self.formatCountVehicles(), drawAttention)
        else:
            self.as_hideCounterS()

    def formatCountVehicles(self):
        return formatCountString(self._carouselDP.getCurrentVehiclesCount(),
                                 self._carouselDP.getTotalVehiclesCount())

    def blinkCounter(self):
        self.as_blinkCounterS()

    def selectVehicle(self, idx):
        if self.__battleSession.isReplayPlaying:
            return
        self._carouselDP.selectVehicle(idx)

    def updateVehicles(self, vehicles=None, filterCriteria=None):
        if self._carouselDP is not None:
            self._carouselDP.updateVehicles(vehicles, filterCriteria)
            self.applyFilter()
        return

    def updateAviability(self):
        if not self.isDisposed():
            state = self._currentVehicle.getViewState()
            self.as_setEnabledS(not state.isLocked())

    def _populate(self):
        super(CarouselEnvironment, self)._populate()
        self._currentVehicle = g_currentVehicle
        self._initDataProvider()
        setting = self.settingsCore.options.getSetting(
            settings_constants.GAME.VEHICLE_CAROUSEL_STATS)
        self._carouselDP.setShowStats(setting.get())
        self._carouselDP.setEnvironment(self.app)
        self._carouselDP.setFlashObject(self.as_getDataProviderS())
        self._carouselDP.buildList()
        self.rentals.onRentChangeNotify += self.__updateRent
        self.igrCtrl.onIgrTypeChanged += self.__updateIgrType
        self.clanLock.onClanLockUpdate += self.__updateClanLocks
        self.itemsCache.onSyncCompleted += self.__onCacheResync
        self._currentVehicle.onChanged += self.__onCurrentVehicleChanged
        self.epicController.onUpdated += self.__updateEpicSeasonRent
        self.rankedController.onUpdated += self.__updateRankedBonusBattles
        self.settingsCore.onSettingsChanged += self._onCarouselSettingsChange
        self.lobbyContext.getServerSettings(
        ).onServerSettingsChange += self.__onServerSettingChanged
        g_playerEvents.onVehicleBecomeElite += self.__onVehicleBecomeElite
        g_prbCtrlEvents.onVehicleClientStateChanged += self.__onVehicleClientStateChanged
        self.startGlobalListening()
        self.applyFilter()
        self.updateAviability()
        self.as_setInitDataS({
            'counterCloseTooltip':
            makeTooltip('#tooltips:tanksFilter/counter/close/header',
                        '#tooltips:tanksFilter/counter/close/body')
        })

    def _dispose(self):
        self.rentals.onRentChangeNotify -= self.__updateRent
        self.igrCtrl.onIgrTypeChanged -= self.__updateIgrType
        self.clanLock.onClanLockUpdate -= self.__updateClanLocks
        self.itemsCache.onSyncCompleted -= self.__onCacheResync
        self._currentVehicle.onChanged -= self.__onCurrentVehicleChanged
        self.epicController.onUpdated -= self.__updateEpicSeasonRent
        self.rankedController.onUpdated -= self.__updateRankedBonusBattles
        self.lobbyContext.getServerSettings(
        ).onServerSettingsChange -= self.__onServerSettingChanged
        self.settingsCore.onSettingsChanged -= self._onCarouselSettingsChange
        g_playerEvents.onVehicleBecomeElite -= self.__onVehicleBecomeElite
        g_prbCtrlEvents.onVehicleClientStateChanged -= self.__onVehicleClientStateChanged
        self.stopGlobalListening()
        self._currentVehicle = None
        self._carouselDP.fini()
        self._carouselDP = None
        self._carouselDPConfig.clear()
        self.__callPopoverCallback()
        super(CarouselEnvironment, self)._dispose()
        return

    def _initDataProvider(self):
        self._carouselDPConfig.update({
            'carouselFilter':
            self._carouselFilterCls(),
            'itemsCache':
            self.itemsCache,
            'currentVehicle':
            self._currentVehicle
        })
        self._carouselDP = self._carouselDPCls(**self._carouselDPConfig)

    def _onCarouselSettingsChange(self, diff):
        if settings_constants.GAME.VEHICLE_CAROUSEL_STATS in diff:
            setting = self.settingsCore.options.getSetting(
                settings_constants.GAME.VEHICLE_CAROUSEL_STATS)
            self._carouselDP.setShowStats(setting.get())
            self._carouselDP.updateVehicles()

    def __updateRent(self, vehicles):
        self.updateVehicles(vehicles)

    def __updateEpicSeasonRent(self, diff):
        self.updateVehicles(filterCriteria=REQ_CRITERIA.VEHICLE.SEASON_RENT)

    def __updateRankedBonusBattles(self):
        self.updateVehicles()

    def __updateIgrType(self, roomType, xpFactor):
        self.updateVehicles(filterCriteria=REQ_CRITERIA.VEHICLE.IS_PREMIUM_IGR)

    def __updateClanLocks(self, vehicles, isFull):
        if isFull:
            self.updateVehicles()
        else:
            self.updateVehicles(vehicles)

    def __onServerSettingChanged(self, diff):
        if 'crystal_rewards_config' in diff:
            self.updateVehicles()

    def __onCacheResync(self, reason, diff):
        if reason in (CACHE_SYNC_REASON.SHOP_RESYNC,
                      CACHE_SYNC_REASON.DOSSIER_RESYNC):
            self.updateVehicles()
            self.updateAviability()
            return
        if reason in (CACHE_SYNC_REASON.STATS_RESYNC,
                      CACHE_SYNC_REASON.INVENTORY_RESYNC,
                      CACHE_SYNC_REASON.CLIENT_UPDATE):
            self.updateAviability()
        if GUI_ITEM_TYPE.VEHICLE in diff:
            self.updateVehicles(diff.get(GUI_ITEM_TYPE.VEHICLE))

    def __onCurrentVehicleChanged(self):
        self.updateAviability()
        if self._carouselDP is not None:
            filteredIndex = self._carouselDP.findVehicleFilteredIndex(
                g_currentVehicle.item)
            if self._carouselDP.pyGetSelectedIdx() != filteredIndex:
                self._carouselDP.selectVehicle(filteredIndex)
                self._carouselDP.refresh()
        return

    def __onVehicleBecomeElite(self, *vehicles):
        self.updateVehicles(vehicles)

    def __onVehicleClientStateChanged(self, vehicles):
        self.updateVehicles(vehicles)

    def __callPopoverCallback(self):
        if callable(self.__filterPopoverRemoveCallback):
            callback = self.__filterPopoverRemoveCallback
            self.__filterPopoverRemoveCallback = None
            callback()
        return

    def _getFilters(self):
        return _CAROUSEL_FILTERS
Ejemplo n.º 19
0
class VehicleCompareCartPopover(VehicleCompareCartPopoverMeta):
    comparisonBasket = dependency.descriptor(IVehicleComparisonBasket)

    def remove(self, vehId):
        self.comparisonBasket.removeVehicleByIdx(int(vehId))

    def removeAll(self):
        self.comparisonBasket.removeAllVehicles()

    def onWindowClose(self):
        self.destroy()

    def gotoCompareView(self):
        showVehicleCompare()
        self.destroy()

    def _populate(self):
        super(VehicleCompareCartPopover, self)._populate()
        self._cartDP = _VehicleCompareCartDataProvider()
        self._cartDP.setFlashObject(self.as_getDPS())
        self._cartDP.rebuildList(self.comparisonBasket.getVehiclesCDs())
        self.comparisonBasket.onChange += self.__onBasketChange
        self.comparisonBasket.onSwitchChange += self.__onVehCmpBasketStateChanged
        self.__initControls()

    def _dispose(self):
        super(VehicleCompareCartPopover, self)._dispose()
        self.comparisonBasket.onChange -= self.__onBasketChange
        self.comparisonBasket.onSwitchChange -= self.__onVehCmpBasketStateChanged
        self._cartDP.fini()
        self._cartDP = None
        return

    def __onVehCmpBasketStateChanged(self):
        if not self.comparisonBasket.isEnabled():
            self.onWindowClose()
        else:
            self.__updateButtonsState()

    def __initControls(self):
        headers = [packHeaderColumnData('nationId', 49, 30, tooltip=VEH_COMPARE.CARTPOPOVER_SORTING_NATION, icon=RES_ICONS.MAPS_ICONS_FILTERS_NATIONS_ALL),
         packHeaderColumnData('typeIndex', 45, 30, tooltip=VEH_COMPARE.CARTPOPOVER_SORTING_VEHTYPE, icon=RES_ICONS.MAPS_ICONS_FILTERS_TANKS_ALL),
         packHeaderColumnData('level', 45, 30, tooltip=VEH_COMPARE.CARTPOPOVER_SORTING_VEHLVL, icon=RES_ICONS.MAPS_ICONS_BUTTONS_TAB_SORT_BUTTON_LEVEL),
         packHeaderColumnData('shortUserName', 140, 30, label=VEH_COMPARE.CARTPOPOVER_SORTING_VEHNAME, tooltip=VEH_COMPARE.CARTPOPOVER_SORTING_VEHNAME_TOOLTIP),
         packHeaderColumnData('actions', 1, 30)]
        self.as_setInitDataS({'title': text_styles.highTitle(_ms(VEH_COMPARE.CARTPOPOVER_TITLE)),
         'tableHeaders': headers})
        self.__updateButtonsState()

    def __onBasketChange(self, _):
        self.__updateButtonsState()

    def __updateButtonsState(self):
        count = self.comparisonBasket.getVehiclesCount()
        buttonsEnabled = count > 0
        if self.comparisonBasket.isFull():
            addBtnTT = VEH_COMPARE.CARTPOPOVER_FULLBASKETCMPBTN_TOOLTIP
            addBtnIcon = RES_ICONS.MAPS_ICONS_LIBRARY_ALERTICON
        else:
            addBtnTT = VEH_COMPARE.CARTPOPOVER_OPENCMPBTN_TOOLTIP
            addBtnIcon = None
        isNavigationEnabled = not g_prbLoader.getDispatcher().getFunctionalState().isNavigationDisabled()
        self.as_updateToCmpBtnPropsS({'btnLabel': _ms(VEH_COMPARE.CARTPOPOVER_GOTOCOMPAREBTN_LABEL, value=count),
         'btnTooltip': addBtnTT,
         'btnEnabled': buttonsEnabled and isNavigationEnabled,
         'btnIcon': addBtnIcon})
        isBasketLocked = self.comparisonBasket.isLocked
        self.as_updateClearBtnPropsS({'btnLabel': VEH_COMPARE.CARTPOPOVER_REMOVEALLBTN_LABEL,
         'btnTooltip': VEH_COMPARE.CARTPOPOVER_REMOVEBTNLOCKED_TOOLTIP if isBasketLocked else VEH_COMPARE.CARTPOPOVER_REMOVEALLBTN_TOOLTIP,
         'btnEnabled': buttonsEnabled and not isBasketLocked})
        return
Ejemplo n.º 20
0
class VOIPManager(VOIPHandler):
    settingsCore = dependency.descriptor(ISettingsCore)

    def __init__(self):
        _logger.info('Create')
        super(VOIPManager, self).__init__()
        self.__initialized = False
        self.__enabled = False
        self.__enabledChannelID = None
        self.__voipServer = ''
        self.__voipDomain = ''
        self.__testDomain = ''
        self.__user = ['', '']
        self.__channel = ['', '']
        self.__currentChannel = ''
        self.__isChannelRejoin = False
        self.__inTesting = False
        self.__loggedIn = False
        self.__needLogginAfterInit = False
        self.__normalLogout = False
        self.__loginAttemptsRemained = 2
        self.__fsm = VOIPFsm()
        self.__expBackOff = backoff.ExpBackoff(_BACK_OFF_MIN_DELAY,
                                               _BACK_OFF_MAX_DELAY,
                                               _BACK_OFF_MODIFIER,
                                               _BACK_OFF_EXP_RANDOM_FACTOR)
        self.__reLoginCallbackID = None
        self.__activateMicByVoice = False
        self.__captureDevices = []
        self.__currentCaptureDevice = ''
        self.__channelUsers = {}
        self.onCaptureDevicesUpdated = Event.Event()
        self.onPlayerSpeaking = Event.Event()
        self.onInitialized = Event.Event()
        self.onFailedToConnect = Event.Event()
        self.onJoinedChannel = Event.Event()
        self.onLeftChannel = Event.Event()
        self.__fsm.onStateChanged += self.__onStateChanged
        return

    @proto_getter(PROTO_TYPE.BW_CHAT2)
    def bwProto(self):
        return None

    @storage_getter('users')
    def usersStorage(self):
        return None

    @proto_getter(PROTO_TYPE.MIGRATION)
    def proto(self):
        return None

    def destroy(self):
        self.__fsm.onStateChanged -= self.__onStateChanged
        self.__cancelReloginCallback()
        BigWorld.VOIP.finalise()
        _logger.info('Destroy')

    def isEnabled(self):
        return self.__enabled

    def isInitialized(self):
        return self.__initialized

    def isNotInitialized(self):
        return not self.__initialized and self.getState() == STATE.NONE

    def isInTesting(self):
        return self.__inTesting

    def getVOIPDomain(self):
        return self.__voipDomain

    def getCurrentChannel(self):
        return self.__currentChannel

    def isVoiceSupported(self):
        return self.getVOIPDomain() != '' and self.isInitialized()

    def isChannelAvailable(self):
        return True if self.bwProto.voipProvider.getChannelParams(
        )[0] else False

    def hasDesiredChannel(self):
        channelUrl = self.__channel[0]
        if channelUrl == self.__testDomain:
            return True
        currentChannelID = hash(channelUrl)
        return self.__enabledChannelID == currentChannelID

    def getUser(self):
        return self.__user[0]

    def isInDesiredChannel(self):
        if not self.__channel[0] == self.__currentChannel:
            return False
        if self.__currentChannel == self.__testDomain:
            return True
        currentChannelID = hash(self.__currentChannel)
        return self.__enabledChannelID == currentChannelID

    def getCaptureDevices(self):
        return self.__captureDevices

    def getCurrentCaptureDevice(self):
        return self.__currentCaptureDevice

    def getState(self):
        return self.__fsm.getState()

    def getAPI(self):
        return BigWorld.VOIP.getAPI()

    def isLoggedIn(self):
        return self.__loggedIn

    def onConnected(self):
        _logger.info('Subscribe')
        self.__loginAttemptsRemained = 2
        voipEvents = g_messengerEvents.voip
        voipEvents.onChannelAvailable += self.__me_onChannelAvailable
        voipEvents.onChannelLost += self.__me_onChannelLost
        voipEvents.onCredentialReceived += self.__me_onCredentialReceived
        usersEvents = g_messengerEvents.users
        usersEvents.onUsersListReceived += self.__me_onUsersListReceived
        usersEvents.onUserActionReceived += self.__me_onUserActionReceived

    def onDisconnected(self):
        _logger.info('Unsubscribe')
        voipEvents = g_messengerEvents.voip
        voipEvents.onChannelAvailable -= self.__me_onChannelAvailable
        voipEvents.onChannelLost -= self.__me_onChannelLost
        voipEvents.onCredentialReceived -= self.__me_onCredentialReceived
        usersEvents = g_messengerEvents.users
        usersEvents.onUsersListReceived -= self.__me_onUsersListReceived
        usersEvents.onUserActionReceived -= self.__me_onUserActionReceived

    def enable(self, enabled, isInitFromPrefs=False):
        if enabled:
            self.__enable(isInitFromPrefs)
        else:
            dbIDs = set()
            for dbID, data in self.__channelUsers.iteritems():
                if data['talking']:
                    dbIDs.add(dbID)

            self.__disable()
        self.__fsm.update(self)

    def applyChannelSetting(self, isEnabled, channelID):
        self.__enabledChannelID = channelID if isEnabled else None
        self.__fsm.update(self)
        return

    def enableCurrentChannel(self, isEnabled=True, autoEnableVOIP=True):
        needsEnableVOIP = isEnabled and not self.settingsCore.getSetting(
            SOUND.VOIP_ENABLE)
        if autoEnableVOIP and needsEnableVOIP:
            self.settingsCore.applySetting(SOUND.VOIP_ENABLE, True)
        params = self.bwProto.voipProvider.getChannelParams()
        channelUrl = params[0]
        if channelUrl:
            _logger.debug(
                "VOIPManager.%s '%s'", 'EnableCurrentChannel'
                if isEnabled else 'DisabledCurrentChannel', channelUrl)
            channelID = hash(channelUrl)
            self.settingsCore.applySetting(SOUND.VOIP_ENABLE_CHANNEL,
                                           (isEnabled, channelID))
        else:
            _logger.error(
                'EnableCurrentChannel: Failed to enable channel. No channel available!'
            )

    def isCurrentChannelEnabled(self):
        params = self.bwProto.voipProvider.getChannelParams()
        channelUrl = params[0]
        if channelUrl:
            channelID = hash(channelUrl)
            return self.__enabledChannelID == channelID
        return False

    def __enable(self, isInitFromPrefs):
        _logger.info('Enable')
        self.__enabled = True
        if self.__channel[0]:
            if not self.__user[0]:
                self.__requestCredentials()
            if not isInitFromPrefs:
                self.enableCurrentChannel(True)

    def __disable(self):
        _logger.info('Disable')
        self.__enabled = False

    def initialize(self, domain, server):
        if self.__initialized:
            _logger.warning('VOIPManager is already initialized')
            return
        _logger.info('Initialize')
        self.__voipServer = server
        self.__voipDomain = domain
        self.__testDomain = 'sip:confctl-2@' + self.__voipDomain
        _logger.debug("voip_server: '%s'", self.__voipServer)
        _logger.debug("voip_domain: '%s'", self.__voipDomain)
        _logger.debug("test_domain: '%s'", self.__testDomain)
        self.__fsm.update(self)
        logLevel = 0
        section = Settings.g_instance.userPrefs
        if section.has_key('development'):
            section = section['development']
            if section.has_key('vivoxLogLevel'):
                logLevel = section['vivoxLogLevel'].asInt
        vinit = {
            VOIPCommon.KEY_SERVER: 'http://%s/api2' % self.__voipServer,
            VOIPCommon.KEY_MIN_PORT: '0',
            VOIPCommon.KEY_MAX_PORT: '0',
            VOIPCommon.KEY_LOG_PREFIX: 'voip',
            VOIPCommon.KEY_LOG_SUFFIX: '.txt',
            VOIPCommon.KEY_LOG_FOLDER: '.',
            VOIPCommon.KEY_LOG_LEVEL: str(logLevel)
        }
        BigWorld.VOIP.initialise(vinit)

    def __login(self, name, password):
        if not self.__initialized:
            self.__needLogginAfterInit = True
        self.__user = [name, password]
        if not self.__needLogginAfterInit:
            self.__fsm.update(self)

    def __loginUser(self):
        _logger.info('Login Request: %s', self.__user[0])
        cmd = {VOIPCommon.KEY_PARTICIPANT_PROPERTY_FREQUENCY: '100'}
        BigWorld.VOIP.login(self.__user[0], self.__user[1], cmd)

    def __loginUserOnCallback(self):
        self.__reLoginCallbackID = None
        self.__loginUser()
        return

    def __reloginUser(self):
        self.__loginAttemptsRemained -= 1
        _logger.warning('VOIPHandler.ReloginUser. Attempts remained: %d',
                        self.__loginAttemptsRemained)
        if self.__enabled:
            self.__requestCredentials(1)

    def __cancelReloginCallback(self):
        if self.__reLoginCallbackID is not None:
            BigWorld.cancelCallback(self.__reLoginCallbackID)
            self.__reLoginCallbackID = None
        return

    def __setReloginCallback(self):
        delay = self.__expBackOff.next()
        _logger.info('__setReloginCallback. Next attempt after %d seconds',
                     delay)
        self.__reLoginCallbackID = BigWorld.callback(
            delay, self.__loginUserOnCallback)

    def logout(self):
        _logger.info('Logout')
        self.__clearUser()
        self.__clearDesiredChannel()
        self.__fsm.update(self)

    def __setAvailableChannel(self, channel, password):
        if not self.__initialized and self.__fsm.inNoneState():
            self.initialize(self.__voipDomain, self.__voipServer)
        if not self.__user[0] and self.isEnabled():
            self.__requestCredentials()
        _logger.info('ReceivedAvailableChannel: %s', channel)
        self.__channel = [channel, password]
        self.__fsm.update(self)
        self.__evaluateAutoJoinChannel(channel)

    def __evaluateAutoJoinChannel(self, newChannel):
        if newChannel == self.__testDomain:
            return
        _, channelID = self.settingsCore.getSetting(SOUND.VOIP_ENABLE_CHANNEL)
        newChannelID = hash(newChannel)
        if channelID != newChannelID:
            self.enableCurrentChannel(self.__isAutoJoinChannel(),
                                      autoEnableVOIP=False)

    def __joinChannel(self, channel, password):
        _logger.info("JoinChannel '%s'", channel)
        BigWorld.VOIP.joinChannel(channel, password)

    def __leaveChannel(self):
        if not self.__initialized:
            return
        _logger.info('LeaveChannel')
        self.__clearDesiredChannel()
        self.__fsm.update(self)

    def enterTestChannel(self):
        if self.__inTesting:
            return
        _logger.info('EnterTestChannel: %s', self.__testDomain)
        self.__inTesting = True
        self.__setAvailableChannel(self.__testDomain, '')

    def leaveTestChannel(self):
        if not self.__inTesting:
            return
        _logger.info('LeaveTestChannel')
        self.__inTesting = False
        params = self.bwProto.voipProvider.getChannelParams()
        if params[0]:
            self.__setAvailableChannel(*params)
        else:
            self.__leaveChannel()

    def setMasterVolume(self, attenuation):
        BigWorld.VOIP.setMasterVolume(attenuation)

    def setMicrophoneVolume(self, attenuation):
        BigWorld.VOIP.setMicrophoneVolume(attenuation)

    def __setVolume(self):
        self.setMasterVolume(
            int(
                round(
                    SoundGroups.g_instance.getVolume(
                        VOIPCommon.KEY_VOIP_MASTER) * 100)))
        self.setMicrophoneVolume(
            int(
                round(
                    SoundGroups.g_instance.getVolume(VOIPCommon.KEY_VOIP_MIC) *
                    100)))

    def __muffleMasterVolume(self):
        SoundGroups.g_instance.muffleWWISEVolume()

    def __restoreMasterVolume(self):
        SoundGroups.g_instance.restoreWWISEVolume()

    def setVoiceActivation(self, enabled):
        _logger.debug('SetVoiceActivation: %s', str(enabled))
        self.__activateMicByVoice = enabled
        self.setMicMute(not enabled)

    def setMicMute(self, muted=True):
        if not self.__initialized:
            return
        if muted and self.__activateMicByVoice:
            return
        self.__setMicMute(muted)

    def __setMicMute(self, muted):
        _logger.debug('SetMicMute: %s', str(muted))
        if muted:
            BigWorld.VOIP.disableMicrophone()
        else:
            BigWorld.VOIP.enableMicrophone()

    def requestCaptureDevices(self):
        _logger.debug('RequestCaptureDevices')
        BigWorld.VOIP.getCaptureDevices()

    def setCaptureDevice(self, deviceName):
        _logger.info('SetCaptureDevice: %s', deviceName)
        BigWorld.VOIP.setCaptureDevice(deviceName)

    def isParticipantTalking(self, dbid):
        outcome = self.__channelUsers.get(dbid, {}).get('talking', False)
        return outcome

    def __requestCredentials(self, reset=0):
        _logger.info('RequestUserCredentials')
        self.bwProto.voipProvider.requestCredentials(reset)

    def __clearDesiredChannel(self):
        self.__channel = ['', '']

    def __clearUser(self):
        self.__user = ['', '']

    def __onChatActionMute(self, dbid, muted):
        _logger.debug('OnChatActionMute: dbID = %d, muted = %r', dbid, muted)
        if dbid in self.__channelUsers and self.__channelUsers[dbid][
                'muted'] != muted:
            self.__muteParticipantForMe(dbid, muted)

    def __muteParticipantForMe(self, dbid, mute):
        _logger.debug('MuteParticipantForMe: %d, %s', dbid, str(mute))
        self.__channelUsers[dbid]['muted'] = mute
        uri = self.__channelUsers[dbid]['uri']
        cmd = {
            VOIPCommon.KEY_COMMAND: VOIPCommon.CMD_SET_PARTICIPANT_MUTE,
            VOIPCommon.KEY_PARTICIPANT_URI: uri,
            VOIPCommon.KEY_STATE: str(mute)
        }
        BigWorld.VOIP.command(cmd)
        return True

    def __isAnyoneTalking(self):
        for info in self.__channelUsers.values():
            if info['talking']:
                return True

        return False

    def __extractDBIDFromURI(self, uri):
        try:
            domain = self.__voipDomain
            login = uri.partition('sip:')[2].rpartition('@' + domain)[0]
            s = login[login.find('.') + 1:]
            return (int(s), login)
        except Exception:
            return -1

    def __sendLeaveChannelCommand(self, channel):
        _logger.info('Leaving channel %s', channel)
        if channel:
            BigWorld.VOIP.leaveChannel(channel)
        self.__fsm.update(self)

    def __resetToInitializedState(self):
        _logger.debug('resetToInitializesState')
        if self.__currentChannel != '':
            for dbid in self.__channelUsers.iterkeys():
                self.onPlayerSpeaking(dbid, False)

            self.__channelUsers.clear()
            self.__restoreMasterVolume()
            self.__currentChannel = ''
        if self.__needLogginAfterInit:
            self.__fsm.update(self)
            self.__needLogginAfterInit = False

    def __onStateChanged(self, _, newState):
        if newState == STATE.INITIALIZED:
            self.__resetToInitializedState()
        elif newState == STATE.LOGGING_IN:
            self.__loginUser()
        elif newState == STATE.LOGGED_IN:
            self.__fsm.update(self)
        elif newState == STATE.JOINING_CHANNEL:
            muteMic = self.__channel[
                0] != self.__testDomain and not self.__activateMicByVoice
            self.setMicMute(muteMic)
            self.__joinChannel(self.__channel[0], self.__channel[1])
        elif newState == STATE.JOINED_CHANNEL:
            _logger.info('Joined to channel: %s', self.__currentChannel)
            self.__fsm.update(self)
        elif newState == STATE.LEAVING_CHANNEL:
            self.__sendLeaveChannelCommand(self.getCurrentChannel())
        elif newState == STATE.LOGGING_OUT:
            self.__normalLogout = True
            BigWorld.VOIP.logout()

    def onVoipInited(self, data):
        _logger.debug('onVoipInited')
        returnCode = int(data[VOIPCommon.KEY_RETURN_CODE])
        if returnCode == VOIPCommon.CODE_SUCCESS:
            self.__initialized = True
            self.__fsm.update(self)
            self.onInitialized(data)
        else:
            self.__initialized = False
            self.__fsm.reset()
            _logger.info('---------------------------')
            _logger.info("ERROR: '%d' - '%s'",
                         int(data[VOIPCommon.KEY_STATUS_CODE]),
                         data[VOIPCommon.KEY_STATUS_STRING])
            _logger.info('---------------------------')

    def onVoipDestroyed(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Voip is not destroyed: %r', data)

    def onCaptureDevicesArrived(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Capture devices are not arrived: %r', data)
            return
        captureDevicesCount = int(data[VOIPCommon.KEY_COUNT])
        self.__captureDevices = []
        for i in xrange(captureDevicesCount):
            self.__captureDevices.append(
                str(data[VOIPCommon.KEY_CAPTURE_DEVICES + '_' + str(i)]))

        self.__currentCaptureDevice = str(
            data[VOIPCommon.KEY_CURRENT_CAPTURE_DEVICE])
        self.onCaptureDevicesUpdated()

    def onSetCaptureDevice(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Capture device is not set: %r', data)

    def onSetLocalSpeakerVolume(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Local speaker volume is not set: %r', data)

    def onSetLocalMicVolume(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Local microphone volume is not set: %r', data)

    def onMuteLocalMic(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Local microphone volume is not muted: %r', data)

    def onLoginStateChange(self, data):
        returnCode = int(data[VOIPCommon.KEY_RETURN_CODE])
        statusCode = int(data[VOIPCommon.KEY_STATUS_CODE])
        statusString = data[VOIPCommon.KEY_STATUS_STRING]
        _logger.debug('onLoginStateChange: Return code %s', returnCode)
        if returnCode == VOIPCommon.CODE_SUCCESS:
            state = int(data[VOIPCommon.KEY_STATE])
            _logger.debug('Return state %s', state)
            if state == VOIPCommon.STATE_LOGGED_IN:
                _logger.debug('onLoginStateChange: LOGGED IN')
                if self.getAPI() == VOIP_SUPPORTED_API.VIVOX:
                    self.bwProto.voipProvider.logVivoxLogin()
                self.__loggedIn = True
                self.__expBackOff.reset()
                if self.__fsm.getState() == STATE.JOINED_CHANNEL:
                    self.__joinChannel(self.__channel[0], self.__channel[1])
                self.__fsm.update(self)
            elif state == VOIPCommon.STATE_LOGGED_OUT:
                _logger.debug('onLoginStateChange: LOGGED OUT %d - %s',
                              statusCode, statusString)
                if self.__normalLogout:
                    _logger.debug('onLoginStateChange: Normal logout')
                    self.__normalLogout = False
                    self.__loggedIn = False
                    self.__fsm.update(self)
                elif self.__reLoginCallbackID is None:
                    _logger.debug('onLoginStateChange: Network lost logout')
                    self.__setReloginCallback()
            elif state == VOIPCommon.STATE_LOGGIN_OUT:
                _logger.debug('onLoginStateChange: LOGGING OUT %d - %s',
                              statusCode, statusString)
        else:
            _logger.info('---------------------------')
            _logger.info("ERROR: '%d' - '%s'", statusCode, statusString)
            _logger.info('---------------------------')
            if (statusCode == VOIPCommon.STATUS_WRONG_CREDENTIALS
                    or statusCode == VOIPCommon.STATUS_UNKNOWN_ACCOUNT
                ) and self.__loginAttemptsRemained > 0:
                self.__reloginUser()
            else:
                self.onFailedToConnect()
        return

    def onSessionAdded(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Session is not added: %r', data)
            return
        currentChannel = self.__currentChannel = data[VOIPCommon.KEY_URI]
        self.__setVolume()
        self.__fsm.update(self)
        isTestChannel = currentChannel == self.__testDomain
        self.onJoinedChannel(currentChannel, isTestChannel,
                             self.__isChannelRejoin and not isTestChannel)

    def onSessionRemoved(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Session is not removed: %r', data)
            return
        for dbid in self.__channelUsers.iterkeys():
            self.onPlayerSpeaking(dbid, False)

        self.__channelUsers.clear()
        self.__restoreMasterVolume()
        leftChannel = self.__currentChannel
        wasTest = leftChannel == self.__testDomain
        self.__currentChannel = ''
        self.__fsm.update(self)
        self.onLeftChannel(leftChannel, wasTest)

    def onNetworkTest(self, data):
        returnCode = int(data[VOIPCommon.KEY_RETURN_CODE])
        if returnCode == VOIPCommon.CODE_ERROR:
            _logger.info('---------------------------')
            _logger.info("ERROR: '%d' - '%s'",
                         int(data[VOIPCommon.KEY_STATUS_CODE]),
                         data[VOIPCommon.KEY_STATUS_STRING])
            _logger.info('---------------------------')
            self.onFailedToConnect()
            self.__clearDesiredChannel()
            self.__clearUser()

    def onParticipantAdded(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Participant is not added: %r', data)
            return
        uri = data[VOIPCommon.KEY_PARTICIPANT_URI]
        dbid, _ = self.__extractDBIDFromURI(uri)
        if dbid == -1:
            return
        self.__channelUsers[dbid] = {
            'talking': False,
            'uri': uri,
            'muted': False
        }
        user = self.usersStorage.getUser(dbid)
        if user and user.isMuted():
            self.__muteParticipantForMe(dbid, True)

    def onParticipantRemoved(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Participant is not removed: %r', data)
            return
        uri = data[VOIPCommon.KEY_PARTICIPANT_URI]
        dbid, _ = self.__extractDBIDFromURI(uri)
        if dbid in self.__channelUsers:
            del self.__channelUsers[dbid]
        self.onPlayerSpeaking(dbid, False)

    def onParticipantUpdated(self, data):
        if int(data[VOIPCommon.KEY_RETURN_CODE]) != VOIPCommon.CODE_SUCCESS:
            _logger.error('Participant is not updated: %r', data)
            return
        uri = data[VOIPCommon.KEY_PARTICIPANT_URI]
        dbid, _ = self.__extractDBIDFromURI(uri)
        if dbid == -1:
            return
        talking = int(data[VOIPCommon.KEY_IS_SPEAKING])
        if dbid in self.__channelUsers:
            channelUser = self.__channelUsers[dbid]
            if channelUser['talking'] != talking:
                channelUser['talking'] = talking
                if self.__isAnyoneTalking():
                    self.__muffleMasterVolume()
                else:
                    self.__restoreMasterVolume()
        self.onPlayerSpeaking(dbid, talking)

    @staticmethod
    def __isAutoJoinChannel():
        if hasattr(BigWorld.player(), 'arena'):
            arena = BigWorld.player().arena
            return not (arena is not None and arena.guiType
                        in (ARENA_GUI_TYPE.RANDOM, ARENA_GUI_TYPE.EPIC_RANDOM,
                            ARENA_GUI_TYPE.EPIC_BATTLE))
        else:
            return True

    def __me_onChannelAvailable(self, uri, pwd, isRejoin):
        self.__isChannelRejoin = isRejoin
        if not self.__inTesting:
            self.__setAvailableChannel(uri, pwd)

    def __me_onChannelLost(self):
        if not self.__inTesting:
            self.__leaveChannel()
            self.settingsCore.applySetting(SOUND.VOIP_ENABLE_CHANNEL,
                                           (False, 0))

    def __me_onCredentialReceived(self, name, pwd):
        _logger.debug('OnUserCredentials: %s', name)
        self.__login(name, pwd)

    def __me_onUsersListReceived(self, tags):
        if USER_TAG.MUTED not in tags:
            return
        for user in self.usersStorage.getList(MutedFindCriteria()):
            dbID = user.getID()
            if dbID in self.__channelUsers:
                self.__muteParticipantForMe(dbID, True)

    def __me_onUserActionReceived(self, actionID, user, shadowMode):
        if actionID in (USER_ACTION_ID.MUTE_SET, USER_ACTION_ID.MUTE_UNSET):
            self.__onChatActionMute(user.getID(), user.isMuted())
Ejemplo n.º 21
0
class RankedBattlesView(LobbySubView, RankedBattlesViewMeta):
    __background_alpha__ = 0.5
    itemsCache = dependency.descriptor(IItemsCache)
    rankedController = dependency.descriptor(IRankedBattlesController)

    def onEscapePress(self):
        self.__close()

    def onCloseBtnClick(self):
        self.__close()

    def onAwardClick(self, blockID):
        if blockID == _AWARD_BLOCK_IDS.WEB_LEAGUE:
            self.rankedController.openWebLeaguePage(ctx={
                'returnAlias':
                RANKEDBATTLES_ALIASES.RANKED_BATTLES_VIEW_ALIAS
            })
        elif blockID == _AWARD_BLOCK_IDS.BOOBY_QUEST:
            consolationQuest = self.rankedController.getConsolationQuest()
            if consolationQuest is not None:
                showMissionDetails(missionID=consolationQuest.getID(),
                                   groupID=consolationQuest.getGroupID())
        elif blockID == _AWARD_BLOCK_IDS.SEASON_AWARDS:
            g_eventBus.handleEvent(events.LoadViewEvent(
                RANKEDBATTLES_ALIASES.RANKED_BATTLES_CYCLES_VIEW_ALIAS),
                                   scope=EVENT_BUS_SCOPE.LOBBY)
        return

    def _populate(self):
        super(RankedBattlesView, self)._populate()
        self.rankedController.onUpdated += self.__updateData
        self.__updateData()

    def _dispose(self):
        self.rankedController.onUpdated -= self.__updateData
        super(RankedBattlesView, self)._dispose()

    def __setData(self, leagueData=None):
        self.as_setDataS({
            'header':
            text_styles.superPromoTitle(RANKED_BATTLES.RANKEDBATTLEVIEW_TITLE),
            'closeLbl':
            RANKED_BATTLES.RANKEDBATTLEVIEW_CLOSEBTN,
            'closeDescr':
            RANKED_BATTLES.RANKEDBATTLEVIEW_CLOSEBTNDESCR,
            'playVideoLbl':
            RANKED_BATTLES.RANKEDBATTLEVIEW_PLAYVIDEOBTN,
            'playVideoBtnEnabled':
            False,
            'calendarStatus':
            self.__getStatusBlock(),
            'progressBlock':
            self.__buildProgressData(),
            'awardsBlock':
            self.__getAwardsBlock(leagueData),
            'bgImgPath':
            RES_ICONS.MAPS_ICONS_RANKEDBATTLES_BG_RANK_BLUR,
            'isUpdateProgress':
            False
        })

    def __updateData(self):
        self.__setData()
        self.rankedController.getLeagueData()(self.__setData)

    def __updateProgress(self):
        self.as_setDataS({
            'progressBlock': self.__buildProgressData(),
            'isUpdateProgress': True
        })

    def __close(self):
        self.fireEvent(events.LoadViewEvent(VIEW_ALIAS.LOBBY_HANGAR),
                       scope=EVENT_BUS_SCOPE.LOBBY)
        self.destroy()

    def __getStatusBlock(self):
        status, timeLeft = self.rankedController.getPrimeTimeStatus()
        showPrimeTimeAlert = status != PRIME_TIME_STATUS.AVAILABLE
        return {
            'alertIcon':
            RES_ICONS.MAPS_ICONS_LIBRARY_ALERTBIGICON
            if showPrimeTimeAlert else None,
            'buttonIcon':
            RES_ICONS.MAPS_ICONS_BUTTONS_CALENDAR,
            'buttonLabel':
            '',
            'buttonVisible':
            True,
            'buttonTooltip':
            makeTooltip(
                RANKED_BATTLES.
                RANKEDBATTLEVIEW_STATUSBLOCK_CALENDARBTNTOOLTIP_HEADER,
                RANKED_BATTLES.
                RANKEDBATTLEVIEW_STATUSBLOCK_CALENDARBTNTOOLTIP_BODY),
            'statusText':
            self.__getAlertStatusText(timeLeft)
            if showPrimeTimeAlert else self.__getStatusText(),
            'popoverAlias':
            RANKEDBATTLES_ALIASES.RANKED_BATTLES_CALENDAR_POPOVER,
            'bgVisible':
            False,
            'shadowFilterVisible':
            showPrimeTimeAlert
        }

    def __buildProgressData(self):
        if self.rankedController.isAccountMastered():
            rank = self.rankedController.getCurrentRank()
            result = [
                self.__packProgressInfo(
                    RES_ICONS.MAPS_ICONS_RANKEDBATTLES_ICON_VICTORY,
                    text_styles.vehicleName(
                        _ms(RANKED_BATTLES.
                            RANKEDBATTLEVIEW_PROGRESSBLOCK_FINALRANK))),
                self.__packRank(rank),
                self.__packProgressInfo(
                    RES_ICONS.MAPS_ICONS_RANKEDBATTLES_ICON_FINAL_CUP_150X100,
                    text_styles.vehicleName(
                        _ms(RANKED_BATTLES.
                            RANKEDBATTLEVIEW_PROGRESSBLOCK_CONTINUE)))
            ]
        else:
            result = [
                self.__packRank(rank)
                for rank in self.rankedController.getRanksChain()
                if rank.getID() != 0
            ]
        return result

    def __packRank(self, rank):
        isCurrent = rank.isCurrent()
        isFinal = isCurrent and rank.getID(
        ) == self.rankedController.getAccRanksTotal()
        bgImage = ''
        if isCurrent or isFinal:
            bgImage = RES_ICONS.MAPS_ICONS_RANKEDBATTLES_RANKEDBATTESVIEW_PIC_ICON_RANK_SHINE_364X364
        imageSize = RANKEDBATTLES_ALIASES.WIDGET_SMALL
        if isCurrent:
            imageSize = RANKEDBATTLES_ALIASES.WIDGET_HUGE if isFinal else RANKEDBATTLES_ALIASES.WIDGET_BIG
        shieldStatus = self.rankedController.getShieldStatus(
            rank=rank, isStatic=True) if not isFinal else None
        return {
            'linkage': 'RankUI',
            'rankData': {
                'rankVO':
                buildRankVO(rank,
                            isEnabled=rank.isAcquired(),
                            imageSize=imageSize,
                            shieldStatus=shieldStatus,
                            showShieldLabel=False,
                            showLadderPoints=True),
                'isBig':
                isCurrent or isFinal,
                'isFinal':
                isFinal,
                'imageBG':
                bgImage,
                'description':
                '',
                'isTransparent':
                not isCurrent,
                'curIcon':
                ''
            }
        }

    def __packProgressInfo(self, image, description):
        return {
            'linkage': 'ProgressInfoBlockUI',
            'infoData': {
                'image': image,
                'description': description
            }
        }

    def __getStepsProgressSubBlock(self,
                                   completedSteps,
                                   totalSteps,
                                   showDescription=True):
        if showDescription:
            stepsStr = text_styles.stats(completedSteps)
            description = text_styles.main(
                _ms(RANKED_BATTLES.RANKEDBATTLEVIEW_PROGRESSBLOCK_STEPS,
                    numbers='{} / {}'.format(stepsStr, totalSteps)))
        else:
            description = ''
        steps = []
        for idx in xrange(1, totalSteps + 1):
            if idx <= completedSteps:
                steps.append(
                    {'state': RANKEDBATTLES_ALIASES.STEP_RECEIVED_STATE})
            else:
                steps.append(
                    {'state': RANKEDBATTLES_ALIASES.STEP_NOT_RECEIVED_STATE})

        return {
            'linkage': 'StepsContainerUI',
            'stepsData': {
                'countText': description,
                'nextCountText': '',
                'steps': steps
            }
        }

    def __getAwardsBlock(self, leagueData=None):
        consolationQuest = self.rankedController.getConsolationQuest()
        consolationQuestBattlesLeft = None
        if consolationQuest is not None and not consolationQuest.isCompleted():
            battlesCondition = consolationQuest.bonusCond.getConditions().find(
                'battles')
            if battlesCondition is not None:
                progress = battlesCondition.getProgressPerGroup()
                if None in progress:
                    currCount, total, _, _ = progress[None]
                    consolationQuestBattlesLeft = total - currCount
        battlesPlayed = self.rankedController.getCurrentCycleStats(
        )['battlesCount']
        return _AwardsBlockBuilder.pack(leagueData,
                                        consolationQuestBattlesLeft,
                                        battlesPlayed)

    def __getStatusText(self):
        season = self.rankedController.getCurrentSeason()
        endTimeStr = self.__getTillTimeString(season.getCycleEndDate())
        key = RANKED_BATTLES.RANKEDBATTLEVIEW_STATUSBLOCK_STATUSTEXT
        return text_styles.stats(i18n.makeString(key)) + endTimeStr

    def __getAlertStatusText(self, timeLeft):
        timeLeftStr = time_utils.getTillTimeString(
            timeLeft, RANKED_BATTLES.STATUS_TIMELEFT)
        return text_styles.vehicleStatusCriticalText(
            _ms(RANKED_BATTLES.PRIMETIMEALERTMESSAGEBLOCK_MESSAGE,
                time=timeLeftStr))

    def __getTillTimeString(self, endTime):
        timeDelta = time_utils.getTimeDeltaFromNow(endTime)
        if timeDelta > time_utils.ONE_DAY:
            formatter = text_styles.neutral
        else:
            formatter = text_styles.alert
        return formatter(
            time_utils.getTillTimeString(timeDelta,
                                         RANKED_BATTLES.STATUS_TIMELEFT))
Ejemplo n.º 22
0
class BattleRoyaleWebApi(W2CSchema):
    __battleRoyale = dependency.descriptor(IBattleRoyaleController)
    __itemsCache = dependency.descriptor(IItemsCache)

    @w2c(W2CSchema, name='get_calendar_info')
    def handleGetCalendarInfo(self, _):
        calendarData = dict()
        for season in self.__getSeasons():
            if season is not None:
                calendarData['season'] = {
                    'id': season.getSeasonID(),
                    'start': season.getStartDate(),
                    'end': season.getEndDate()
                }
                calendarData['cycles'] = [{
                    'id': cycle.ID,
                    'start': cycle.startDate,
                    'end': cycle.endDate,
                    'announce_only': cycle.announceOnly
                } for cycle in season.getAllCycles().values()]

        return calendarData

    @w2c(W2CSchema, name='get_seasons_achievements')
    def getSeasonAchievements(self, _):
        dossierDescr = self.__itemsCache.items.getAccountDossier(
        ).getDossierDescr()
        seasonsAchievements = self.__getSeasonAchievements(
            dossierDescr.expand('battleRoyaleSeasons'),
            BattleRoyaleSeasonAchievements)
        currentSeason = self.__battleRoyale.getCurrentSeason()
        if currentSeason and currentSeason.getCycleID():
            now = time_utils.getCurrentLocalServerTimestamp()
            stats = self.__battleRoyale.getStats()
            seasonsAchievements[currentSeason.getSeasonID(),
                                currentSeason.getCycleID()] = {
                                    'battle_count':
                                    stats.battleCount,
                                    'kill_count':
                                    stats.killCount,
                                    'top1':
                                    stats.topCount,
                                    'season_id':
                                    currentSeason.getSeasonID(),
                                    'episode_id':
                                    currentSeason.getCycleID()
                                    or currentSeason.getLastActiveCycleID(now)
                                }
        return seasonsAchievements.values()

    def __getSeasonAchievements(self, achievements, template):
        seasonsAchievements = {}
        for seasonID, cycleID in achievements:
            if not self.__validateSeasonData(seasonID, cycleID):
                continue
            key = (seasonID, cycleID)
            seasonsAchievements[key] = template(
                *(key + achievements[key]))._asdict()

        return seasonsAchievements

    def __validateSeasonData(self, seasonID, cycleID):
        seasons = self.__getSeasons()
        seasonValidationData = {
            season.getSeasonID():
            [cycle.ID for cycle in season.getAllCycles().values()]
            for season in seasons if season is not None
        }
        return seasonID in seasonValidationData and cycleID in seasonValidationData.get(
            seasonID, [])

    def __getSeasons(self):
        return (self.__battleRoyale.getCurrentSeason(),
                self.__battleRoyale.getNextSeason(),
                self.__battleRoyale.getPreviousSeason())
class BattleTypeSelectPopover(BattleTypeSelectPopoverMeta):
    __rankedController = dependency.descriptor(IRankedBattlesController)
    __lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self, _=None):
        super(BattleTypeSelectPopover, self).__init__()
        self._tooltip = None
        return

    def selectFight(self, actionName):
        self.__selectFight(actionName)

    def getTooltipData(self, itemData, itemIsDisabled):
        if itemData is None:
            return
        else:
            tooltip = ''
            isSpecial = False
            if itemData == PREBATTLE_ACTION_NAME.RANDOM:
                tooltip = TOOLTIPS.BATTLETYPES_STANDART
            elif itemData == PREBATTLE_ACTION_NAME.EPIC:
                tooltip, isSpecial = self.__getEpicAvailabilityData()
            elif itemData == PREBATTLE_ACTION_NAME.RANKED:
                tooltip, isSpecial = self.__getRankedAvailabilityData()
            elif itemData == PREBATTLE_ACTION_NAME.E_SPORT:
                tooltip = TOOLTIPS.BATTLETYPES_UNIT
            elif itemData == PREBATTLE_ACTION_NAME.STRONGHOLDS_BATTLES_LIST:
                if not itemIsDisabled:
                    tooltip = TOOLTIPS.BATTLETYPES_STRONGHOLDS
                else:
                    tooltip = TOOLTIPS.BATTLETYPES_STRONGHOLDS_DISABLED
            elif itemData == PREBATTLE_ACTION_NAME.TRAININGS_LIST:
                tooltip = TOOLTIPS.BATTLETYPES_TRAINING
            elif itemData == PREBATTLE_ACTION_NAME.EPIC_TRAINING_LIST:
                tooltip = TOOLTIPS.BATTLETYPES_EPIC_TRAINING
            elif itemData == PREBATTLE_ACTION_NAME.SPEC_BATTLES_LIST:
                tooltip = TOOLTIPS.BATTLETYPES_SPEC
            elif itemData == PREBATTLE_ACTION_NAME.BATTLE_TUTORIAL:
                tooltip = TOOLTIPS.BATTLETYPES_BATTLETUTORIAL
            elif itemData == PREBATTLE_ACTION_NAME.SANDBOX:
                isSpecial = True
                tooltip = TOOLTIPS_CONSTANTS.BATTLE_TRAINING
            elif itemData == PREBATTLE_ACTION_NAME.BATTLE_ROYALE:
                tooltip = TOOLTIPS_CONSTANTS.BATTLE_ROYALE_SELECTOR_INFO
                isSpecial = True
            elif itemData == PREBATTLE_ACTION_NAME.MAPBOX:
                tooltip = TOOLTIPS_CONSTANTS.MAPBOX_SELECTOR_INFO
                isSpecial = True
            result = {'isSpecial': isSpecial, 'tooltip': tooltip}
            self._tooltip = tooltip
            return result

    def demoClick(self):
        demonstratorWindow = self.app.containerManager.getView(
            WindowLayer.WINDOW,
            criteria={
                POP_UP_CRITERIA.VIEW_ALIAS: VIEW_ALIAS.DEMONSTRATOR_WINDOW
            })
        if demonstratorWindow is not None:
            demonstratorWindow.onWindowClose()
        else:
            self.fireEvent(
                LoadViewEvent(SFViewLoadParams(
                    VIEW_ALIAS.DEMONSTRATOR_WINDOW)), EVENT_BUS_SCOPE.LOBBY)
        return

    def update(self):
        if not self.isDisposed():
            self.as_updateS(*battle_selector_items.getItems().getVOs())

    def _populate(self):
        super(BattleTypeSelectPopover, self)._populate()
        self.update()

    def __getRankedAvailabilityData(self):
        return (TOOLTIPS_CONSTANTS.RANKED_SELECTOR_INFO,
                True) if self.__rankedController.isAvailable() else (
                    TOOLTIPS_CONSTANTS.RANKED_UNAVAILABLE_INFO, True)

    def __getEpicAvailabilityData(self):
        return (TOOLTIPS_CONSTANTS.EPIC_BATTLE_SELECTOR_INFO, True)

    @process
    def __selectFight(self, actionName):
        navigationPossible = yield self.__lobbyContext.isHeaderNavigationPossible(
        )
        if not navigationPossible:
            return
        battle_selector_items.getItems().select(actionName)
class EpicMetaGameUnavailableTooltip(BlocksTooltipData):
    connectionMgr = dependency.descriptor(IConnectionManager)
    epicController = dependency.descriptor(IEpicBattleMetaGameController)

    def __init__(self, ctx):
        super(EpicMetaGameUnavailableTooltip,
              self).__init__(ctx, TOOLTIP_TYPE.EPIC_SELECTOR_UNAVAILABLE_INFO)
        self._setContentMargin(top=20, left=20, bottom=20, right=20)
        self._setMargins(afterBlock=20)
        self._setWidth(_TOOLTIP_MIN_WIDTH)

    def _packBlocks(self, *args):
        items = super(EpicMetaGameUnavailableTooltip, self)._packBlocks()
        items.append(self._packHeaderBlock())
        timeTableBlocks = [self._packTimeTableHeaderBlock()]
        primeTime = self.epicController.getPrimeTimes().get(
            self.connectionMgr.peripheryID, None)
        if primeTime is None or self.epicController.hasAnySeason() is None:
            return items
        else:
            todayStart, todayEnd = time_utils.getDayTimeBoundsForLocal()
            todayEnd += 1
            tomorrowStart, tomorrowEnd = todayStart + time_utils.ONE_DAY, todayEnd + time_utils.ONE_DAY
            todayPeriods = ()
            tomorrowPeriods = ()
            time, status = self.epicController.getSeasonEndTime()
            if status:
                todayPeriods = primeTime.getPeriodsBetween(
                    todayStart, min(todayEnd, time))
                if tomorrowStart < time:
                    tomorrowPeriods = primeTime.getPeriodsBetween(
                        tomorrowStart, min(tomorrowEnd, time))
                todayStr = self._packPeriods(todayPeriods)
                timeTableBlocks.append(
                    self._packTimeBlock(message=text_styles.main(
                        EPIC_BATTLE.
                        SELECTORTOOLTIP_EPICBATTLE_DISABLED_TIMETABLE_TODAY),
                                        timeStr=text_styles.bonusPreviewText(
                                            todayStr)))
                tomorrowStr = self._packPeriods(tomorrowPeriods)
                timeTableBlocks.append(
                    self._packTimeBlock(message=text_styles.main(
                        EPIC_BATTLE.
                        SELECTORTOOLTIP_EPICBATTLE_DISABLED_TIMETABLE_TOMORROW
                    ),
                                        timeStr=text_styles.stats(
                                            tomorrowStr)))
                items.append(
                    formatters.packBuildUpBlockData(
                        timeTableBlocks, 7, BLOCKS_TOOLTIP_TYPES.
                        TOOLTIP_BUILDUP_BLOCK_WHITE_BG_LINKAGE))
            items.append(
                self._getTillEndBlock(
                    time_utils.getTimeDeltaFromNow(
                        time_utils.makeLocalServerTime(time))))
            return items

    def _packHeaderBlock(self):
        return formatters.packTitleDescBlock(
            title=text_styles.highTitle(
                EPIC_BATTLE.SELECTORTOOLTIP_EPICBATTLE_DISABLED_TITLE),
            desc=text_styles.main(
                EPIC_BATTLE.SELECTORTOOLTIP_EPICBATTLE_DISABLED_DESC))

    def _packTimeTableHeaderBlock(self):
        return formatters.packImageTextBlockData(
            title=text_styles.stats(
                EPIC_BATTLE.SELECTORTOOLTIP_EPICBATTLE_DISABLED_TIMETABLE_TITLE
            ),
            img=RES_ICONS.MAPS_ICONS_BUTTONS_CALENDAR,
            imgPadding=formatters.packPadding(top=2),
            txtPadding=formatters.packPadding(left=5))

    def _packTimeBlock(self, message, timeStr):
        return formatters.packTextParameterBlockData(value=timeStr,
                                                     name=message,
                                                     valueWidth=97)

    def _packPeriods(self, periods):
        if periods:
            periodsStr = []
            for periodStart, periodEnd in periods:
                startTime = formatDate('%H:%M', periodStart)
                endTime = formatDate('%H:%M', periodEnd)
                periodsStr.append(
                    i18n.makeString(RANKED_BATTLES.CALENDARDAY_TIME,
                                    start=startTime,
                                    end=endTime))

            return '\n'.join(periodsStr)
        return i18n.makeString(
            EPIC_BATTLE.SELECTORTOOLTIP_EPICBATTLE_DISABLED_TIMETABLE_EMPTY)

    def _getTillEndBlock(self, timeLeft):
        _, status = self.epicController.getSeasonEndTime()
        if status:
            endKey = EPIC_BATTLE.SELECTORTOOLTIP_EPICBATTLE_DISABLED_TILLEND
        else:
            endKey = EPIC_BATTLE.SELECTORTOOLTIP_EPICBATTLE_DISABLED_STARTIN
        return formatters.packTextBlockData(
            text_styles.main(endKey) + ' ' + text_styles.stats(
                time_utils.getTillTimeString(
                    timeLeft,
                    MENU.HEADERBUTTONS_BATTLE_TYPES_RANKED_AVAILABILITY)))
class HitDirectionController(IViewComponentsController):
    __slots__ = ('__pull', '__ui', '__isVisible', '__callbackIDs',
                 '__damageIndicatorCrits', '__damageIndicatorAllies',
                 '__damageIndicatorExtType', '__arenaDP', '__weakref__')
    settingsCore = dependency.descriptor(ISettingsCore)
    sessionProvider = dependency.descriptor(IBattleSessionProvider)
    lobbyContext = dependency.descriptor(ILobbyContext)

    def __init__(self, setup):
        super(HitDirectionController, self).__init__()
        self.__pull = [
            _HitDirection(idx_) for idx_ in xrange(HIT_INDICATOR_MAX_ON_SCREEN)
        ]
        self.__ui = None
        self.__isVisible = False
        self.__callbackIDs = {}
        self.__damageIndicatorExtType = False
        self.__damageIndicatorCrits = False
        self.__damageIndicatorAllies = False
        self.__arenaDP = weakref.proxy(setup.arenaDP)
        return

    def getControllerID(self):
        return BATTLE_CTRL_ID.HIT_DIRECTION

    def startControl(self):
        g_eventBus.addListener(GameEvent.GUI_VISIBILITY,
                               self.__handleGUIVisibility,
                               scope=EVENT_BUS_SCOPE.BATTLE)
        self.settingsCore.onSettingsChanged += self.__onSettingsChanged

    def stopControl(self):
        self.settingsCore.onSettingsChanged -= self.__onSettingsChanged
        handler = avatar_getter.getInputHandler()
        if handler is not None:
            from AvatarInputHandler import AvatarInputHandler
            if isinstance(handler, AvatarInputHandler):
                handler.onPostmortemKillerVisionEnter -= self.__onPostmortemKillerVision
        ctrl = self.sessionProvider.shared.vehicleState
        if ctrl is not None:
            ctrl.onVehicleControlling -= self.__onVehicleControlling
        g_eventBus.removeListener(GameEvent.GUI_VISIBILITY,
                                  self.__handleGUIVisibility,
                                  scope=EVENT_BUS_SCOPE.BATTLE)
        self.__clearHideCallbacks()
        self.__arenaDP = None
        return

    def getContainer(self):
        return self.__ui

    def getHit(self, idx):
        if idx < len(self.__pull):
            hit = self.__pull[idx]
        else:
            hit = None
        return hit

    def isVisible(self):
        return self.__isVisible

    def setVisible(self, flag):
        self.__isVisible = flag
        if self.__ui:
            self.__ui.setVisible(flag)

    def setViewComponents(self, component):
        self.__damageIndicatorExtType = bool(
            self.settingsCore.getSetting(DAMAGE_INDICATOR.TYPE))
        self.__damageIndicatorCrits = bool(
            self.settingsCore.getSetting(DAMAGE_INDICATOR.PRESET_CRITS))
        self.__damageIndicatorAllies = bool(
            self.settingsCore.getSetting(DAMAGE_INDICATOR.PRESET_ALLIES))
        self.__ui = component
        self.__ui.invalidateSettings()
        self.__ui.setVisible(self.__isVisible)
        proxy = weakref.proxy(self.__ui)
        handler = avatar_getter.getInputHandler()
        if handler is not None:
            from AvatarInputHandler import AvatarInputHandler
            if isinstance(handler, AvatarInputHandler):
                handler.onPostmortemKillerVisionEnter += self.__onPostmortemKillerVision
        ctrl = self.sessionProvider.shared.vehicleState
        if ctrl is not None:
            ctrl.onVehicleControlling += self.__onVehicleControlling
        for hit in self.__pull:
            idx = hit.getIndex()
            duration = hit.setIndicator(proxy)
            if duration:
                self.__callbackIDs[idx] = BigWorld.callback(
                    duration, partial(self.__tickToHideHit, idx))

        return

    def clearViewComponents(self):
        for hit in self.__pull:
            hit.clear()

        if self.__ui:
            self.__ui.destroy()
        self.__ui = None
        return

    def addHit(self, hitDirYaw, attackerID, damage, isBlocked, critFlags,
               isHighExplosive, damagedID, attackReasonID):
        atackerVehInfo = self.__arenaDP.getVehicleInfo(attackerID)
        atackerVehType = atackerVehInfo.vehicleType
        isAlly = self.__arenaDP.isAllyTeam(atackerVehInfo.team)
        playerVehType = self.__arenaDP.getVehicleInfo(damagedID).vehicleType
        hitData = HitData(yaw=hitDirYaw,
                          attackerID=attackerID,
                          isAlly=isAlly,
                          damage=damage,
                          attackerVehName=atackerVehType.shortNameWithPrefix,
                          isBlocked=isBlocked,
                          attackerVehClassTag=atackerVehType.classTag,
                          critFlags=critFlags,
                          playerVehMaxHP=playerVehType.maxHealth,
                          isHighExplosive=isHighExplosive,
                          attackReasonID=attackReasonID,
                          friendlyFireMode=self.__isFriendlyFireMode())
        if not self._isValidHit(hitData):
            return
        else:
            hit = self.__findHit(hitData)
            if hit is None:
                extendHitData = False
                hit = self.__getNextHit()
            else:
                extendHitData = hit.isShown()
            idx = hit.getIndex()
            self.__clearHideCallback(idx)
            duration = hit.show(hitData, extend=extendHitData)
            if duration:
                self.__callbackIDs[idx] = BigWorld.callback(
                    duration, partial(self.__tickToHideHit, idx))
            return hit

    def _isValidHit(self, hitData):
        if hitData.isNonPlayerAttackReason(
        ) or hitData.isBattleAbilityConsumable(
        ) or hitData.isBattleConsumables():
            return False
        isCriticalNoDamage = hitData.isCritical() and hitData.getDamage() == 0
        if self.__damageIndicatorExtType and not self.__damageIndicatorCrits and isCriticalNoDamage:
            return False
        return False if self.__damageIndicatorExtType and not self.__damageIndicatorAllies and hitData.isFriendlyFire(
        ) else True

    def _hideAllHits(self):
        for hit in self.__pull:
            hit.hide()

    def __getNextHit(self):
        find = self.__pull[0]
        for hit in self.__pull:
            if not hit.isShown():
                return hit
            if hit.getStartTime() < find.getStartTime():
                find = hit

        return find

    def __isFriendlyFireMode(self):
        friendlyFireBonusTypes = self.lobbyContext.getServerSettings(
        ).getFriendlyFireBonusTypes()
        isFriendlyFireMode = self.sessionProvider.arenaVisitor.bonus.isFriendlyFireMode(
            friendlyFireBonusTypes)
        isCustomAllyDamageEffect = self.sessionProvider.arenaVisitor.bonus.hasCustomAllyDamageEffect(
        )
        return isFriendlyFireMode and isCustomAllyDamageEffect

    def __findHit(self, hitData):
        for hit in self.__pull:
            data = hit.getHitData()
            if data is not None:
                if hitData.getAttackerID() == data.getAttackerID():
                    currentMask = data.getHitFlags() & _AGGREGATED_HIT_BITS
                    newMask = hitData.getHitFlags() & _AGGREGATED_HIT_BITS
                    if currentMask > 0:
                        if currentMask == newMask:
                            return hit
                        if currentMask == HIT_FLAGS.HP_DAMAGE and newMask == HIT_FLAGS.HP_DAMAGE | HIT_FLAGS.IS_CRITICAL:
                            return hit
                        if currentMask == HIT_FLAGS.HP_DAMAGE | HIT_FLAGS.IS_CRITICAL and newMask == HIT_FLAGS.HP_DAMAGE:
                            return hit

        return

    def __tickToHideHit(self, idx):
        self.__callbackIDs.pop(idx, None)
        self.__pull[idx].hide()
        return

    def __clearHideCallback(self, idx):
        callbackID = self.__callbackIDs.pop(idx, None)
        if callbackID is not None:
            BigWorld.cancelCallback(callbackID)
        return

    def __clearHideCallbacks(self):
        for _, callbackID in self.__callbackIDs.items():
            if callbackID is not None:
                BigWorld.cancelCallback(callbackID)

        self.__callbackIDs.clear()
        return

    def __handleGUIVisibility(self, event):
        self.setVisible(event.ctx['visible'])

    def __onSettingsChanged(self, diff):
        if DAMAGE_INDICATOR.TYPE in diff:
            self.__damageIndicatorExtType = bool(diff[DAMAGE_INDICATOR.TYPE])
        if DAMAGE_INDICATOR.PRESET_CRITS in diff:
            self.__damageIndicatorCrits = bool(
                diff[DAMAGE_INDICATOR.PRESET_CRITS])
        if DAMAGE_INDICATOR.PRESET_ALLIES in diff:
            self.__damageIndicatorAllies = bool(
                diff[DAMAGE_INDICATOR.PRESET_ALLIES])
        if self.__ui is not None:
            for key in _VISUAL_DAMAGE_INDICATOR_SETTINGS:
                if key in diff:
                    self.__ui.invalidateSettings()
                    for hit in self.__pull:
                        hit.redraw()

                    break

        return

    def __onPostmortemKillerVision(self, killerVehicleID):
        if killerVehicleID != self.__arenaDP.getPlayerVehicleID():
            self._hideAllHits()

    def __onVehicleControlling(self, vehicle):
        if not vehicle.isPlayerVehicle:
            self._hideAllHits()
Ejemplo n.º 26
0
class CustomizationPropertiesSheet(CustomizationPropertiesSheetMeta):
    itemsCache = dependency.instance(IItemsCache)
    service = dependency.descriptor(ICustomizationService)
    _hangarSpace = dependency.descriptor(IHangarSpace)

    def __init__(self):
        super(CustomizationPropertiesSheet, self).__init__()
        self.__ctx = None
        self._slotID = -1
        self._regionID = -1
        self._areaID = -1
        self._isVisible = False
        self._editMode = False
        self._extraMoney = None
        self._isItemAppliedToAll = False
        self.__interactionType = CUSTOMIZATION_ALIASES.CUSTOMIZATION_POJECTION_INTERACTION_DEFAULT
        self.__changes = [False] * 3
        return

    @property
    def isVisible(self):
        return self._isVisible

    def editMode(self, value, interactionType):
        self._editMode = value
        if self._editMode:
            self.__interactionType = interactionType
        else:
            self.interactionStatusUpdate(False)
            self.__interactionType = -1

    def interactionStatusUpdate(self, value):
        self.fireEvent(
            CameraRelatedEvents(
                CameraRelatedEvents.FORCE_DISABLE_CAMERA_MOVEMENT,
                ctx={'disable': value}), EVENT_BUS_SCOPE.DEFAULT)

    def setScale(self, value):
        pass

    def setRotation(self, value):
        pass

    def _populate(self):
        super(CustomizationPropertiesSheet, self)._populate()
        self.__ctx = self.service.getCtx()
        self._extraMoney = None
        self._isItemAppliedToAll = False
        self.__ctx.onCacheResync += self.__onCacheResync
        self.__ctx.onCustomizationSeasonChanged += self.__onSeasonChanged
        self.__ctx.onCustomizationItemInstalled += self.__onItemsInstalled
        self.__ctx.onCustomizationItemsRemoved += self.__onItemsRemoved
        self.__ctx.onCustomizationCamouflageColorChanged += self.__onCamouflageColorChanged
        self.__ctx.onCustomizationCamouflageScaleChanged += self.__onCamouflageScaleChanged
        self.__ctx.onCustomizationProjectionDecalScaleChanged += self.__onProjectionDecalScaleChanged
        self.__ctx.onCustomizationItemsBought += self.__onItemsBought
        self.__ctx.onCustomizationItemSold += self.__onItemSold
        return

    def _dispose(self):
        self.__ctx.onCustomizationItemSold -= self.__onItemSold
        self.__ctx.onCustomizationItemsBought -= self.__onItemsBought
        self.__ctx.onCustomizationCamouflageScaleChanged -= self.__onCamouflageScaleChanged
        self.__ctx.onCustomizationCamouflageColorChanged -= self.__onCamouflageColorChanged
        self.__ctx.onCustomizationProjectionDecalScaleChanged -= self.__onProjectionDecalScaleChanged
        self.__ctx.onCustomizationItemsRemoved -= self.__onItemsRemoved
        self.__ctx.onCustomizationItemInstalled -= self.__onItemsInstalled
        self.__ctx.onCustomizationSeasonChanged -= self.__onSeasonChanged
        self.__ctx.onCacheResync -= self.__onCacheResync
        self._extraMoney = None
        self._isItemAppliedToAll = False
        self._slotID = -1
        self._regionID = -1
        self._areaID = -1
        self.__ctx = None
        super(CustomizationPropertiesSheet, self)._dispose()
        return

    def show(self, areaID, slotID, regionID):
        if self._slotID == slotID and self._regionID == regionID and self._areaID == areaID and self.isVisible:
            return
        self._slotID = slotID
        self._regionID = regionID
        self._areaID = areaID
        self._isVisible = True
        if self.__update():
            self.__ctx.onPropertySheetShown()
        self.__ctx.vehicleAnchorsUpdater.displayMenu(True)

    def hide(self):
        if not self.isVisible:
            return
        self._isVisible = False
        self.as_hideS()
        self.__ctx.onPropertySheetHidden()
        self.__ctx.vehicleAnchorsUpdater.displayMenu(False)

    def onActionBtnClick(self, actionType, actionData):
        if actionType == CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_APPLY_TO_ALL_PARTS:
            self._isItemAppliedToAll = not self._isItemAppliedToAll
            self.__applyToOtherAreas(self._isItemAppliedToAll)
        elif actionType == CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_APPLY_TO_ALL_SEASONS:
            self._isItemAppliedToAll = not self._isItemAppliedToAll
            self.__applyToOtherSeasons(self._isItemAppliedToAll)
        elif actionType == CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_REMOVE_ONE:
            self.__removeElement()
        elif actionType == CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_RENT_CHECKBOX_CHANGE:
            self.__ctx.changeAutoRent()
            self.__update()
        elif actionType == CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_REMOVE_FROM_ALL_PARTS:
            self.__removeFromAllAreas()
        elif actionType == CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_SCALE_CHANGE:
            if self._slotID == GUI_ITEM_TYPE.CAMOUFLAGE:
                if self._currentComponent.patternSize != actionData:
                    self.__ctx.changeCamouflageScale(self._areaID,
                                                     self._regionID,
                                                     actionData)
            elif self._slotID == GUI_ITEM_TYPE.PROJECTION_DECAL:
                actionData += 1
                if self._currentComponent.scaleFactorId != actionData:
                    self.__ctx.changeProjectionDecalScale(
                        self._areaID, self._regionID, actionData)
        elif actionType == CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_COLOR_CHANGE:
            if self._currentComponent.palette != actionData:
                self.__ctx.changeCamouflageColor(self._areaID, self._regionID,
                                                 actionData)
        elif actionType == CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_CLOSE:
            self.hide()
            self.__ctx.onClearItem()

    def onClose(self):
        self.hide()

    @property
    def _currentSlotData(self):
        if self._slotID == -1 or self._areaID == -1 or self._slotID == GUI_ITEM_TYPE.STYLE:
            return
        else:
            slot = self.__ctx.currentOutfit.getContainer(self._areaID).slotFor(
                self._slotID)
            if slot is None or self._regionID == -1:
                return
            slotId = self.__ctx.getSlotIdByAnchorId(
                C11nId(self._areaID, self._slotID, self._regionID))
            return slot.getSlotData(slotId.regionIdx)

    @property
    def _currentItem(self):
        slotData = self._currentSlotData
        return None if slotData is None else slotData.item

    @property
    def _currentComponent(self):
        slotData = self._currentSlotData
        return None if slotData is None else slotData.component

    @property
    def _currentStyle(self):
        return self.__ctx.modifiedStyle if self._slotID == GUI_ITEM_TYPE.STYLE else None

    def __update(self):
        if self._isVisible and self._slotID != -1 and self._regionID != -1 and self._areaID != -1:
            self.__updateItemAppliedToAllFlag()
            self.__updateExtraPrice()
            self.as_setDataAndShowS(self.__makeVO())
            self.__ctx.caruselItemUnselected()
            self.__ctx.onPropertySheetShown()
            return True
        return False

    def __applyToOtherAreas(self, installItem):
        if self.__ctx.currentTab not in (C11nTabs.PAINT, C11nTabs.CAMOUFLAGE):
            return
        currentSeason = self.__ctx.currentSeason
        if installItem:
            self.__ctx.installItemToAllTankAreas(currentSeason, self._slotID,
                                                 self._currentSlotData)
        else:
            self.__ctx.removeItemFromAllTankAreas(currentSeason, self._slotID)
        self.__update()

    def __removeFromAllAreas(self):
        currentSeason = self.__ctx.currentSeason
        self.__ctx.removeItemFromAllTankAreas(currentSeason, self._slotID)
        self.__update()

    def __applyToOtherSeasons(self, installItem):
        if self.__ctx.currentTab not in (C11nTabs.EFFECT, C11nTabs.EMBLEM,
                                         C11nTabs.INSCRIPTION,
                                         C11nTabs.PROJECTION_DECAL):
            return
        if installItem:
            self.__ctx.installItemForAllSeasons(self._areaID, self._slotID,
                                                self._regionID,
                                                self._currentSlotData)
        else:
            self.__ctx.removeItemForAllSeasons(self._areaID, self._slotID,
                                               self._regionID)
        self.__update()

    def __removeElement(self):
        if self._slotID == GUI_ITEM_TYPE.STYLE:
            self.__ctx.removeStyle(self._currentStyle.intCD)
        else:
            slotId = self.__ctx.getSlotIdByAnchorId(
                C11nId(areaId=self._areaID,
                       slotType=self._slotID,
                       regionIdx=self._regionID))
            if slotId is not None:
                self.__ctx.removeItemFromSlot(self.__ctx.currentSeason, slotId)
        return

    def __updateItemAppliedToAllFlag(self):
        self._isItemAppliedToAll = False
        if self.__ctx.currentTab in (C11nTabs.PAINT, C11nTabs.CAMOUFLAGE):
            self._isItemAppliedToAll = True
            for areaId in Area.TANK_PARTS:
                regionsIndexes = getAppliedRegionsForCurrentHangarVehicle(
                    areaId, self._slotID)
                multiSlot = self.__ctx.currentOutfit.getContainer(
                    areaId).slotFor(self._slotID)
                for regionIdx in regionsIndexes:
                    slotData = multiSlot.getSlotData(regionIdx)
                    df = self._currentSlotData.weakDiff(slotData)
                    if slotData.item is None or df.item is not None:
                        break
                else:
                    continue

                self._isItemAppliedToAll = False
                break

        elif self.__ctx.currentTab in (C11nTabs.EFFECT, C11nTabs.EMBLEM,
                                       C11nTabs.INSCRIPTION):
            self._isItemAppliedToAll = True
            firstSeason = SeasonType.COMMON_SEASONS[0]
            fistSlotData = self.__ctx.getModifiedOutfit(
                firstSeason).getContainer(self._areaID).slotFor(
                    self._slotID).getSlotData(self._regionID)
            if fistSlotData.item is not None:
                for season in SeasonType.COMMON_SEASONS[1:]:
                    slotData = self.__ctx.getModifiedOutfit(
                        season).getContainer(self._areaID).slotFor(
                            self._slotID).getSlotData(self._regionID)
                    df = fistSlotData.weakDiff(slotData)
                    if slotData.item is None or df.item is not None:
                        self._isItemAppliedToAll = False
                        break

            else:
                self._isItemAppliedToAll = False
        return

    def __makeVO(self):
        currentElement = self._currentStyle if self._slotID == GUI_ITEM_TYPE.STYLE else self._currentItem
        vo = {
            'intCD':
            -1 if not currentElement else currentElement.intCD,
            'renderersData':
            self.__makeRenderersVOs() if currentElement else [],
            'isProjectionEnable':
            self._slotID == GUI_ITEM_TYPE.PROJECTION_DECAL,
            'isBigRadius':
            self._slotID
            in (GUI_ITEM_TYPE.INSCRIPTION, GUI_ITEM_TYPE.PROJECTION_DECAL,
                GUI_ITEM_TYPE.EMBLEM)
        }
        return vo

    def __makeSlotVO(self):
        vo = None
        if not self._currentItem:
            vo = {
                'imgIconSrc':
                RES_ICONS.MAPS_ICONS_LIBRARY_TANKITEM_BUY_TANK_POPOVER_SMALL
            }
        return vo

    def __makeRenderersVOs(self):
        renderers = []
        if self._slotID == GUI_ITEM_TYPE.PAINT:
            renderers.append(self.__makeSetOnOtherTankPartsRendererVO())
        elif self._slotID == GUI_ITEM_TYPE.CAMOUFLAGE:
            vo = self.__makeCamoColorRendererVO()
            if vo is not None:
                renderers.append(vo)
            renderers.append(self.__makeScaleRendererVO())
            renderers.append(self.__makeSetOnOtherTankPartsRendererVO())
        elif self._slotID in (GUI_ITEM_TYPE.EMBLEM, GUI_ITEM_TYPE.INSCRIPTION,
                              GUI_ITEM_TYPE.MODIFICATION):
            renderers.append(self.__makeSetOnOtherSeasonsRendererVO())
        elif self._slotID == GUI_ITEM_TYPE.STYLE:
            isExtentionEnabled = self._currentStyle and self._currentStyle.isRentable
            if isExtentionEnabled:
                renderers.append(self.__makeExtensionRendererVO())
        elif self._slotID == GUI_ITEM_TYPE.PROJECTION_DECAL:
            renderers.append(self.__makeScaleRendererVO())
        renderers.append(self.__makeRemoveRendererVO())
        renderers.append(self.__makeCloseeRendererVO())
        return renderers

    def __updateExtraPrice(self):
        if self._isItemAppliedToAll and self._currentItem:
            appliedIems = tuple((it for it in self.__ctx.getPurchaseItems()
                                 if not it.isDismantling
                                 and it.item.intCD == self._currentItem.intCD))
            if self.__ctx.currentTab in (C11nTabs.PAINT, C11nTabs.CAMOUFLAGE):
                appliedIems = tuple((it for it in appliedIems
                                     if it.group == self.__ctx.currentSeason))
            outfit = self.__ctx.originalOutfit
            slotData = outfit.getContainer(self._areaID).slotFor(
                self._slotID).getSlotData(self._regionID)
            isCurrentlyApplied = slotData.item == self._currentItem
            itemCache = self.itemsCache.items.getItemByCD(
                self._currentItem.intCD)
            inventoryCount = itemCache.inventoryCount
            appliedItemPrice = itemCache.getBuyPrice()
            extraInventoryCount = max(
                0,
                len(appliedIems) -
                max(inventoryCount, int(not isCurrentlyApplied)))
            self._extraMoney = appliedItemPrice.price * extraInventoryCount
        else:
            self._extraMoney = None
        return

    def __makeSetOnOtherTankPartsRendererVO(self):
        icon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_TANK
        hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_TANK_HOVER
        actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_APPLYTOWHOLETANK
        if self._isItemAppliedToAll:
            icon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_DEL_TANK
            hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_DEL_TANK_HOVER
            actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_CANCEL
        return {
            'iconSrc':
            icon,
            'iconHoverSrc':
            hoverIcon,
            'actionBtnLabel':
            text_styles.tutorial(actionBtnLabel),
            'actionType':
            CUSTOMIZATION_ALIASES.
            CUSTOMIZATION_SHEET_ACTION_APPLY_TO_ALL_PARTS,
            'rendererLnk':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_BTN_RENDERER_UI
        }

    def __removeAllTankPartsRendererVO(self):
        icon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_DEL_TANK
        hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_DEL_TANK_HOVER
        actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_CLEAR
        return {
            'iconSrc':
            icon,
            'iconHoverSrc':
            hoverIcon,
            'actionBtnLabel':
            text_styles.tutorial(actionBtnLabel),
            'actionType':
            CUSTOMIZATION_ALIASES.
            CUSTOMIZATION_SHEET_ACTION_REMOVE_FROM_ALL_PARTS,
            'rendererLnk':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_BTN_RENDERER_UI
        }

    def __makeRemoveRendererVO(self):
        iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_CROSS
        hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_CROSS_HOVER
        if self._slotID == GUI_ITEM_TYPE.STYLE:
            actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_REMOVESTYLE
            iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_STYLE_X
            hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_STYLE_X_HOVER
        else:
            if self._slotID == GUI_ITEM_TYPE.MODIFICATION:
                actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_REMOVE_TANK
                iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_EFFECTS_X
                hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_EFFECTS_X_HOVER
            elif self._slotID == GUI_ITEM_TYPE.EMBLEM:
                actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_REMOVE_EMBLEM
                iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_EMBLEM_X
                hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_EMBLEM_X_HOVER
            elif self._slotID == GUI_ITEM_TYPE.INSCRIPTION:
                actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_REMOVE_INSCRIPTION
                iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_TYPE_X
                hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_TYPE_X_HOVER
            elif self._slotID == GUI_ITEM_TYPE.PROJECTION_DECAL:
                actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_REMOVE_PROJECTIONDECAL
                iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_EFFECTS_X
                hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_EFFECTS_X_HOVER
            else:
                actionBtnLabel = VEHICLE_CUSTOMIZATION.getSheetBtnRemoveText(
                    getCustomizationTankPartName(self._areaID, self._regionID))
            if self._slotID == GUI_ITEM_TYPE.CAMOUFLAGE:
                iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_CAMO_X
                hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_CAMO_X_HOVER
            elif self._slotID == GUI_ITEM_TYPE.PAINT:
                iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_COLORS_X
                hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_REMOVE_COLORS_X_HOVER
        return {
            'iconSrc':
            iconSrc,
            'iconHoverSrc':
            hoverIcon,
            'actionBtnLabel':
            text_styles.tutorial(actionBtnLabel),
            'rendererLnk':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_BTN_RENDERER_UI,
            'actionType':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_REMOVE_ONE
        }

    def __makeCloseeRendererVO(self):
        iconSrc = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_CROSS
        hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_CROSS_HOVER
        actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_CLOSE
        return {
            'iconSrc': iconSrc,
            'iconHoverSrc': hoverIcon,
            'actionBtnLabel': text_styles.tutorial(actionBtnLabel),
            'rendererLnk':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_BTN_RENDERER_UI,
            'actionType':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_CLOSE
        }

    def __makeExtensionRendererVO(self):
        if self.__ctx.autoRentEnabled():
            icon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_DEL_RENT
            hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_DEL_RENT_HOVER
            label = VEHICLE_CUSTOMIZATION.CUSTOMIZATION_POPOVER_STYLE_NOTAUTOPROLONGATIONLABEL
        else:
            icon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_RENT
            hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_RENT_HOVER
            label = VEHICLE_CUSTOMIZATION.CUSTOMIZATION_POPOVER_STYLE_AUTOPROLONGATIONLABEL
        return {
            'iconSrc':
            icon,
            'iconHoverSrc':
            hoverIcon,
            'actionBtnLabel':
            text_styles.tutorial(label),
            'actionType':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_RENT_CHECKBOX_CHANGE,
            'rendererLnk':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_BTN_RENDERER_UI
        }

    def __makeCamoColorRendererVO(self):
        btnsBlockVO = []
        colornum = _DEFAULT_COLORNUM
        for palette in self._currentItem.palettes:
            colornum = max(
                colornum, sum(
                    ((color >> 24) / 255.0 > 0 for color in palette)))

        for idx, palette in enumerate(
                islice(self._currentItem.palettes, _MAX_PALETTES)):
            texture = _PALETTE_TEXTURE.format(colornum=colornum)
            icon = camoIconTemplate(texture,
                                    _PALETTE_WIDTH,
                                    _PALETTE_HEIGHT,
                                    palette,
                                    background=_PALETTE_BACKGROUND)
            btnsBlockVO.append(
                CustomizationCamoSwatchVO(
                    icon, idx == self._currentComponent.palette)._asdict())

        return {
            'iconSrc':
            RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_COLORS,
            'iconHoverSrc':
            RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_COLORS_HOVER,
            'actionType':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_COLOR_CHANGE,
            'rendererLnk':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_SCALE_COLOR_RENDERER_UI,
            'btnsBlockVO': btnsBlockVO
        } if len(btnsBlockVO) == _MAX_PALETTES else None

    def __makeScaleRendererVO(self):
        btnsBlockVO = []
        if self._slotID == GUI_ITEM_TYPE.CAMOUFLAGE:
            selected = self._currentComponent.patternSize
        else:
            selected = self._currentComponent.scaleFactorId - 1
        for idx, scaleSizeLabel in enumerate(SCALE_SIZE):
            btnsBlockVO.append({
                'paletteIcon': '',
                'label': scaleSizeLabel,
                'selected': selected == idx,
                'value': idx
            })

        return {
            'iconSrc': RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_SCALE,
            'iconHoverSrc':
            RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_SCALE_HOVER,
            'actionType':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_ACTION_SCALE_CHANGE,
            'rendererLnk':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_SCALE_COLOR_RENDERER_UI,
            'btnsBlockVO': btnsBlockVO
        }

    def __makeSetOnOtherSeasonsRendererVO(self):
        icon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_ALL_SEASON
        hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_ALL_SEASON_HOVER
        actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_APPLYTOALLMAPS
        if self._isItemAppliedToAll:
            actionBtnLabel = VEHICLE_CUSTOMIZATION.PROPERTYSHEET_ACTIONBTN_REMOVE_SEASONS
            icon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_DEL_ALL_SEASON
            hoverIcon = RES_ICONS.MAPS_ICONS_CUSTOMIZATION_PROPERTY_SHEET_ICON_DEL_ALL_SEASON_HOVER
        return {
            'iconSrc':
            icon,
            'iconHoverSrc':
            hoverIcon,
            'actionBtnLabel':
            text_styles.tutorial(actionBtnLabel),
            'actionType':
            CUSTOMIZATION_ALIASES.
            CUSTOMIZATION_SHEET_ACTION_APPLY_TO_ALL_SEASONS,
            'rendererLnk':
            CUSTOMIZATION_ALIASES.CUSTOMIZATION_SHEET_BTN_RENDERER_UI
        }

    def __onCacheResync(self, *_):
        if not g_currentVehicle.isPresent():
            self.hide()
            return
        if self.__ctx.mode == C11nMode.CUSTOM:
            self.hide()
        else:
            self.__update()

    def __onSeasonChanged(self, seasonType):
        self.hide()

    def __onCamouflageColorChanged(self, areaId, regionIdx, paletteIdx):
        self.__update()

    def __onCamouflageScaleChanged(self, areaId, regionIdx, scale):
        self.__update()

    def __onProjectionDecalScaleChanged(self, areaId, regionIdx, scale):
        self.__update()

    def __onItemsInstalled(self, item, slotId, buyLimitReached):
        self.__update()

    def __onItemsRemoved(self):
        self.hide()

    def __onItemsBought(self, purchaseItems, results):
        self.__update()

    def __onItemSold(self, item, count):
        self.__update()
Ejemplo n.º 27
0
class ProfileHof(ProfileHofMeta):
    _eventsCache = dependency.descriptor(IEventsCache)
    _clansController = dependency.descriptor(IWebController)
    _errorsStatusMap = {
        '1004': PROFILE_CONSTANTS.HOF_SPECIAL_CASES,
        '1005': PROFILE_CONSTANTS.HOF_SPECIAL_CASES,
        '1015': PROFILE_CONSTANTS.HOF_SPECIAL_CASES,
        '1016': PROFILE_CONSTANTS.HOF_SPECIAL_CASES,
        '1003': PROFILE_CONSTANTS.HOF_RESULTS_HIDE,
        '1006': PROFILE_CONSTANTS.HOF_RESULTS_EXCLUSION,
        '1007': PROFILE_CONSTANTS.HOF_RESULTS_INCLUSION
    }
    _requestRetriesCount = 3
    _retryDelay = 0.5
    _bgPath = '../maps/icons/hof/hof_back_landing.png'
    _buttonsWithCounter = (PROFILE_CONSTANTS.HOF_ACHIEVEMENTS_BUTTON,
                           PROFILE_CONSTANTS.HOF_VEHICLES_BUTTON)

    def __init__(self, *args):
        super(ProfileHof, self).__init__(*args)
        self.__status = PROFILE_CONSTANTS.HOF_RESULTS_SHOW
        self.__retriesCount = 0
        self.__isMaintenance = False
        self.__viewDisposed = False
        self.__requestProcessing = False
        self.__retryCallback = None
        return

    def showAchievementsRating(self):
        setHofButtonOld(PROFILE_CONSTANTS.HOF_ACHIEVEMENTS_BUTTON)
        self.__openHofBrowserView(getHofAchievementsRatingUrl())

    def showVehiclesRating(self):
        setHofButtonOld(PROFILE_CONSTANTS.HOF_VEHICLES_BUTTON)
        self.__openHofBrowserView(getHofVehiclesRatingUrl())

    @process
    def changeStatus(self):
        if self.__status == PROFILE_CONSTANTS.HOF_RESULTS_SHOW:
            success = yield DialogsInterface.showI18nConfirmDialog(
                'hof/excludeRating')
            if success:
                self.__makeRequest(
                    self._clansController.getClanDossier(
                    ).requestHofUserExclude,
                    PROFILE_CONSTANTS.HOF_RESULTS_EXCLUSION,
                    lambda errorCode: self.__getRatingStatus())
        elif self.__status == PROFILE_CONSTANTS.HOF_RESULTS_HIDE:
            self.__makeRequest(
                self._clansController.getClanDossier().requestHofUserRestore,
                PROFILE_CONSTANTS.HOF_RESULTS_INCLUSION,
                lambda errorCode: self.__getRatingStatus())
        else:
            LOG_WARNING('Something went wrong! Getting actual status.')
            self.__getRatingStatus()

    def onSectionActivated(self):
        if self.lobbyContext.getServerSettings().bwHallOfFame.isStatusEnabled:
            if self.__requestProcessing:
                LOG_WARNING(
                    'ProfileHof request canceled: another request is processing'
                )
            else:
                self.__getRatingStatus()
        else:
            self.as_setStatusS(PROFILE_CONSTANTS.HOF_SPECIAL_CASES)

    def _populate(self):
        super(ProfileHof, self)._populate()
        self.lobbyContext.getServerSettings(
        ).onServerSettingsChange += self.__onServerSettingChanged
        self.as_setBackgroundS(self._bgPath)
        self.as_setBtnCountersS(self.__getCountersList())

    def _dispose(self):
        if self.__retryCallback:
            LOG_WARNING(
                'ProfileHof request canceled: ProfileHof view was disposed')
            BigWorld.cancelCallback(self.__retryCallback)
        self.__viewDisposed = True
        self.lobbyContext.getServerSettings(
        ).onServerSettingsChange -= self.__onServerSettingChanged
        super(ProfileHof, self)._dispose()

    def __getCountersList(self):
        counters = []
        for buttonName in self._buttonsWithCounter:
            if isHofButtonNew(buttonName):
                counters.append({'componentId': buttonName, 'count': '1'})

        return counters

    def __getRatingStatus(self):
        def handleError(errorCode):
            status = self._errorsStatusMap.get(errorCode)
            if status:
                self.__status = status
                self.as_setStatusS(status)
            else:
                LOG_ERROR('Unknown error code: ' + str(errorCode))

        self.__makeRequest(
            self._clansController.getClanDossier().requestHofUserInfo,
            PROFILE_CONSTANTS.HOF_RESULTS_SHOW, handleError)

    @process
    def __makeRequest(self, requestFunc, successStatus, errorCallback):
        if self.__retriesCount == 0:
            if not self.__isMaintenance:
                self.as_showWaitingS(WAITING.HOF_LOADING)
            self.__requestProcessing = True
        else:
            self.__retryCallback = None
        response = yield requestFunc()
        if self.__viewDisposed:
            LOG_WARNING(
                'ProfileHof request canceled: ProfileHof view was disposed')
            return
        else:
            if response:
                self.__refreshRequest()
                if self.__isMaintenance:
                    self.as_hideServiceViewS()
                    self.as_setBtnCountersS(self.__getCountersList())
                    self.__isMaintenance = False
                errors = response.getErrors()
                if not errors:
                    self.__status = successStatus
                    self.as_setStatusS(successStatus)
                else:
                    errorCallback(errors[0])
            elif self.__retriesCount < self._requestRetriesCount:
                self.__retriesCount += 1
                self.__retryCallback = BigWorld.callback(
                    self._retryDelay,
                    partial(self.__makeRequest, requestFunc, successStatus,
                            errorCallback))
            else:
                self.__refreshRequest()
                if not self.__isMaintenance:
                    self.__isMaintenance = True
                    header = icons.alert() + i18n.makeString(
                        MENU.BROWSER_DATAUNAVAILABLE_HEADER)
                    description = i18n.makeString(
                        MENU.BROWSER_DATAUNAVAILABLE_DESCRIPTION)
                    self.as_showServiceViewS(header, description)
                    self.as_setBtnCountersS([])
            return

    def __refreshRequest(self):
        self.__retriesCount = 0
        if not self.__isMaintenance:
            self.as_hideWaitingS()
        self.__requestProcessing = False

    def __openHofBrowserView(self, url):
        self._eventsCache.onProfileVisited()
        g_eventBus.handleEvent(
            events.LoadViewEvent(VIEW_ALIAS.BROWSER_VIEW,
                                 ctx={
                                     'url':
                                     url,
                                     'returnAlias':
                                     VIEW_ALIAS.LOBBY_PROFILE,
                                     'allowRightClick':
                                     True,
                                     'webHandlers':
                                     createHofWebHandlers(),
                                     'selectedAlias':
                                     VIEW_ALIAS.PROFILE_HOF,
                                     'disabledKeys':
                                     getHofDisabledKeys(),
                                     'onServerSettingsChange':
                                     onServerSettingsChange
                                 }), EVENT_BUS_SCOPE.LOBBY)

    def __onServerSettingChanged(self, diff):
        if 'hallOfFame' in diff:
            self.onSectionActivated()
Ejemplo n.º 28
0
class BCHangar(Hangar):
    bootcampCtrl = dependency.descriptor(IBootcampController)

    def __init__(self, ctx=None):
        super(BCHangar, self).__init__(ctx)
        self._observer = None
        return

    def showNewElements(self, newElements):
        list = newElements['keys']
        if self._observer is not None:
            self._observer.as_showAnimatedS(list)
        self.ammoPanel.showNewElements(list)
        return

    def updateVisibleComponents(self, visibleSettings):
        if visibleSettings is None:
            visibleSettings = self.bootcampCtrl.getLobbySettings()
        if self._observer is not None:
            self._observer.as_setBootcampDataS(visibleSettings)
        self.ammoPanel.updateVisibleComponents(visibleSettings)
        self.headerComponent.updateVisibleComponents(visibleSettings)
        return

    def onEscape(self):
        dialogsContainer = self.app.containerManager.getContainer(
            ViewTypes.TOP_WINDOW)
        if not self.__isViewOpenOrLoading(
                dialogsContainer,
                VIEW_ALIAS.LOBBY_MENU) and not self.__isViewOpenOrLoading(
                    dialogsContainer, VIEW_ALIAS.BOOTCAMP_OUTRO_VIDEO
                ) and not self.__isViewOpenOrLoading(
                    dialogsContainer, VIEW_ALIAS.BOOTCAMP_QUEUE_DIALOG):
            self.fireEvent(events.LoadViewEvent(VIEW_ALIAS.LOBBY_MENU),
                           scope=EVENT_BUS_SCOPE.LOBBY)

    def showHelpLayout(self):
        pass

    def _onPopulateEnd(self):
        g_bootcampEvents.onRequestChangeResearchButtonState += self.researchPanel.setNavigationEnabled

    def _populate(self):
        super(BCHangar, self)._populate()
        self._observer = self.app.bootcampManager.getObserver(
            'BCHangarObserver')
        if self._observer is not None:
            self._observer.as_setBootcampDataS(
                self.bootcampCtrl.getLobbySettings())
        return

    def _dispose(self):
        g_bootcampEvents.onRequestChangeResearchButtonState -= self.researchPanel.setNavigationEnabled
        g_bootcampEvents.onHangarDispose()
        self._observer = None
        super(BCHangar, self)._dispose()
        return

    def __isViewOpenOrLoading(self, container, viewAlias):
        openView = container.getView(
            criteria={POP_UP_CRITERIA.VIEW_ALIAS: viewAlias})
        if openView is not None:
            return True
        else:
            for loadingView in container.getAllLoadingViews():
                if loadingView.settings.alias == viewAlias:
                    return True

            return False
Ejemplo n.º 29
0
class SelectRespawnView(ViewImpl):
    __sessionProvider = dependency.descriptor(IBattleSessionProvider)

    def __init__(self, *args, **kwargs):
        super(SelectRespawnView, self).__init__(
            R.views.battle.battleRoyale.select_respawn.SelectRespawn(),
            ViewFlags.COMPONENT, SelectRespawnViewModel, *args, **kwargs)
        arenaVisitor = self.__sessionProvider.arenaVisitor
        self.__mapTexture = 'url:../../{}'.format(
            arenaVisitor.type.getMinimapTexture())
        self.__background = self.__getBgByGeometryName(
            arenaVisitor.type.getGeometryName())
        bottomLeft, topRight = arenaVisitor.type.getBoundingBox()
        self.__mapSize, _ = topRight - bottomLeft
        self.__offset = bottomLeft
        self.__closeTime = 0
        self.__points = []
        self.__pointsById = {}
        self.__timer = BRPrebattleTimer(weakref.proxy(self))

    @property
    def viewModel(self):
        return super(SelectRespawnView, self).getViewModel()

    def updateCloseTime(self, timeLeft, state):
        self.__timer.updateCloseTime(timeLeft, state)

    def dispose(self):
        pass

    def setPoints(self, points):
        with self.viewModel.transaction() as vm:
            vmPoints = vm.getPoints()
            vmPoints.clear()
            for point in points:
                pointId = point['guid']
                coordX, coordY = point['position'] - self.__offset
                pointVM = RespawnPointViewModel()
                pointVM.setPointID(pointId)
                pointVM.setCoordX(coordX)
                pointVM.setCoordY(coordY)
                vmPoints.addViewModel(pointVM)

            vmPoints.invalidate()

    def updatePoint(self, vehicleId, pointId, prevPointId):
        arenaDP = self.__sessionProvider.getArenaDP()
        playerName = arenaDP.getVehicleInfo(vehicleId).player.name
        with self.viewModel.transaction() as vm:
            vmPoints = vm.getPoints()
            for vmPoint in vmPoints:
                if vmPoint.getPointID() == pointId:
                    if not vmPoint.getPlayerName1():
                        vmPoint.setPlayerName1(playerName)
                    else:
                        vmPoint.setPlayerName2(playerName)
                if vmPoint.getPointID() == prevPointId:
                    if vmPoint.getPlayerName1() == playerName:
                        vmPoint.setPlayerName1(vmPoint.getPlayerName2() or '')
                        vmPoint.setPlayerName2('')
                    if vmPoint.getPlayerName2() == playerName:
                        vmPoint.setPlayerName2('')

            vmPoints.invalidate()

    def _initialize(self, *args, **kwargs):
        super(SelectRespawnView, self)._initialize()
        self.viewModel.onCompleteBtnClick += self.__onCompleteBtnClick
        self.viewModel.onSelectPoint += self.__onSelectPoint
        with self.viewModel.transaction() as vm:
            vm.setMapSize(abs(self.__mapSize))
            vm.setMinimapBG(self.__mapTexture)
            vm.setHeader(R.strings.battle_royale.selectRespawn.header())
            vm.setDescription(
                R.strings.battle_royale.selectRespawn.description())
            vm.setBtnDescription(
                R.strings.battle_royale.selectRespawn.btnDescription())
            vm.setBackground(self.__background)
            vm.setIsReplay(self.__sessionProvider.isReplayPlaying)

    def _finalize(self):
        super(SelectRespawnView, self)._finalize()
        self.viewModel.onCompleteBtnClick -= self.__onCompleteBtnClick
        self.viewModel.onSelectPoint -= self.__onSelectPoint

    def __getBgByGeometryName(self, geometry):
        if geometry == '250_br_battle_city2-1':
            return R.images.gui.maps.icons.battleRoyale.spawnBg.c_250_br_battle_city2_1(
            )
        else:
            return R.images.gui.maps.icons.battleRoyale.spawnBg.c_251_br_battle_city3(
            ) if geometry == '251_br_battle_city3' else None

    def __onSelectPoint(self):
        spawnCtrl = self.__sessionProvider.dynamic.spawn
        if spawnCtrl:
            _logger.info('Selected point ID = %s',
                         self.viewModel.getSelectedPointID())
            spawnCtrl.chooseSpawnKeyPoint(self.viewModel.getSelectedPointID())

    def __onCompleteBtnClick(self):
        spawnCtrl = self.__sessionProvider.dynamic.spawn
        if spawnCtrl:
            spawnCtrl.placeVehicle()
class ItemsRequester(IItemsRequester):
    itemsFactory = dependency.descriptor(IGuiItemsFactory)

    def __init__(self, inventory, stats, dossiers, goodies, shop, recycleBin, vehicleRotation, ranked, badges, epicMetaGame):
        self.__inventory = inventory
        self.__stats = stats
        self.__dossiers = dossiers
        self.__goodies = goodies
        self.__shop = shop
        self.__vehicleRotation = vehicleRotation
        self.__recycleBin = recycleBin
        self.__ranked = ranked
        self.__badges = badges
        self.__epicMetaGame = epicMetaGame
        self.__itemsCache = defaultdict(dict)
        self.__vehCustomStateCache = defaultdict(dict)

    @property
    def inventory(self):
        return self.__inventory

    @property
    def stats(self):
        return self.__stats

    @property
    def dossiers(self):
        return self.__dossiers

    @property
    def goodies(self):
        return self.__goodies

    @property
    def shop(self):
        return self.__shop

    @property
    def recycleBin(self):
        return self.__recycleBin

    @property
    def vehicleRotation(self):
        return self.__vehicleRotation

    @property
    def ranked(self):
        return self.__ranked

    @property
    def badges(self):
        return self.__badges

    @property
    def epicMetaGame(self):
        return self.__epicMetaGame

    @async
    @process
    def request(self, callback=None):
        from gui.Scaleform.Waiting import Waiting
        Waiting.show('download/inventory')
        yield self.__stats.request()
        yield self.__inventory.request()
        yield self.__vehicleRotation.request()
        Waiting.hide('download/inventory')
        Waiting.show('download/shop')
        yield self.__shop.request()
        Waiting.hide('download/shop')
        Waiting.show('download/dossier')
        yield self.__dossiers.request()
        Waiting.hide('download/dossier')
        Waiting.show('download/discounts')
        yield self.__goodies.request()
        Waiting.hide('download/discounts')
        Waiting.show('download/recycleBin')
        yield self.__recycleBin.request()
        Waiting.hide('download/recycleBin')
        Waiting.show('download/ranked')
        yield self.__ranked.request()
        Waiting.hide('download/ranked')
        Waiting.show('download/badges')
        yield self.__badges.request()
        Waiting.hide('download/badges')
        Waiting.show('download/epicMetaGame')
        yield self.epicMetaGame.request()
        Waiting.hide('download/epicMetaGame')
        callback(self)

    def isSynced(self):
        return self.__stats.isSynced() and self.__inventory.isSynced() and self.__recycleBin.isSynced() and self.__shop.isSynced() and self.__dossiers.isSynced() and self.__goodies.isSynced() and self.__vehicleRotation.isSynced() and self.ranked.isSynced() and self.epicMetaGame.isSynced()

    @async
    @process
    def requestUserDossier(self, databaseID, callback):
        dr = self.__dossiers.getUserDossierRequester(databaseID)
        userAccDossier = yield dr.getAccountDossier()
        clanInfo = yield dr.getClanInfo()
        seasons = yield dr.getRated7x7Seasons()
        ranked = yield dr.getRankedInfo()
        container = self.__itemsCache[GUI_ITEM_TYPE.ACCOUNT_DOSSIER]
        container[databaseID] = (userAccDossier,
         clanInfo,
         seasons,
         ranked)
        callback((userAccDossier, clanInfo, dr.isHidden))

    def unloadUserDossier(self, databaseID):
        container = self.__itemsCache[GUI_ITEM_TYPE.ACCOUNT_DOSSIER]
        if databaseID in container:
            del container[databaseID]
            self.__dossiers.closeUserDossier(databaseID)

    @async
    @process
    def requestUserVehicleDossier(self, databaseID, vehTypeCompDescr, callback):
        dr = self.__dossiers.getUserDossierRequester(databaseID)
        userVehDossier = yield dr.getVehicleDossier(vehTypeCompDescr)
        container = self.__itemsCache[GUI_ITEM_TYPE.VEHICLE_DOSSIER]
        container[databaseID, vehTypeCompDescr] = userVehDossier
        callback(userVehDossier)

    def clear(self):
        while self.__itemsCache:
            _, cache = self.__itemsCache.popitem()
            cache.clear()

        self.__vehCustomStateCache.clear()
        self.__inventory.clear()
        self.__shop.clear()
        self.__stats.clear()
        self.__dossiers.clear()
        self.__goodies.clear()
        self.__vehicleRotation.clear()
        self.__recycleBin.clear()
        self.__ranked.clear()
        self.__badges.clear()
        self.epicMetaGame.clear()

    def invalidateCache(self, diff=None):
        invalidate = defaultdict(set)
        if diff is None:
            LOG_DEBUG('Gui items cache full invalidation')
            for itemTypeID, cache in self.__itemsCache.iteritems():
                if itemTypeID not in (GUI_ITEM_TYPE.ACCOUNT_DOSSIER, GUI_ITEM_TYPE.VEHICLE_DOSSIER, GUI_ITEM_TYPE.BATTLE_ABILITY):
                    cache.clear()

        else:
            for statName, data in diff.get('stats', {}).iteritems():
                if statName in ('unlocks', ('unlocks', '_r')):
                    self._invalidateUnlocks(data, invalidate)
                if statName == 'eliteVehicles':
                    invalidate[GUI_ITEM_TYPE.VEHICLE].update(data)
                if statName in ('vehTypeXP', 'vehTypeLocks'):
                    invalidate[GUI_ITEM_TYPE.VEHICLE].update(data.keys())
                if statName in (('multipliedXPVehs', '_r'),):
                    getter = vehicles.getVehicleTypeCompactDescr
                    inventoryVehiclesCDs = [ getter(v['compDescr']) for v in self.__inventory.getItems(GUI_ITEM_TYPE.VEHICLE).itervalues() ]
                    invalidate[GUI_ITEM_TYPE.VEHICLE].update(inventoryVehiclesCDs)
                if statName in ('oldVehInvIDs',):
                    invalidate[GUI_ITEM_TYPE.VEHICLE].update(data)

        for cacheType, data in diff.get('cache', {}).iteritems():
            if cacheType == 'vehsLock':
                for itemID in data.keys():
                    vehData = self.__inventory.getVehicleData(_getDiffID(itemID))
                    if vehData is not None:
                        invalidate[GUI_ITEM_TYPE.VEHICLE].add(vehData.descriptor.type.compactDescr)

        for cacheType, data in diff.get('groupLocks', {}).iteritems():
            if cacheType in ('isGroupLocked', 'groupBattles'):
                getter = vehicles.getVehicleTypeCompactDescr
                inventoryVehiclesCDs = [ getter(v['compDescr']) for v in self.inventory.getItems(GUI_ITEM_TYPE.VEHICLE).itervalues() ]
                invalidate[GUI_ITEM_TYPE.VEHICLE].update(inventoryVehiclesCDs)

        for itemTypeID, itemsDiff in diff.get('inventory', {}).iteritems():
            if itemTypeID == GUI_ITEM_TYPE.VEHICLE:
                if 'compDescr' in itemsDiff:
                    for strCD in itemsDiff['compDescr'].itervalues():
                        if strCD is not None:
                            invalidate[itemTypeID].add(vehicles.getVehicleTypeCompactDescr(strCD))

                for data in itemsDiff.itervalues():
                    for itemID in data.iterkeys():
                        vehData = self.__inventory.getVehicleData(_getDiffID(itemID))
                        if vehData is not None:
                            invalidate[itemTypeID].add(vehData.descriptor.type.compactDescr)
                            invalidate[GUI_ITEM_TYPE.TANKMAN].update(self.__getTankmenIDsForVehicle(vehData))

            if itemTypeID == GUI_ITEM_TYPE.TANKMAN:
                for data in itemsDiff.itervalues():
                    invalidate[itemTypeID].update(data.keys())
                    for itemID in data.keys():
                        tmanInvID = _getDiffID(itemID)
                        tmanData = self.__inventory.getTankmanData(tmanInvID)
                        if tmanData is not None and tmanData.vehicle != -1:
                            invalidate[GUI_ITEM_TYPE.VEHICLE].update(self.__getVehicleCDForTankman(tmanData))
                            invalidate[GUI_ITEM_TYPE.TANKMAN].update(self.__getTankmenIDsForTankman(tmanData))

            if itemTypeID == GUI_ITEM_TYPE.SHELL:
                invalidate[itemTypeID].update(itemsDiff.keys())
                vehicleItems = self.__inventory.getItems(GUI_ITEM_TYPE.VEHICLE)
                if vehicleItems:
                    for shellIntCD in itemsDiff.iterkeys():
                        for vehicle in vehicleItems.itervalues():
                            shells = vehicle['shells']
                            for intCD, _, _ in LayoutIterator(shells):
                                if shellIntCD == intCD:
                                    vehicleIntCD = vehicles.getVehicleTypeCompactDescr(vehicle['compDescr'])
                                    invalidate[GUI_ITEM_TYPE.VEHICLE].add(vehicleIntCD)
                                    vehicleData = self.__inventory.getItemData(vehicleIntCD)
                                    if vehicleData is not None:
                                        gunIntCD = vehicleData.descriptor.gun.compactDescr
                                        invalidate[GUI_ITEM_TYPE.GUN].add(gunIntCD)

            if itemTypeID == GUI_ITEM_TYPE.CUSTOMIZATION:
                for vehicleIntCD, outfitsData in itemsDiff.get(CustomizationInvData.OUTFITS, {}).iteritems():
                    invalidate[GUI_ITEM_TYPE.VEHICLE].add(vehicleIntCD)
                    seasons = (outfitsData or {}).keys() or SeasonType.RANGE
                    vehicle = self.getItemByCD(vehicleIntCD)
                    for season in seasons:
                        outfitCompactDescr = None
                        if outfitsData:
                            outfitData = outfitsData.get(season)
                            if outfitData:
                                outfitCompactDescr, _ = outfitData
                        newOutfit = Outfit(outfitCompactDescr)
                        if season == SeasonType.ALL:
                            prevOutfit = vehicle.getOutfit(SeasonType.SUMMER) or Outfit()
                            prevStyleId = prevOutfit.id
                            newStyleId = newOutfit.id
                            if prevStyleId != newStyleId:
                                invalidStyles = set()
                                invalidStyles.add(self.__updateStyleAppliedCount(prevStyleId, vehicleIntCD, 0))
                                invalidStyles.add(self.__updateStyleAppliedCount(newStyleId, vehicleIntCD, 1))
                                for styleIntCD in invalidStyles:
                                    if styleIntCD is not None:
                                        invalidate[GUI_ITEM_TYPE.CUSTOMIZATION].add(styleIntCD)

                        else:
                            prevOutfit = vehicle.getCustomOutfit(season) or Outfit()
                            prevItemsCounter = prevOutfit.itemsCounter
                            newItemsCounter = newOutfit.itemsCounter
                            newItemsCounter.subtract(prevItemsCounter)
                            for itemCD, count in newItemsCounter.iteritems():
                                self.__inventory.updateC11nItemAppliedCount(itemCD, vehicleIntCD, count)
                                invalidate[GUI_ITEM_TYPE.CUSTOMIZATION].add(itemCD)

                        invalidate[GUI_ITEM_TYPE.OUTFIT].add((vehicleIntCD, season))

                for cType, items in itemsDiff.get(CustomizationInvData.ITEMS, {}).iteritems():
                    for idx in items.iterkeys():
                        intCD = vehicles.makeIntCompactDescrByID('customizationItem', cType, idx)
                        invalidate[GUI_ITEM_TYPE.CUSTOMIZATION].add(intCD)

            invalidate[itemTypeID].update(itemsDiff.keys())

        for itemType, itemsDiff in diff.get('recycleBin', {}).iteritems():
            deletedItems = itemsDiff.get('buffer', {})
            for itemID in deletedItems.iterkeys():
                if itemType == 'tankmen':
                    invalidate[GUI_ITEM_TYPE.TANKMAN].add(itemID * -1)
                invalidate[GUI_ITEM_TYPE.VEHICLE].add(itemID)

        if 'goodies' in diff:
            vehicleDiscounts = self.__shop.getVehicleDiscountDescriptions()
            for goodieID in diff['goodies'].iterkeys():
                if goodieID in vehicleDiscounts:
                    vehicleDiscount = vehicleDiscounts[goodieID]
                    invalidate[GUI_ITEM_TYPE.VEHICLE].add(vehicleDiscount.target.targetValue)

        for itemTypeID, uniqueIDs in invalidate.iteritems():
            self._invalidateItems(itemTypeID, uniqueIDs)

        return invalidate

    def getVehicle(self, vehInvID):
        vehInvData = self.__inventory.getVehicleData(vehInvID)
        return self.__makeVehicle(vehInvData.descriptor.type.compactDescr, vehInvData) if vehInvData is not None else None

    def getStockVehicle(self, typeCompDescr, useInventory=False):
        if getTypeOfCompactDescr(typeCompDescr) == GUI_ITEM_TYPE.VEHICLE:
            proxy = self if useInventory else None
            return self.itemsFactory.createVehicle(typeCompDescr=typeCompDescr, proxy=proxy)
        else:
            return

    def getVehicleCopy(self, vehicle):
        return self.itemsFactory.createVehicle(typeCompDescr=vehicle.intCD, strCompactDescr=vehicle.descriptor.makeCompactDescr(), inventoryID=vehicle.invID, proxy=self)

    def getTankman(self, tmanInvID):
        tankman = None
        tmanInvData = self.__inventory.getTankmanData(tmanInvID)
        if tmanInvData is not None:
            tankman = self.__makeTankman(tmanInvID, tmanInvData)
        else:
            duration = self.__shop.tankmenRestoreConfig.billableDuration
            tankmanData = self.__recycleBin.getTankman(tmanInvID, duration)
            if tankmanData is not None:
                tankman = self.__makeDismissedTankman(tmanInvID, tankmanData)
        return tankman

    def getItems(self, itemTypeID=None, criteria=REQ_CRITERIA.EMPTY, nationID=None):
        result = ItemsCollection()
        if not isinstance(itemTypeID, tuple):
            itemTypeID = (itemTypeID,)
        for typeID in itemTypeID:
            if typeID == GUI_ITEM_TYPE.VEHICLE and nationID is None and criteria.lookInInventory():
                vehGetter = self.getVehicle
                for vehInvID in (self.inventory.getItems(GUI_ITEM_TYPE.VEHICLE) or {}).iterkeys():
                    item = vehGetter(vehInvID)
                    if criteria(item):
                        result[item.intCD] = item

            itemGetter = self.getItemByCD
            protector = criteria.getIntCDProtector()
            if protector is not None and protector.isUnlinked():
                return result
            for intCD in vehicle_items_getter.getItemsIterator(self.__shop.getItemsData(), nationID=nationID, itemTypeID=typeID):
                if protector is not None and protector.isTriggered(intCD):
                    continue
                item = itemGetter(intCD)
                if criteria(item):
                    result[intCD] = item

        return result

    def getTankmen(self, criteria=REQ_CRITERIA.TANKMAN.ACTIVE):
        result = ItemsCollection()
        activeTankmenInvData = self.__inventory.getItemsData(GUI_ITEM_TYPE.TANKMAN)
        for invID, tankmanInvData in activeTankmenInvData.iteritems():
            item = self.__makeTankman(invID, tankmanInvData)
            if criteria(item):
                result[invID] = item

        duration = self.__shop.tankmenRestoreConfig.billableDuration
        dismissedTankmenData = self.__recycleBin.getTankmen(duration)
        for invID, tankmanData in dismissedTankmenData.iteritems():
            item = self.__makeDismissedTankman(invID, tankmanData)
            if criteria(item):
                result[invID] = item

        return result

    def getVehicles(self, criteria=REQ_CRITERIA.EMPTY):
        return self.getItems(GUI_ITEM_TYPE.VEHICLE, criteria=criteria)

    def getBadges(self, criteria=REQ_CRITERIA.EMPTY):
        result = ItemsCollection()
        for badgeID, badgeData in self.__badges.available.iteritems():
            item = self.itemsFactory.createBadge(badgeData, proxy=self)
            if criteria(item):
                result[badgeID] = item

        return result

    def getItemByCD(self, typeCompDescr):
        return self.__makeVehicle(typeCompDescr) if getTypeOfCompactDescr(typeCompDescr) == GUI_ITEM_TYPE.VEHICLE else self.__makeSimpleItem(typeCompDescr)

    def getItem(self, itemTypeID, nationID, innationID):
        typeCompDescr = vehicles.makeIntCompactDescrByID(GUI_ITEM_TYPE_NAMES[itemTypeID], nationID, innationID)
        return self.__makeVehicle(typeCompDescr) if itemTypeID == GUI_ITEM_TYPE.VEHICLE else self.__makeSimpleItem(typeCompDescr)

    def getTankmanDossier(self, tmanInvID):
        tankman = self.getTankman(tmanInvID)
        tmanDossierDescr = self.__getTankmanDossierDescr(tmanInvID)
        currentVehicleItem = None
        if tankman.isInTank:
            extDossier = self.getVehicleDossier(tankman.vehicleDescr.type.compactDescr)
            currentVehicleItem = self.getItemByCD(tankman.vehicleDescr.type.compactDescr)
        else:
            extDossier = self.getAccountDossier()
        return self.itemsFactory.createTankmanDossier(tankman.descriptor, tmanDossierDescr, extDossier, currentVehicleItem=currentVehicleItem)

    def getVehicleDossier(self, vehTypeCompDescr, databaseID=None):
        if databaseID is None:
            return self.itemsFactory.createVehicleDossier(self.__getVehicleDossierDescr(vehTypeCompDescr), vehTypeCompDescr)
        else:
            container = self.__itemsCache[GUI_ITEM_TYPE.VEHICLE_DOSSIER]
            dossier = container.get((int(databaseID), vehTypeCompDescr))
            if dossier is None:
                LOG_WARNING('Vehicle dossier for this user is empty', vehTypeCompDescr, databaseID)
                return
            playerDossier = self.getAccountDossier(databaseID)
            return self.itemsFactory.createVehicleDossier(dossier, vehTypeCompDescr, playerDBID=databaseID, rankedCurrentSeason=playerDossier.getRankedCurrentSeason())

    def getVehicleDossiersIterator(self):
        for intCD, dossier in self.__dossiers.getVehDossiersIterator():
            yield (intCD, dossiers2.getVehicleDossierDescr(dossier))

    def getAccountDossier(self, databaseID=None):
        if databaseID is None:
            dossierDescr = self.__getAccountDossierDescr()
            return self.itemsFactory.createAccountDossier(dossierDescr)
        container = self.__itemsCache[GUI_ITEM_TYPE.ACCOUNT_DOSSIER]
        dossier, _, _, ranked = container.get(int(databaseID))
        if dossier is None:
            LOG_WARNING('Trying to get empty user dossier', databaseID)
            return
        else:
            return self.itemsFactory.createAccountDossier(dossier, databaseID, rankedCurrentSeason=ranked)

    def getClanInfo(self, databaseID=None):
        if databaseID is None:
            return (self.__stats.clanDBID, self.__stats.clanInfo)
        container = self.__itemsCache[GUI_ITEM_TYPE.ACCOUNT_DOSSIER]
        _, clanInfo, _, _ = container.get(int(databaseID))
        if clanInfo is None:
            LOG_WARNING('Trying to get empty user clan info', databaseID)
            return
        else:
            return clanInfo

    def getPreviousItem(self, itemTypeID, invDataIdx):
        itemData = self.__inventory.getPreviousItem(itemTypeID, invDataIdx)
        return self.__makeItem(itemTypeID, invDataIdx, strCompactDescr=itemData.compDescr, inventoryID=itemData.invID, proxy=self)

    def doesVehicleExist(self, intCD):
        itemTypeID, nationID, innationID = vehicles.parseIntCompactDescr(intCD)
        return innationID in vehicles.g_list.getList(nationID)

    def _invalidateItems(self, itemTypeID, uniqueIDs):
        cache = self.__itemsCache[itemTypeID]
        for uid in uniqueIDs:
            invRes = self.__inventory.invalidateItem(itemTypeID, uid)
            if uid in cache:
                LOG_DEBUG('Item marked as invalid', uid, cache[uid], invRes)
                self.__deleteItemFromCache(cache, uid, itemTypeID)
            LOG_DEBUG('No cached item', uid, invRes)

    def _invalidateUnlocks(self, unlocked, result):
        vehInCache = self.__itemsCache[GUI_ITEM_TYPE.VEHICLE]
        for itemCD in unlocked:
            itemTypeID = getTypeOfCompactDescr(itemCD)
            if itemTypeID == GUI_ITEM_TYPE.VEHICLE:
                result[itemTypeID].add(itemCD)
                if itemCD in vehInCache:
                    self._invalidateUnlocks(vehInCache[itemCD].getAutoUnlockedItems(), result)
            if itemTypeID in GUI_ITEM_TYPE.VEHICLE_MODULES:
                result[itemTypeID].add(itemCD)
            if itemTypeID != GUI_ITEM_TYPE.FUEL_TANK:
                LOG_WARNING('Item is not vehicle or module', itemTypeID)

    def __deleteItemFromCache(self, cache, uid, itemTypeID):
        if itemTypeID == GUI_ITEM_TYPE.VEHICLE:
            item = cache[uid]
            if item.isCustomStateSet():
                self.__vehCustomStateCache[uid] = item.getCustomState()
            elif uid in self.__vehCustomStateCache:
                del self.__vehCustomStateCache[uid]
        del cache[uid]

    def __getAccountDossierDescr(self):
        return dossiers2.getAccountDossierDescr(self.__stats.accountDossier)

    def __getTankmanDossierDescr(self, tmanInvID):
        tmanData = self.__inventory.getTankmanData(tmanInvID)
        return dossiers2.getTankmanDossierDescr(tmanData.descriptor.dossierCompactDescr) if tmanData is not None else dossiers2.getTankmanDossierDescr()

    def __getVehicleDossierDescr(self, vehTypeCompDescr):
        return dossiers2.getVehicleDossierDescr(self.__dossiers.getVehicleDossier(vehTypeCompDescr))

    def __makeItem(self, itemTypeIdx, uid, *args, **kwargs):
        container = self.__itemsCache[itemTypeIdx]
        if uid in container:
            return container[uid]
        else:
            if not self.isSynced():
                self.__logBrokenSync()
            item = self.itemsFactory.createGuiItem(itemTypeIdx, *args, **kwargs)
            if item is not None:
                container[uid] = item
                self.__restoreItemCustomState(itemTypeIdx, uid, item)
            return item

    def __restoreItemCustomState(self, itemTypeIdx, uid, item):
        if itemTypeIdx == GUI_ITEM_TYPE.VEHICLE:
            prevItem = self.__vehCustomStateCache.get(uid, None)
            if prevItem:
                item.setCustomState(prevItem)
                del self.__vehCustomStateCache[uid]
        return

    def __makeVehicle(self, typeCompDescr, vehInvData=None):
        vehInvData = vehInvData or self.__inventory.getItemData(typeCompDescr)
        return self.__makeItem(GUI_ITEM_TYPE.VEHICLE, typeCompDescr, strCompactDescr=vehInvData.compDescr, inventoryID=vehInvData.invID, proxy=self) if vehInvData is not None else self.__makeItem(GUI_ITEM_TYPE.VEHICLE, typeCompDescr, typeCompDescr=typeCompDescr, proxy=self)

    def __makeTankman(self, tmanInvID, tmanInvData=None):
        tmanInvData = tmanInvData or self.__inventory.getTankmanData(tmanInvID)
        if tmanInvData is not None:
            vehicle = None
            if tmanInvData.vehicle > 0:
                vehicle = self.getVehicle(tmanInvData.vehicle)
            return self.__makeItem(GUI_ITEM_TYPE.TANKMAN, tmanInvID, strCompactDescr=tmanInvData.compDescr, inventoryID=tmanInvID, vehicle=vehicle, proxy=self)
        else:
            return

    def __makeDismissedTankman(self, tmanID, tmanData):
        strCD, dismissedAt = tmanData
        return self.__makeItem(GUI_ITEM_TYPE.TANKMAN, tmanID, strCompactDescr=strCD, inventoryID=tmanID, proxy=self, dismissedAt=dismissedAt)

    def __makeSimpleItem(self, typeCompDescr):
        return self.__makeItem(getTypeOfCompactDescr(typeCompDescr), typeCompDescr, intCompactDescr=typeCompDescr, proxy=self)

    def __getTankmenIDsForVehicle(self, vehData):
        vehTmanIDs = set()
        for tmanInvID in vehData.crew:
            if tmanInvID is not None:
                vehTmanIDs.add(tmanInvID)

        return vehTmanIDs

    def __getTankmenIDsForTankman(self, tmanData):
        vehData = self.__inventory.getVehicleData(tmanData.vehicle)
        return self.__getTankmenIDsForVehicle(vehData) if vehData is not None else set()

    def __getVehicleCDForTankman(self, tmanData):
        vehData = self.__inventory.getVehicleData(tmanData.vehicle)
        return {vehData.descriptor.type.compactDescr} if vehData is not None else set()

    def __logBrokenSync(self):
        requesters = (self.__stats,
         self.__inventory,
         self.__recycleBin,
         self.__shop,
         self.__dossiers,
         self.__goodies,
         self.__vehicleRotation,
         self.ranked)
        unsyncedList = [ r.__class__.__name__ for r in [ r for r in requesters if not r.isSynced() ] ]
        LOG_ERROR('Trying to create fitting item when requesters are not fully synced:', unsyncedList, stack=True)

    def __updateStyleAppliedCount(self, styleId, vehicleIntCD, count):
        if styleId == 0:
            return None
        else:
            styleIntCD = vehicles.makeIntCompactDescrByID('customizationItem', CustomizationType.STYLE, styleId)
            self.__inventory.updateC11nItemAppliedCount(styleIntCD, vehicleIntCD, count)
            return styleIntCD