def CreateRedeemingPanelLayout(self):
     instructionText = '<url=localsvc:service=vgsService&method=ShowRedeemUI>%s</url>' % (
         localization.GetByLabel(
             'UI/RedeemWindow/ClickToInitiateRedeeming'), )
     self.redeemingPanel = RedeemPanel(
         parent=self,
         align=uiconst.TOBOTTOM,
         dragEnabled=False,
         instructionText=instructionText,
         redeemButtonBackgroundColor=REDEEM_BUTTON_BACKGROUND_COLOR,
         redeemButtonFillColor=REDEEM_BUTTON_FILL_COLOR)
     self.redeemingPanel.UpdateDisplay()
 def InitUI(self):
     self.selectionScreen.Flush()
     self.redeemPanel = RedeemPanel(parent=self.selectionScreen, collapseCallback=self.ExitRedeemMode, expandCallback=self.EnterRedeemMode, dragEnabled=True, instructionText=localization.GetByLabel('UI/RedeemWindow/DragAndDropToGive'), redeemButtonBorderColor=csColors.REDEEM_BORDER, redeemButtonBackgroundColor=csColors.REDEEM_BORDER_BACKGROUND, redeemButtonFillColor=csColors.REDEEM_BORDER_FILL, textColor=csColors.REDEEM_PANEL_AVAILABLE_TEXT, redeemPanelBackgroundColor=csColors.REDEEM_PANEL_FILL)
     self.topBorder = Container(name='topBorder', parent=self.selectionScreen, align=uiconst.TOTOP_NOPUSH, height=40, state=uiconst.UI_PICKCHILDREN)
     self.centerArea = Container(name='centerAra', parent=self.selectionScreen, align=uiconst.TOALL, state=uiconst.UI_PICKCHILDREN)
     self.logoCont = Container(parent=self, name='logoCont', align=uiconst.TOTOP_NOPUSH, height=100, state=uiconst.UI_NORMAL)
     self.logo = uiprimitives.Sprite(parent=self.logoCont, texturePath='res:/UI/Texture/classes/CharacterSelection/logo.png', align=uiconst.CENTER, pos=(0,
      0,
      LOGO_WIDTH,
      LOGO_HEIGHT))
     self.charactersCont = Container(name='charactersCont', parent=self.centerArea, align=uiconst.CENTER, state=uiconst.UI_PICKCHILDREN, width=1050, height=600)
     self.SetupCharacterSlots()
Esempio n. 3
0
 def CreateFakeRedeemPanel(self):
     instructionText = '<url=localsvc:service=vgsService&method=ShowRedeemUI>%s</url>' % (
         localization.GetByLabel(
             'UI/RedeemWindow/ClickToInitiateRedeeming'), )
     self.fakeRedeemingPanel = RedeemPanel(
         parent=self.backgroundBottomContainer,
         name='fakeRedeemPanel',
         align=uiconst.TOBOTTOM,
         dragEnabled=False,
         redeemButtonBackgroundColor=REDEEM_BUTTON_BACKGROUND_COLOR,
         redeemButtonFillColor=REDEEM_BUTTON_FILL_COLOR,
         buttonClick=None,
         instructionText=instructionText)
     self.fakeRedeemingPanel.UpdateDisplay(animate=False)
     self.fakeRedeemingPanel.HidePanel(animate=False)
     self.vgsUiController.view.storeContainer.redeemingPanel.HidePanel()
     self.vgsUiController.view.storeContainer.redeemingPanel.SetListenToRedeemQueueUpdatedEvents(
         False)
class AurumStoreContainer(Container):
    default_name = 'AurumStoreContainer'
    default_state = uiconst.UI_NORMAL

    def ApplyAttributes(self, attributes):
        Container.ApplyAttributes(self, attributes)
        self.store = sm.GetService('vgsService').GetStore()
        self.tagsByCategoryId = {}
        self.selectedRootCategoryId = None
        self.selectedCategoryId = None
        self.activeTagsByRootCategoryId = {}
        self.page = None
        Fill(bgParent=self, color=BACKGROUND_COLOR)
        self.CreateRedeemingPanelLayout()
        self.CreateBaseLayout()
        self.CreateHeaderLayout()
        self.CreateContentLayout()
        self.SetFilterOptions()
        self.currentAurBalance = 0
        self._OnResize()

    def _OnResize(self, *args):
        top, left, width, height = self.GetAbsolute()
        contentWidth = min(MAX_CONTENT_WIDTH, width)
        self.leftContainer.width = (width - contentWidth) / 2
        self.contentContainer.width = contentWidth
        self.rightContainer.width = width - self.leftContainer.width - contentWidth
        self.redeemingPanel.width = width
        if hasattr(self, 'grid'):
            self.grid.SetParentWidth(self.contentContainer.width)
        self.SetSidebarContentMask()

    def CreateHeaderLayout(self):
        contentContainer = Container(parent=self.headerContainer,
                                     align=uiconst.TOTOP,
                                     height=CAPTION_HEIGHT,
                                     top=CAPTION_OFFSET)
        LogoHomeButton(parent=self.headerContainer,
                       align=uiconst.TOPLEFT,
                       onClick=self.OnClickHomeButton)
        ExitButton(
            parent=self.headerContainer,
            align=uiconst.TOPRIGHT,
            onClick=uicore.cmd.ToggleAurumStore,
            top=4,
            left=10,
            hint=localization.GetByLabel('UI/VirtualGoodsStore/ExitStore'))
        self.aurButton = HeaderBuyAurButton(parent=contentContainer,
                                            align=uiconst.TORIGHT,
                                            onClick=self._BuyAurum,
                                            padding=(4, 0, 4, 0),
                                            left=6)
        cont = Container(name='AurContainer',
                         parent=contentContainer,
                         align=uiconst.TORIGHT,
                         width=200,
                         padRight=8)
        self.aurLabel = AurLabelHeader(parent=cont,
                                       align=uiconst.CENTERRIGHT,
                                       height=32,
                                       amount=100,
                                       padTop=1)

    def _BuyAurum(self):
        sm.GetService('audio').SendUIEvent('store_aur')
        sm.GetService('viewState').GetView(
            ViewState.VirtualGoodsStore)._LogBuyAurum('TopButton')
        uicore.cmd.BuyAurumOnline()

    def SetSidebarContentMask(self):
        for container in (self.leftContainer, self.rightContainer):
            container.Flush()
            GradientSprite(name='OfferSlipGradient',
                           align=uiconst.TOTOP,
                           parent=container,
                           rgbData=((0.0, BACKGROUND_COLOR[:3]), ),
                           alphaData=((0.0, CONTENT_SLIP_UNDER_AREA_OPACITY),
                                      (0.5, 1.0), (1.0, 1.0)),
                           height=self.topContainer.height +
                           self.filterContainer.height + HEADER_PADDING,
                           rotation=math.pi / 2)

    def CreateBaseLayout(self):
        wholeWidthContainer = Container(parent=self,
                                        name='WholeWindowContainer',
                                        align=uiconst.TOALL)
        self.leftContainer = Container(parent=wholeWidthContainer,
                                       name='LeftSideBar',
                                       align=uiconst.TOLEFT)
        self.rightContainer = Container(parent=wholeWidthContainer,
                                        name='RightSideBar',
                                        align=uiconst.TORIGHT)
        self.contentContainer = Container(parent=wholeWidthContainer,
                                          name='Content',
                                          align=uiconst.TOLEFT)
        self.topContainer = ContainerAutoSize(name='Top Container',
                                              parent=self.contentContainer,
                                              align=uiconst.TOTOP)
        Fill(name='SlipUnderLayer',
             bgParent=self.topContainer,
             color=BACKGROUND_COLOR)
        self.headerContainer = Container(parent=self.topContainer,
                                         name='Header',
                                         align=uiconst.TOTOP,
                                         bgColor=HEADER_BG_COLOR,
                                         height=HEADER_HEIGHT,
                                         clipChildren=True)
        self.categoryContainer = Container(parent=self.topContainer,
                                           name='Categories',
                                           align=uiconst.TOTOP,
                                           height=CATEGORIES_HEIGHT,
                                           padTop=HEADER_PADDING,
                                           state=uiconst.UI_PICKCHILDREN)
        self.subCategoryContainer = Container(name='SubCategories',
                                              parent=self.topContainer,
                                              align=uiconst.TOTOP,
                                              padTop=HEADER_PADDING,
                                              bgColor=TAG_COLOR,
                                              state=uiconst.UI_PICKCHILDREN,
                                              clipChildren=True)
        self.subCategoryButtonContainer = FlowContainer(
            name='SubCategoryButtons',
            parent=self.subCategoryContainer,
            centerContent=True,
            align=uiconst.TOTOP,
            contentSpacing=(1, 0),
            state=uiconst.UI_PICKCHILDREN)
        self.filterContainer = Container(name='Filter',
                                         parent=self.contentContainer,
                                         align=uiconst.TOTOP,
                                         padTop=HEADER_PADDING,
                                         state=uiconst.UI_PICKCHILDREN,
                                         height=CATEGORIES_HEIGHT)

    def CreateContentLayout(self):
        self.contentScroll = OfferScrollContainer(parent=self.contentContainer,
                                                  align=uiconst.TOALL)
        self.banner = BannerReel(parent=self.contentScroll,
                                 align=uiconst.TOTOP,
                                 bannerWidth=MAX_CONTENT_WIDTH,
                                 bannerHeight=AD_HEIGHT)
        self.grid = OfferGrid(parent=self.contentScroll,
                              align=uiconst.TOTOP,
                              contentSpacing=(CONTENT_PADDING,
                                              CONTENT_PADDING),
                              padBottom=CONTENT_PADDING,
                              columns=OFFER_COLUMNS,
                              incrementSize=OFFER_COLUMNS)
        for x in xrange(4 * OFFER_COLUMNS):
            offer = VgsOffer(parent=self.grid,
                             width=MAX_OFFER_IMAGE_SIZE,
                             height=MAX_OFFER_IMAGE_SIZE,
                             align=uiconst.NOALIGN)

        self.contentScroll.RegisterContentLoader(self.grid)

    def CreateRedeemingPanelLayout(self):
        instructionText = '<url=localsvc:service=vgsService&method=ShowRedeemUI>%s</url>' % (
            localization.GetByLabel(
                'UI/RedeemWindow/ClickToInitiateRedeeming'), )
        self.redeemingPanel = RedeemPanel(
            parent=self,
            align=uiconst.TOBOTTOM,
            dragEnabled=False,
            instructionText=instructionText,
            redeemButtonBackgroundColor=REDEEM_BUTTON_BACKGROUND_COLOR,
            redeemButtonFillColor=REDEEM_BUTTON_FILL_COLOR)
        self.redeemingPanel.UpdateDisplay()

    def SelectCategory(self, categoryId):
        self.selectedRootCategoryId = categoryId
        for button in self.categoryButtons:
            if button.isActive and button.categoryId != categoryId:
                button.SetActive(False)

    def SelectSubCategory(self, subcategoryId):
        self.selectedCategoryId = subcategoryId
        for button in self.subcategoryButtons:
            if button.isActive and button.categoryId != subcategoryId:
                button.SetActive(False)

    def OnClickCategory(self, categoryId):
        self.LoadCategoryPage(categoryId)

    @RunThreadOnce(THREAD_KEY_LOAD_PAGE)
    def LoadCategoryPage(self, categoryId):
        if self.page == PAGE_CATEGORY and self.selectedRootCategoryId == categoryId and self.selectedCategoryId is None:
            return
        logger.debug('Loading category page: %s', categoryId)
        self.SelectCategory(categoryId)
        categoriesById = self.store.GetCategories()
        category = categoriesById[categoryId]
        subcategories = [
            categoriesById[subCatId] for subCatId in category.subcategories
        ]
        subcategories = localization.util.Sort(subcategories,
                                               key=lambda c: c.name)
        self.SetSubCategories(subcategories)
        self.SelectSubCategory(None)
        self.SetOffersAndTags(categoryId)
        self.page = PAGE_CATEGORY

    def OnClickSubCategory(self, subcategoryId):
        self.LoadSubCategoryPage(subcategoryId)

    @RunThreadOnce(THREAD_KEY_LOAD_PAGE)
    def LoadSubCategoryPage(self, subcategoryId):
        if self.page == PAGE_SUBCATEGORY and self.selectedCategoryId == subcategoryId:
            return
        logger.debug('Loading sub category page: %s', subcategoryId)
        self.selectedCategoryId = subcategoryId
        self.SetOffersAndTags(subcategoryId)
        self.SelectSubCategory(subcategoryId)
        self.page = PAGE_SUBCATEGORY

    def SetOffersAndTags(self, categoryId):
        tags = self.store.GetTagsByCategoryId(categoryId)
        self.SetFilterTags(tags)
        tagIds = self.filterBar.GetSelectedFilterTagIds()
        offers = self.store.GetFilteredOffers(categoryId, tagIds)
        self.HideBanner()
        self.SetOffers(offers)

    @RunThreadOnce(THREAD_KEY_LOAD_PAGE)
    def OnClickHomeButton(self):
        self.LoadLandingPage()

    def LoadLandingPage(self):
        logger.debug('LoadLandingPage')
        if self.page == PAGE_HOME:
            return
        logger.debug('Loading landing page')
        self._SetSubCategories(None)
        self.SelectCategory(None)
        self.SelectSubCategory(None)
        self.SetFilterTags([])
        self.ShowBanner()
        offers = self.store.GetOffers().values()
        self.SetOffers(offers)
        self.page = PAGE_HOME

    @RunThreadOnce('VGS.ShowBanner')
    def ShowBanner(self):
        if self.banner.HasBanners() and not self.banner.display:
            self.banner.top = 0
            self.banner.display = True
            self.SetSubCategories(None)
            uicore.animations.MoveInFromTop(self.banner,
                                            amount=self.banner.height,
                                            sleep=True)

    @RunThreadOnce('VGS.HideBanner')
    def HideBanner(self):
        uicore.animations.MoveOutTop(self.banner,
                                     amount=self.banner.height,
                                     sleep=True)
        self.banner.top = 0
        self.banner.display = False

    @postponeUntilFocus
    def SetAUR(self, amount):
        logger.debug('SetAUR %s', amount)
        uicore.animations.MorphScalar(
            self,
            'currentAurBalance',
            startVal=self.currentAurBalance,
            endVal=amount,
            curveType=uiconst.ANIM_SMOOTH,
            duration=1.5,
            callback=lambda: self.SetCurrentAurBalance(amount))

    def SetCurrentAurBalance(self, amount):
        self._currentAurBalance = amount
        self.aurLabel.SetAmount(self._currentAurBalance)

    def GetCurrentAurBalance(self):
        return self._currentAurBalance

    currentAurBalance = property(GetCurrentAurBalance, SetCurrentAurBalance)

    def SetCategories(self, categories):
        logger.debug('SetCategories %s', categories)
        self.categoryContainer.Flush()
        searchContainer = Container(name='SearchBox',
                                    parent=self.categoryContainer,
                                    width=SEARCH_BOX_WIDTH,
                                    align=uiconst.TORIGHT)
        categoryButtonsContainer = GridContainer(name='ButtonGrid',
                                                 parent=self.categoryContainer,
                                                 align=uiconst.TOALL,
                                                 columns=len(categories),
                                                 lines=1)
        tagById = self.store.GetTags()
        self.categoryButtons = []
        for category in categories:
            button = CategoryButton(parent=categoryButtonsContainer,
                                    categoryId=category.id,
                                    label=category.name,
                                    align=uiconst.TOALL,
                                    onClick=self.OnClickCategory,
                                    padRight=1)
            self.categoryButtons.append(button)
            tags = []
            for tagId in category.tagIds:
                tag = tagById.get(tagId)
                if tag:
                    tags.append(Tag(tag.id, tag.name))

            self.tagsByCategoryId[category.id] = tags

        iconContainer = Container(name='SearchIconContainer',
                                  parent=searchContainer,
                                  width=CATEGORIES_HEIGHT,
                                  align=uiconst.TOLEFT,
                                  bgColor=CATEGORY_COLOR)
        Sprite(parent=iconContainer,
               texturePath='res:/UI/Texture/Vgs/Search_icon.png',
               width=32,
               height=32,
               align=uiconst.CENTER)
        self.searchEdit = SinglelineEdit(parent=searchContainer,
                                         align=uiconst.TORIGHT,
                                         pos=(0, 0, SEARCH_BOX_WIDTH -
                                              CATEGORIES_HEIGHT - 2, 0),
                                         fontsize=16,
                                         padding=(1, 0, 0, 0),
                                         OnChange=self.Search,
                                         bgColor=TAG_COLOR)
        self.searchEdit.ShowClearButton(
            icon='res:/UI/Texture/Icons/73_16_45.png')
        self.searchEdit.SetHistoryVisibility(False)
        self.searchEdit.sr.background.Hide()

    @RunThreadOnce(THREAD_KEY_LOAD_PAGE)
    def Search(self, searchString):
        self.page = PAGE_SEARCH
        self.HideBanner()
        self.SelectSubCategory(None)
        self.SelectCategory(None)
        self._SetSubCategories(None)
        self.SetFilterTags([])
        sm.GetService('viewState').GetView(
            ViewState.VirtualGoodsStore).Search(searchString)

    @RunThreadOnce('VGS.SetSubCategories')
    def SetSubCategories(self, subcategories):
        self._SetSubCategories(subcategories)

    def _SetSubCategories(self, subcategories):
        self.subCategoryButtonContainer.Flush()
        self.subcategoryButtons = []
        if subcategories is None:
            if self.subCategoryContainer.height > 0:
                uicore.animations.MorphScalar(
                    self.subCategoryContainer,
                    attrName='height',
                    startVal=self.subCategoryContainer.height,
                    endVal=0,
                    duration=0.5,
                    callback=self.SetSidebarContentMask)
        else:
            if int(self.subCategoryContainer.height) != CATEGORIES_HEIGHT:
                uicore.animations.MorphScalar(
                    self.subCategoryContainer,
                    attrName='height',
                    startVal=self.subCategoryContainer.height,
                    endVal=CATEGORIES_HEIGHT,
                    duration=0.5,
                    sleep=False,
                    callback=self.SetSidebarContentMask)
            for subcategory in subcategories:
                button = SubCategoryButton(
                    parent=self.subCategoryButtonContainer,
                    label=subcategory.name,
                    align=uiconst.NOALIGN,
                    height=CATEGORIES_HEIGHT,
                    categoryId=subcategory.id,
                    onClick=self.OnClickSubCategory)
                self.subcategoryButtons.append(button)

    def SetOffers(self, offers):
        if self.selectedCategoryId is None and self.selectedRootCategoryId is None:
            specialOffers = [o for o in offers if o.label is not None]
            notSpecialOffers = [o for o in offers if o.label is None]
            offers = SortOffers(specialOffers)
            offers.extend(SortOffers(notSpecialOffers))
        else:
            offers = SortOffers(offers)
        self.grid.SetOffers(offers)

    def SetFilterOptions(self):
        self.filterContainer.Flush()
        Fill(name='SlipUnderLayer',
             bgParent=self.filterContainer,
             color=BACKGROUND_COLOR,
             opacity=CONTENT_SLIP_UNDER_AREA_OPACITY,
             padTop=-HEADER_PADDING * 2)
        options = [(localization.GetByLabel(
            'UI/VirtualGoodsStore/Sorting/ByPriceAscending'),
                    SORT_PRICE_ASCENDING),
                   (localization.GetByLabel(
                       'UI/VirtualGoodsStore/Sorting/ByPriceDescending'),
                    SORT_PRICE_DESCENDING),
                   (localization.GetByLabel(
                       'UI/VirtualGoodsStore/Sorting/ByNameAscending'),
                    SORT_NAME_ASCENDING),
                   (localization.GetByLabel(
                       'UI/VirtualGoodsStore/Sorting/ByNameDescending'),
                    SORT_NAME_DESCENDING)]
        self.filterCombo = VgsFilterCombo(parent=self.filterContainer,
                                          align=uiconst.TORIGHT,
                                          options=options,
                                          callback=self.OnSortOrderChanged,
                                          select=GetSortOrder(),
                                          padding=(4, 2, 0, 4))
        self.filterBar = VgsOfferFilterBar(
            parent=self.filterContainer, onFilterChanged=self.OnFilterChanged)

    def SetFilterTags(self, tags):
        activeTags = self.activeTagsByRootCategoryId.get(
            self.GetSelectedRootCategoryId(), {})
        self.subCategoryContainer.state = uiconst.UI_PICKCHILDREN
        self.filterBar.SetTags(tags, activeTags)

    def OnSortOrderChanged(self, combo, key, value):
        settings.user.ui.Set('VgsOfferSortOrder', value)
        sm.GetService('viewState').GetView(
            ViewState.VirtualGoodsStore)._LogFilterChange(value)
        self.SetOffers(self.grid.GetOffers())

    def OnFilterChanged(self):
        tagIds = self.filterBar.GetSelectedFilterTagIds()
        rootCategoryId = self.GetSelectedRootCategoryId()
        self.activeTagsByRootCategoryId[rootCategoryId] = tagIds
        offers = self.store.GetFilteredOffers(
            self.selectedCategoryId or rootCategoryId, tagIds)
        self.SetOffers(offers)

    def GetSelectedCategoryId(self):
        return self.selectedCategoryId

    def GetSelectedRootCategoryId(self):
        return self.selectedRootCategoryId

    def OnMouseWheel(self, dz):
        self.contentScroll.OnMouseWheel(dz)
Esempio n. 5
0
class CharacterSelection(uicls.LayerCore):
    __notifyevents__ = [
        'OnSetDevice', 'OnJumpQueueMessage', 'OnCharacterHandler',
        'OnUIRefresh', 'OnUIScalingChange', 'OnTokensRedeemed',
        'OnGraphicSettingsChanged', 'OnUIoffsetChanged'
    ]
    minSidePadding = 50

    def OnSetDevice(self):
        if not self.isopen:
            return
        self.OnRefreshScreen()

    def OnUIRefresh(self):
        self.OnRefreshScreen()

    def OnUIScalingChange(self, *args):
        self.OnRefreshScreen()

    def OnGraphicSettingsChanged(self, changes):
        if gfxsettings.UI_CAMERA_OFFSET in changes:
            self.ChangeUIoffset()

    def OnUIoffsetChanged(self):
        self.ChangeUIoffset()

    def ChangeUIoffset(self):
        cameraOffset = settings.user.ui.offsetUIwithCamera
        uiOffsetWithCamera = settings.user.ui.cameraOffset
        if self.uiOffset != (cameraOffset, uiOffsetWithCamera):
            self.OnRefreshScreen()

    def OnCloseView(self):
        self.isTabStop = False
        screen = self.selectionScreen
        self.selectionScreen = None
        self.ClearBackground()
        if screen is not None and not screen.destroyed:
            screen.Close()
        sm.GetService('dynamicMusic').UpdateDynamicMusic()

    def OnJumpQueueMessage(self, msgtext, ready):
        if ready:
            log.LogInfo('Jump Queue: ready, slamming through...')
            self.__Confirm(sm.GetService('jumpQueue').GetPreparedQueueCharID())
        else:
            log.LogInfo('Jump Queue: message=', msgtext)
            sm.GetService('gameui').Say(msgtext)

    def OnCharacterHandler(self, *_):
        self.SetData()
        self.OnRefreshScreen()

    def GetChars(self):
        return sm.GetService('cc').GetCharactersToSelect()

    def ReduceCharacterGraphics(self):
        gfxsettings.Set(gfxsettings.GFX_CHAR_FAST_CHARACTER_CREATION,
                        True,
                        pending=False)
        gfxsettings.Set(gfxsettings.GFX_CHAR_CLOTH_SIMULATION,
                        0,
                        pending=False)
        gfxsettings.Set(gfxsettings.GFX_CHAR_TEXTURE_QUALITY, 2, pending=False)

    def OnOpenView(self):
        self.isTabStop = True
        self.remoteCharacterSvc = sm.RemoteSvc('charUnboundMgr')
        self.mapSvc = sm.GetService('map')
        self.SetData()
        self.OnRefreshScreen()
        self.AnimateScreenIn()
        sm.GetService('dynamicMusic').UpdateDynamicMusic()
        sm.GetService('audio').SendUIEvent('character_selection_start')
        uthread.new(evetypes.GetTypeIDByNameDict)
        loggly.GetPermission()
        loggly.Initialize()
        charId = blue.os.GetStartupArgValue('character')
        if charId:
            self.ready = True
            self.ConfirmWithCharID(int(charId))

    def SetData(self, force=False):
        characterSelectionData = self.GetCharacterSelectionData(force=force)
        self.chars = characterSelectionData.GetChars()
        self.subscriptionEndTimes = characterSelectionData.GetSubscriptionEndTime(
        )
        self.numSlotsOwnedByUser = characterSelectionData.GetNumCharacterSlots(
        )
        self.slotsToDisplay = characterSelectionData.GetMaxServerCharacters()
        self.currentAdInfo = None
        self.adImageFetched = False
        self.showAd = True
        self.countDownCont = None

    def OnRefreshScreen(self):
        if self._IsSelectionScreenDisabled():
            return
        uicore.registry.SetFocus(self)
        self.ready = False
        self.countDownThread = None
        self.characterSlotList = []
        self.uiOffset = (0, 0)
        self.maxFullSlotSize = None
        self.Flush()
        self.ClearBackground()
        self.selectionScreen = Container(name='selectionScreen',
                                         parent=self,
                                         state=uiconst.UI_PICKCHILDREN)
        self.InitUI()
        self.AddBackground()
        self.AddFeatureContainer()
        self.LoadCharacterSlots()
        self.SetRedeemPanelMode()
        self.AdjustFeatureBarPosition()
        self.CollapseOrExpandSlots(animate=False, loadingSlots=False)
        self.AdjustLogo()
        self.SetTimer()
        self.loadingWheel = uicls.LoadingWheel(parent=self.selectionScreen,
                                               align=uiconst.CENTER,
                                               state=uiconst.UI_NORMAL,
                                               idx=0)
        self.loadingWheel.display = False

    def _IsSelectionScreenDisabled(self):
        return self._IsSelectionScreenAvailable(
        ) and self.selectionScreen.state == uiconst.UI_DISABLED

    def _IsSelectionScreenAvailable(self):
        return hasattr(
            self, 'selectionScreen'
        ) and self.selectionScreen and not self.selectionScreen.destroyed

    def AnimateScreenIn(self):
        uicore.animations.MorphScalar(self.bg,
                                      'opacity',
                                      startVal=0.0,
                                      endVal=1.0,
                                      duration=1.0)
        uicore.animations.MorphScalar(self.logo,
                                      'opacity',
                                      startVal=0.0,
                                      endVal=1.0,
                                      duration=0.5,
                                      timeOffset=0.5)
        uicore.animations.MorphScalar(self.featureContainer,
                                      'opacity',
                                      startVal=0.0,
                                      endVal=1.0,
                                      duration=0.5,
                                      timeOffset=1.5)
        if self.countDownCont:
            uicore.animations.MorphScalar(self.countDownCont,
                                          'opacity',
                                          startVal=0.0,
                                          endVal=1.0,
                                          duration=0.3,
                                          timeOffset=2.0)
        slotDelay = 0.5
        uthread.new(self.PlaySound_thread,
                    event='character_selection_animstart',
                    sleepTime=slotDelay)
        for idx, eachSlot in self.slotsByIdx.iteritems():
            baseAnimationOffset = slotDelay + idx * 0.1
            eachSlot.AnimateSlotIn(animationOffset=baseAnimationOffset,
                                   soundFunction=self.PlaySound_thread,
                                   charContHeight=self.charactersCont.height)

    def PlaySound_thread(self, event, sleepTime):
        blue.pyos.synchro.Sleep(1000 * sleepTime)
        sm.GetService('audio').SendUIEvent(event)

    def AnimateScreenOut(self, excludeSlotForCharID):
        self.selectionScreen.state = uiconst.UI_DISABLED
        slotDelay = 0.5
        slots = self.slotsByIdx.values()
        slots = sorted(slots, key=lambda x: x.slotIdx, reverse=True)
        counter = 0
        uthread.new(self.PlaySound_thread,
                    event='character_selection_animstart',
                    sleepTime=slotDelay)
        for eachSlot in slots:
            if eachSlot.charID == excludeSlotForCharID:
                continue
            baseAnimationOffset = slotDelay + counter * 0.1
            eachSlot.AnimateSlotOut(animationOffset=baseAnimationOffset,
                                    soundFunction=self.PlaySound_thread,
                                    charContHeight=self.charactersCont.height)
            counter += 1

        uicore.animations.MorphScalar(self.logo,
                                      'opacity',
                                      startVal=1.0,
                                      endVal=0.0,
                                      duration=0.5,
                                      timeOffset=2.0)
        uicore.animations.MorphScalar(self.featureContainer,
                                      'opacity',
                                      startVal=1.0,
                                      endVal=0.0,
                                      duration=0.3,
                                      timeOffset=0)
        if self.redeemPanel.HasRedeemItems():
            uicore.animations.MorphScalar(self.redeemPanel,
                                          'opacity',
                                          startVal=1.0,
                                          endVal=0.0,
                                          duration=0.3,
                                          timeOffset=0)
        if self.countDownCont:
            uicore.animations.MorphScalar(self.countDownCont,
                                          'opacity',
                                          startVal=1.0,
                                          endVal=0.0,
                                          duration=0.3,
                                          timeOffset=3.0)

    def EnableScreen(self):
        self.selectionScreen.state = uiconst.UI_PICKCHILDREN
        self.AnimateScreenIn()

    def GetCharacterSelectionData(self, force=False):
        return sm.GetService('cc').GetCharacterSelectionData(force=force)

    def InitUI(self):
        self.seasonSidebar = None
        self.selectionScreen.Flush()
        self.redeemPanel = RedeemPanel(
            parent=self.selectionScreen,
            collapseCallback=self.ExitRedeemMode,
            expandCallback=self.EnterRedeemMode,
            dragEnabled=True,
            instructionText=localization.GetByLabel(
                'UI/RedeemWindow/DragAndDropToGive'),
            redeemButtonBorderColor=csColors.REDEEM_BORDER,
            redeemButtonBackgroundColor=csColors.REDEEM_BORDER_BACKGROUND,
            redeemButtonFillColor=csColors.REDEEM_BORDER_FILL,
            textColor=csColors.REDEEM_PANEL_AVAILABLE_TEXT,
            redeemPanelBackgroundColor=csColors.REDEEM_PANEL_FILL)
        self.topBorder = Container(name='topBorder',
                                   parent=self.selectionScreen,
                                   align=uiconst.TOTOP_NOPUSH,
                                   height=40,
                                   state=uiconst.UI_PICKCHILDREN)
        self._ConstructSeasonInfo()
        self.centerArea = Container(name='centerAra',
                                    parent=self.selectionScreen,
                                    align=uiconst.TOALL,
                                    state=uiconst.UI_PICKCHILDREN)
        self.logoCont = Container(parent=self,
                                  name='logoCont',
                                  align=uiconst.TOTOP_NOPUSH,
                                  height=100,
                                  state=uiconst.UI_NORMAL)
        self.logo = uiprimitives.Sprite(
            parent=self.logoCont,
            texturePath='res:/UI/Texture/classes/CharacterSelection/logo.png',
            align=uiconst.CENTER,
            pos=(0, 0, LOGO_WIDTH, LOGO_HEIGHT))
        self.charactersCont = Container(name='charactersCont',
                                        parent=self.centerArea,
                                        align=uiconst.CENTER,
                                        state=uiconst.UI_PICKCHILDREN,
                                        width=1050,
                                        height=600)
        self.SetupCharacterSlots()
        uthread.new(self._LoadSeasonInfo)

    def AddBackground(self):
        clientHeight = uicore.desktop.height
        percentOfClientHeight = float(clientHeight) / BG_HEIGHT
        newHeight = clientHeight
        newWidth = int(percentOfClientHeight * BG_WIDTH)
        self.bg = uiprimitives.Sprite(
            parent=uicore.desktop,
            name='charselBackground',
            texturePath=
            'res:/UI/Texture/classes/CharacterSelection/background.png',
            align=uiconst.CENTER,
            pos=(0, 0, newWidth, newHeight),
            state=uiconst.UI_DISABLED)
        self.bgOverlay = uiprimitives.Fill(bgParent=uicore.desktop,
                                           color=(0, 0, 0, 1.0))

    def ClearBackground(self):
        if getattr(self, 'bg', None):
            self.bg.Close()
            self.bgOverlay.Close()
        if getattr(self, 'logoCont', None):
            self.logoCont.Close()

    def OnTokensRedeemed(self, redeemedItems, charID):
        self.redeemPanel.RedeemItems(redeemedItems)
        if not self.redeemPanel.HasRedeemItems():
            self.redeemPanel.HidePanel()

    def ExitRedeemMode(self, animate=True):
        self.redeemPanel.CollapsePanel(animate=animate,
                                       duration=csUtil.COLLAPSE_TIME)

    def EnterRedeemMode(self, animate=True):
        self.redeemPanel.ExpandPanel(animate=animate,
                                     duration=csUtil.COLLAPSE_TIME)

    def CollapseOrExpandSlots(self, animate=True, loadingSlots=False):
        shouldShipBeVisible = self.ShouldShipBeVisible()
        self.ChangeSlotCollapsedState(animate=animate,
                                      loadingSlots=loadingSlots)
        for eachSlot in self.slotsByIdx.itervalues():
            if shouldShipBeVisible:
                eachSlot.ExpandSlot(animate=animate)
            else:
                eachSlot.CollapseSlot(animate=animate)

    def ShouldShipBeVisible(self):
        if self.maxFullSlotSize:
            maxFullSlotSize = self.maxFullSlotSize
        else:
            l, ct, cw, ch = self.charactersCont.GetAbsolute()
            maxFullSlotSize = ch
        redeemPanelHeight = self.redeemPanel.GetHeight()
        emptySpace = uicore.desktop.height - maxFullSlotSize
        if emptySpace < 2 * (
                MINIMUM_LOGOHEIGHT + LOGO_PADDING
        ) or emptySpace < FEATURE_BAR_HEIGHT + redeemPanelHeight:
            shipVisible = False
        else:
            shipVisible = True
        return shipVisible

    def ChangeSlotCollapsedState(self, animate, loadingSlots=False):
        shouldShipBeVisible = self.ShouldShipBeVisible()
        maxCurrentCharacterSlotHeight = self.GetMaxCharacterSlotHeight(
            shipVisible=shouldShipBeVisible)
        charactersContTop = 0
        diff = self.charactersCont.height - maxCurrentCharacterSlotHeight
        if animate or loadingSlots and not self.redeemPanel.IsCollapsed():
            charactersContTop = min(0, int(-diff / 2.0))
        freeSpace = uicore.desktop.height - maxCurrentCharacterSlotHeight

        def FindExtraShift(componentHeight):
            shift = 0
            if freeSpace / 2.0 < componentHeight:
                shift = componentHeight - int(freeSpace / 2.0)
            return shift

        bgOffset = 0
        extraShift = 0
        if self.redeemPanel.HasRedeemItems(
        ) and not self.redeemPanel.IsCollapsed():
            bgOffset = -self.redeemPanel.GetPanelHeight()
            extraShift = FindExtraShift(self.redeemPanel.height)
        if extraShift:
            charactersContTop = min(charactersContTop, -extraShift)
        uicore.animations.MorphScalar(self.logo,
                                      'opacity',
                                      startVal=self.logo.opacity,
                                      endVal=1.0,
                                      duration=csUtil.COLLAPSE_TIME)
        if extraShift:
            cl, ct, cw, ch = self.charactersCont.GetAbsolute()
            if ct - extraShift < self.logoCont.height - LOGO_PADDING / 2:
                uicore.animations.MorphScalar(self.logo,
                                              'opacity',
                                              startVal=self.logo.opacity,
                                              endVal=0.05,
                                              duration=csUtil.COLLAPSE_TIME)
        if animate:
            uicore.animations.MorphScalar(self.bg,
                                          'top',
                                          startVal=self.bg.top,
                                          endVal=bgOffset,
                                          duration=csUtil.COLLAPSE_TIME)
            uicore.animations.MorphScalar(self.charactersCont,
                                          'height',
                                          startVal=self.charactersCont.height,
                                          endVal=maxCurrentCharacterSlotHeight,
                                          duration=csUtil.COLLAPSE_TIME)
            uicore.animations.MorphScalar(self.charactersCont,
                                          'top',
                                          startVal=self.charactersCont.top,
                                          endVal=charactersContTop,
                                          duration=csUtil.COLLAPSE_TIME)
        else:
            self.bg.top = bgOffset
            uicore.animations.StopAnimation(self.charactersCont, 'height')
            self.charactersCont.height = maxCurrentCharacterSlotHeight
            self.charactersCont.top = charactersContTop

    def AdjustFeatureBarPosition(self):
        shouldShipBeVisible = self.ShouldShipBeVisible()
        maxCurrentCharacterSlotHeight = self.GetMaxCharacterSlotHeight(
            shouldShipBeVisible)
        redeemPanelButtonHeight = self.redeemPanel.GetButtonHeight()
        availableHeight = int(
            (uicore.desktop.height - maxCurrentCharacterSlotHeight) /
            2.0) - redeemPanelButtonHeight
        self.featureContainer.top = int(
            availableHeight /
            2.0) + redeemPanelButtonHeight - FEATURE_BAR_HEIGHT / 2

    def GetMaxCharacterSlotHeight(self, shipVisible=True):
        if self.characterSlotList:
            return max((slot.GetSlotHeight(shipVisible=shipVisible)
                        for slot in self.characterSlotList))
        else:
            return max([
                slot.GetSlotHeight(shipVisible=shipVisible)
                for slot in self.slotsByIdx.itervalues()
            ])

    def SetupCharacterSlots(self):
        self.characterSlotList = []
        self.slotsByCharID = {}
        self.slotsByIdx = {}
        self.slotsToDisplay = min(self.numSlotsOwnedByUser + 1,
                                  self.slotsToDisplay)
        paddingFromImage = SmallCharacterSlot.GetExtraWidth()
        spaceForEachSlot = (uicore.desktop.width -
                            2 * self.minSidePadding) / self.slotsToDisplay
        maxSize = SmallCharacterSlot.maxImageSize + paddingFromImage
        spaceForEachSlot = min(maxSize, spaceForEachSlot)
        occupiedSlots = len(self.chars[:self.slotsToDisplay])
        for idx in xrange(occupiedSlots):
            slot = SmallCharacterSlot(name='characterSlot_%s' % idx,
                                      parent=self.charactersCont,
                                      callback=self.EnterGameWithCharacter,
                                      deleteCallback=self.Terminate,
                                      undoDeleteCallback=self.UndoTermination,
                                      terminateCallback=self.Terminate,
                                      slotIdx=idx,
                                      width=spaceForEachSlot)
            slot.OnMouseEnter = (self.OnSlotOnMouseEnter, slot)
            slot.OnMouseExit = (self.OnSlotMouseExit, slot)
            self.characterSlotList.append(slot)
            self.slotsByIdx[idx] = slot

        for idx in xrange(occupiedSlots, self.slotsToDisplay):
            if idx > self.numSlotsOwnedByUser - 1:
                callback = self.GoBuySlot
                ownSlot = False
            else:
                callback = self.CreateCharacter
                ownSlot = True
            slot = SmallEmptySlot(name='emptySlot_%s' % idx,
                                  parent=self.charactersCont,
                                  callback=callback,
                                  slotIdx=idx,
                                  width=spaceForEachSlot,
                                  ownSlot=ownSlot)
            self.slotsByIdx[idx] = slot
            slot.OnMouseEnter = (self.OnSlotOnMouseEnter, slot)
            slot.OnMouseExit = (self.OnSlotMouseExit, slot)

        self.charactersCont.width = spaceForEachSlot * self.slotsToDisplay
        self.SetUIOffset()

    def SetUIOffset(self):
        cameraOffset = settings.user.ui.offsetUIwithCamera
        uiOffsetWithCamera = settings.user.ui.cameraOffset
        push = sm.GetService('window').GetCameraLeftOffset(
            self.charactersCont.width, align=uiconst.CENTER, left=0)
        self.uiOffset = (cameraOffset, uiOffsetWithCamera)
        self.charactersCont.left = push
        self.logo.left = push

    def LoadCharacterSlots(self):
        allSlots = self.characterSlotList[:]
        for characterInfo in self.chars[:self.slotsToDisplay]:
            charID = characterInfo.characterID
            characterSlot = allSlots.pop(0)
            self.LoadSlotForCharacter(charID, characterSlot)
            characterSlot.SetMouseExitState()

        if self.characterSlotList:
            maxShipIconHeight = max((slot.GetShipAndLocationContHeight()
                                     for slot in self.characterSlotList))
        else:
            shipPadding = CharLocation.paddingShipAlignmentTop + CharLocation.paddingShipAlignmentBottom
            maxShipIconHeight = CharLocation.minShipSize + CharLocation.locationContHeight + shipPadding
        for slot in self.slotsByIdx.itervalues():
            slot.SetShipContHeight(maxShipIconHeight)

        maxSlotHeight = self.GetMaxCharacterSlotHeight()
        self.maxFullSlotSize = maxSlotHeight
        self.charactersCont.height = maxSlotHeight
        self.ready = True

    def LoadSlotForCharacter(self, charID, characterSlot):
        self.slotsByCharID[charID] = characterSlot
        characterDetails = self.GetCharacterSelectionData().GetCharInfo(charID)
        characterSlot.LoadSlot(charID, characterDetails)

    def SetRedeemPanelMode(self):
        self.redeemPanel.UpdateDisplay(animate=True, timeOffset=0)
        if not self.redeemPanel.HasRedeemItems():
            self.ExitRedeemMode(animate=False)
            return
        if self.redeemPanel.IsCollapsed():
            self.ExitRedeemMode(animate=False)
            self.redeemPanel.CollapsePanel(animate=False)
        else:
            self.EnterRedeemMode(animate=False)
            self.redeemPanel.ExpandPanel(animate=False)

    def AddFeatureContainer(self):
        distanceFromBottom = self.redeemPanel.GetButtonHeight()
        self.featureContainer = Container(parent=self.selectionScreen,
                                          name='featureContainer',
                                          align=uiconst.TOBOTTOM_NOPUSH,
                                          height=FEATURE_BAR_HEIGHT,
                                          top=distanceFromBottom)
        innerFeatureContainer = Container(parent=self.featureContainer,
                                          name='innerFeatureCont',
                                          align=uiconst.CENTER,
                                          width=834,
                                          height=FEATURE_BAR_HEIGHT)
        self.openStoreContainer = Container(name='openStoreContainer',
                                            parent=innerFeatureContainer,
                                            state=uiconst.UI_PICKCHILDREN,
                                            align=uiconst.CENTER,
                                            width=270,
                                            height=90)
        OpenStoreButton(parent=self.openStoreContainer,
                        align=uiconst.CENTER,
                        onClick=uicore.cmd.ToggleAurumStore)
        self.adSpriteContainer = Container(name='adSpriteContainer ',
                                           parent=innerFeatureContainer,
                                           align=uiconst.CENTERRIGHT,
                                           width=BANNER_WIDTH,
                                           height=BANNER_HEIGHT)
        self.adSprint = uiprimitives.Sprite(name='adSprite',
                                            parent=self.adSpriteContainer,
                                            state=uiconst.UI_NORMAL,
                                            width=BANNER_WIDTH,
                                            height=BANNER_HEIGHT)
        DeleteButton(parent=self.adSpriteContainer,
                     name='closeAdButton',
                     align=uiconst.TOPRIGHT,
                     pos=(2, 2, 16, 16),
                     texturePath='res:/UI/Texture/Icons/Plus_Small.png',
                     state=uiconst.UI_NORMAL,
                     color=(0.5, 0.5, 0.5, 1.0),
                     callback=self.CloseAd,
                     hint=localization.GetByLabel('UI/Common/Buttons/Close'),
                     rotation=math.pi / 4.0,
                     idx=0)
        self.DisplayAd()

    def AdjustLogo(self):
        cl, ct, cw, ch = self.charactersCont.GetAbsolute()
        if ct > 0:
            availableHeightAbove = ct
        else:
            availableHeightAbove = int(
                (uicore.desktop.height - self.maxFullSlotSize) / 2.0)
        logoContHeight = max(availableHeightAbove,
                             MINIMUM_LOGOHEIGHT + LOGO_PADDING)
        self.logoCont.height = logoContHeight
        self.logo.display = True
        availableHeightForLogo = logoContHeight - LOGO_PADDING
        percentage = max(0.55,
                         min(1.0, availableHeightForLogo / float(LOGO_HEIGHT)))
        newHeight = int(percentage * LOGO_HEIGHT)
        newWidth = int(percentage * LOGO_WIDTH)
        self.logo.height = newHeight
        self.logo.width = newWidth

    def SetTimer(self):
        if itertoolsext.any(self.subscriptionEndTimes.values()):
            self.countDownCont = CountDownCont(
                parent=self.topBorder,
                align=uiconst.TOTOP,
                height=self.topBorder.height,
                timers=self.subscriptionEndTimes)

    def OnSlotOnMouseEnter(self, slot, *args):
        if not slot.mouseOverState:
            sm.GetService('audio').SendUIEvent('character_hover_picture')
        for eachSlot in self.slotsByIdx.itervalues():
            if eachSlot.charID:
                characterData = self.GetCharacterSelectionData().GetCharInfo(
                    eachSlot.charID)
                deletePrepTime = characterData.GetDeletePrepareTime()
                if deletePrepTime:
                    continue
            if eachSlot == slot:
                eachSlot.SetMouseOverState(animate=True)
            else:
                eachSlot.SetMouseExitState(animate=True)

    def OnSlotMouseExit(self, slot, *args):
        if uiutil.IsUnder(uicore.uilib.mouseOver, slot):
            return
        slot.SetMouseExitState(animate=True)

    def GoBuySlot(self, slotSelected):
        uicore.cmd.OpenAccountManagement()

    def CreateCharacter(self, slotSelected):
        self.CreateNewCharacter()

    def EnterGameWithCharacter(self, slotSelected):
        characterData = self.GetCharacterSelectionData().GetCharInfo(
            slotSelected.charID)
        deletePrepTime = characterData.GetDeletePrepareTime()
        if deletePrepTime is not None:
            return
        if self.seasonSidebar:
            self.seasonSidebar.Close()
        slotSelected.SetMouseOverState()
        slotSelected.PlaySelectedAnimation()
        self.ConfirmWithCharID(slotSelected.charID)
        if sm.GetService('jumpQueue').GetPreparedQueueCharID():
            boundCharacterService = sm.RemoteSvc('charMgr')
            gatekeeper.character.Initialize(
                lambda args: boundCharacterService.GetCohortsForCharacter)
            experimentSvc = sm.StartService('experimentClientSvc')
            experimentSvc.Initialize(languageID=session.languageID)

    def CreateNewCharacter(self):
        if not self.ready:
            eve.Message('Busy')
            return
        lowEnd = gfxsettings.GetDeviceClassification(
        ) == gfxsettings.DEVICE_LOW_END
        msg = uiconst.ID_YES
        if not sm.StartService('device').SupportsSM3():
            msg = eve.Message('AskMissingSM3', {},
                              uiconst.YESNO,
                              default=uiconst.ID_NO)
        if msg != uiconst.ID_YES:
            return
        msg = uiconst.ID_YES
        if not lowEnd and ccUtil.SupportsHigherShaderModel():
            msg = eve.Message('AskUseLowShader', {},
                              uiconst.YESNO,
                              default=uiconst.ID_NO)
        if msg != uiconst.ID_YES:
            return
        if lowEnd:
            msg2 = eve.Message('ReduceGraphicsSettings', {},
                               uiconst.YESNO,
                               default=uiconst.ID_NO)
            if msg2 == uiconst.ID_YES:
                self.ReduceCharacterGraphics()
        eve.Message('CCNewChar')
        uthread.new(sm.GetService('gameui').GoCharacterCreation,
                    askUseLowShader=0)

    def CreateNewAvatar(self, charID):
        charData = self.GetCharacterSelectionData().GetCharInfo(charID)
        charDetails = charData.charDetails
        if charData.GetPaperDollState == const.paperdollStateForceRecustomize:
            eve.Message('ForcedPaperDollRecustomization')
        uthread.new(sm.GetService('gameui').GoCharacterCreation,
                    charID,
                    charDetails.gender,
                    charDetails.bloodlineID,
                    dollState=charData.GetPaperDollState())

    def Confirm(self):
        if not self.characterSlotList:
            return
        slot = self.characterSlotList[0]
        self.EnterGameWithCharacter(slot)

    def ConfirmWithCharID(self, charID, *_):
        log.LogInfo('Character selection: Character selection confirmation')
        if not self.ready:
            log.LogInfo(
                'Character selection: Denied character selection confirmation, not ready'
            )
            eve.Message('Busy')
            return
        isInSync = self.WaitForClockSynchroAndGetSynchroState()
        if not isInSync:
            eve.Message('ClockSynchroInProgress')
            return
        if sm.GetService('jumpQueue').GetPreparedQueueCharID() != charID:
            self.__Confirm(charID)

    def WaitForClockSynchroAndGetSynchroState(self):
        for x in xrange(300):
            if not sm.GetService('connection').IsClockSynchronizing():
                return True
            if x > 30:
                log.general.Log(
                    'Clock synchronization still in progress after %d seconds'
                    % x, log.LGINFO)
            blue.pyos.synchro.SleepWallclock(1000)

        return not sm.GetService('connection').IsClockSynchronizing()

    def EnterAsCharacter(self, charID, loadDungeon, secondChoiceID):
        MAX_RETRIES = 10
        RETRY_SECONDS = 6
        for numTries in xrange(MAX_RETRIES):
            try:
                sm.GetService('sessionMgr').PerformSessionChange(
                    'charsel', self.remoteCharacterSvc.SelectCharacterID,
                    charID, loadDungeon, secondChoiceID)
                return
            except UserError as e:
                if e.msg == 'SystemCheck_SelectFailed_Loading' and numTries < MAX_RETRIES - 1:
                    log.LogNotice(
                        'System is currently loading. Retrying %s/%s' %
                        (numTries, MAX_RETRIES))
                    blue.pyos.synchro.SleepWallclock(RETRY_SECONDS * 1000)
                else:
                    self.EnableScreen()
                    raise

        self.EnableScreen()

    def __Confirm(self, charID, secondChoiceID=None):
        charData = self.GetCharacterSelectionData().GetCharInfo(charID)
        dollState = charData.GetPaperDollState()
        sm.GetService('cc').StoreCurrentDollState(dollState)
        if dollState in (const.paperdollStateForceRecustomize,
                         const.paperdollStateNoExistingCustomization):
            self.CreateNewAvatar(charID)
            return
        self.ready = False
        self.TryEnterGame(charID, secondChoiceID)
        if charID:
            petitionMessage = charData.GetPetitionMessage()
            if petitionMessage:
                uthread.new(sm.GetService('petition').CheckNewMessages)
            mailCount = charData.GetUnreaddMailCount()
            notificationCount = charData.GetUnreadNotificationCount()
            if mailCount + notificationCount > 0:
                uthread.new(
                    sm.GetService('mailSvc').CheckNewMessages_thread,
                    mailCount, notificationCount)

    def TryEnterGame(self, charID, secondChoiceID):
        loadingHeader = localization.GetByLabel(
            'UI/CharacterSelection/CharacterSelection')
        loadingText = localization.GetByLabel(
            'UI/CharacterSelection/EnterGameAs', char=charID)
        sm.GetService('audio').SendUIEvent('msg_OnLogin_play')
        sm.GetService('audio').SendUIEvent('msg_OnConnecting_play')
        self.ShowLoading()
        try:
            eve.Message('OnCharSel')
            sm.GetService('jumpQueue').PrepareQueueForCharID(charID)
            try:
                loadDungeon = sm.GetService(
                    'experimentClientSvc').ShouldStartInDungeon()
                self.selectionScreen.state = uiconst.UI_DISABLED
                self.AnimateScreenOut(excludeSlotForCharID=charID)
                self.EnterAsCharacter(charID, loadDungeon, secondChoiceID)
            except UserError as e:
                self.EnableScreen()
                if e.msg == 'SystemCheck_SelectFailed_Full':
                    solarSystemID = e.args[1]['system'][1]
                    self.SelectAlternativeSolarSystem(charID, solarSystemID,
                                                      secondChoiceID)
                    return
                if e.msg != 'SystemCheck_SelectFailed_Queued':
                    sm.GetService('jumpQueue').PrepareQueueForCharID(None)
                    raise
            except:
                self.EnableScreen()
                sm.GetService('jumpQueue').PrepareQueueForCharID(None)
                raise

        except:
            self.EnableScreen()
            self.HideLoading()
            sm.GetService('loading').FadeOut()
            self.ready = True
            raise

    def SelectAlternativeSolarSystem(self,
                                     charID,
                                     solarSystemID,
                                     secondChoiceID=None):
        neighbors = self.mapSvc.GetNeighbors(solarSystemID)
        if secondChoiceID is None:
            selectText = localization.GetByLabel(
                'UI/CharacterSelection/SelectAlternativeSystem')
        else:
            selectText = localization.GetByLabel(
                'UI/CharacterSelection/SelectAnotherAlternativeSystem')
            secondChoiceNeighbors = self.mapSvc.GetNeighbors(secondChoiceID)
            neighbors.extend(secondChoiceNeighbors)
        systemSecClass = self.mapSvc.GetSecurityClass(solarSystemID)
        validNeighbors = []
        for ssid in neighbors:
            if ssid == secondChoiceID or ssid == solarSystemID:
                continue
            if self.mapSvc.GetSecurityClass(ssid) != systemSecClass:
                continue
            systemItem = self.mapSvc.GetItem(ssid)
            regionID = self.mapSvc.GetRegionForSolarSystem(ssid)
            regionItem = self.mapSvc.GetItem(regionID)
            factionID = systemItem.factionID
            factionName = ''
            if factionID:
                factionName = cfg.eveowners.Get(factionID).ownerName
            label = '%s<t>%s<t>%s<t>%s' % (
                systemItem.itemName, regionItem.itemName,
                self.mapSvc.GetSecurityStatus(ssid), factionName)
            validNeighborTuple = (label, ssid, None)
            validNeighbors.append(validNeighborTuple)

        loadingSvc = sm.StartService('loading')
        self.HideLoading()
        loadingSvc.FadeOut()
        scrollHeaders = [
            localization.GetByLabel('UI/Common/LocationTypes/SolarSystem'),
            localization.GetByLabel('UI/Common/LocationTypes/Region'),
            localization.GetByLabel('UI/Common/Security'),
            localization.GetByLabel('UI/Sovereignty/Sovereignty')
        ]
        ret = uix.ListWnd(
            validNeighbors,
            None,
            localization.GetByLabel('UI/CharacterSelection/SystemCongested'),
            selectText,
            1,
            scrollHeaders=scrollHeaders,
            minw=555)
        if ret:
            self.__Confirm(charID, ret[1])
        else:
            sm.StartService('jumpQueue').PrepareQueueForCharID(None)
            self.ready = True

    def Terminate(self, charID, *args):
        if not self.ready:
            eve.Message('Busy')
            return
        try:
            self.ready = 0
            characterData = self.GetCharacterSelectionData().GetCharInfo(
                charID)
            deletePrepTime = characterData.GetDeletePrepareTime()
            if deletePrepTime:
                now = blue.os.GetWallclockTime()
                if deletePrepTime < now:
                    self.DeleteCharacter(charID,
                                         characterData.charDetails.gender)
                else:
                    timeLeft = deletePrepTime - now
                    infoMsg = localization.GetByLabel(
                        'UI/CharacterSelection/AlreadyInBiomassQueue',
                        charID=charID,
                        timeLef=timeLeft)
                    eve.Message('CustomInfo', {'info': infoMsg})
            else:
                self.SubmitToBiomassQueue(charID)
        finally:
            self.ready = 1

    def DeleteCharacter(self, charID, gender):
        eve.Message('CCTerminate')
        if eve.Message('AskDeleteCharacter', {'charID': charID},
                       uiconst.YESNO) != uiconst.ID_YES:
            return
        self.ShowLoading()
        if gender == const.genderFemale:
            beginMsg = 'CCTerminateForGoodFemaleBegin'
            endMsg = 'CCTerminateForGoodFemale'
        else:
            beginMsg = 'CCTerminateForGoodMaleBegin'
            endMsg = 'CCTerminateForGoodMale'
        eve.Message(beginMsg)
        try:
            error = self.remoteCharacterSvc.DeleteCharacter(charID)
            eve.Message(endMsg)
        finally:
            self.HideLoading()
            self.ready = 1

        if error:
            eve.Message(error)
            return
        self.SetData(force=True)
        self.OnRefreshScreen()

    def SubmitToBiomassQueue(self, charID):
        if eve.Message('AskSubmitToBiomassQueue', {'charID': charID},
                       uiconst.YESNO) != uiconst.ID_YES:
            return
        ret = self.remoteCharacterSvc.PrepareCharacterForDelete(charID)
        if ret:
            eve.Message('SubmitToBiomassQueueConfirm', {
                'charID': charID,
                'when': ret - blue.os.GetWallclockTime()
            })
        self.UpdateSlot(charID)

    def UndoTermination(self, charID, *args):
        sm.RemoteSvc('charUnboundMgr').CancelCharacterDeletePrepare(charID)
        self.UpdateSlot(charID)

    def UpdateSlot(self, charID):
        self.GetCharacterSelectionData(force=True)
        slot = self.slotsByCharID.get(charID, None)
        if slot:
            characterDetails = self.GetCharacterSelectionData().GetCharInfo(
                charID)
            slot.RefreshCharacterDetails(characterDetails)
            slot.SetDeleteUI()
        else:
            self.OnRefreshScreen()

    def DisplayAd(self):
        if self.currentAdInfo == -1:
            self.showAd = False
        if not self.showAd:
            self.adSpriteContainer.state = uiconst.UI_HIDDEN
            return
        if self.currentAdInfo is None:
            uthread.new(self.FetchAdInfo_thread)
        elif not self.adImageFetched:
            uthread.new(self.LoadAd, inThread=True)
        else:
            self.LoadAd()

    def FetchAdInfo_thread(self):
        adInfo = self.GetAdToDisplay()
        self.currentAdInfo = adInfo
        self.LoadAd(inThread=True)

    def LoadAd(self, inThread=False):
        if self.currentAdInfo == -1:
            self.showAd = False
            self.adSpriteContainer.state = uiconst.UI_HIDDEN
            return
        with ExceptionEater('Failed to load ad'):
            self.OpenAd(self.currentAdInfo, inThread=inThread)

    def GetAdToDisplay(self):
        try:
            targetedAds, nonTargetedAds = self.FindAvailableAds()
        except Exception as e:
            log.LogError('Failed to fetch ads, e = ', e)
            return -1

        ads = targetedAds + nonTargetedAds
        for ad in ads:
            didShowAd = settings.public.ui.Get(
                'CSS_AdAlreadyDisplayed_%s' % ad.adID, False)
            if not didShowAd:
                return ad

        return -1

    def FindAvailableAds(self):
        adUrl = csUtil.GetCharacterSelectionAdPageUrl(session.languageID)
        feed = corebrowserutil.GetStringFromURL(adUrl).read()
        root = ET.fromstring(feed)
        namespaces = csUtil.xmlNamespaces
        itemlist = root.findall('atom:entry', namespaces=namespaces)
        targetedAds = []
        nonTargetedAds = []
        if session.userType == const.userTypeTrial:
            target = csUtil.adTrialTerm
        else:
            charData = self.GetCharacterSelectionData()
            creationDate = charData.GetUserCreationDate()
            now = blue.os.GetWallclockTime()
            if now - 6 * const.MONTH30 < creationDate:
                target = csUtil.adMediumTerm
            else:
                target = csUtil.adAdvancedTerm
        for eachItem in itemlist:
            with ExceptionEater('Failed to parse ad'):
                imageEntry = eachItem.find('ccpmedia:group/ccpmedia:content',
                                           namespaces=namespaces)
                linkEntry = eachItem.find(
                    'ccpmedia:group/ccpmedia:description',
                    namespaces=namespaces)
                adID = eachItem.find('atom:id', namespaces=namespaces).text
                link = linkEntry.text
                imageUrl = imageEntry.attrib['url']
                imageWidth = imageEntry.attrib['width']
                imageHeight = imageEntry.attrib['height']
                adInfo = uiutil.Bunch(link=link,
                                      imageUrl=imageUrl,
                                      width=int(imageWidth),
                                      height=int(imageHeight),
                                      adID=adID)
                if eachItem.find("atom:category[@term='%s']" % target,
                                 namespaces=namespaces) is not None:
                    targetedAds.append(adInfo)
                elif eachItem.find('atom:category',
                                   namespaces=namespaces) is None:
                    nonTargetedAds.append(adInfo)

        return (targetedAds, nonTargetedAds)

    def OpenAd(self, adInfo, inThread=False):
        tex, w, h = sm.GetService('photo').GetTextureFromURL(adInfo.imageUrl)
        adImageFetched = True
        if tex.resPath == NONE_PATH:
            log.LogError(
                'Did not get a valid image for the character selection screen ad'
            )
            return
        self.adSprint.texture = tex
        self.adSprint.url = adInfo.link
        self.adSprint.OnClick = (self.ClickAd, adInfo.link)
        self.openStoreContainer.align = uiconst.CENTERLEFT
        settings.public.ui.Set('CSS_AdAlreadyDisplayed_%s' % adInfo.adID, True)

    def CloseAd(self):
        uicore.animations.FadeOut(self.adSpriteContainer,
                                  duration=0.5,
                                  sleep=True)
        self.adSpriteContainer.display = False
        self.showAd = False

    def ClickAd(self, url):
        if url.startswith(('https://', 'http://')):
            uthread.new(self.ClickURL, url)
        else:
            log.LogError('Not valid ad path, no ad displayed. Path = ', url)

    def ClickURL(self, url, *args):
        blue.os.ShellExecute(url)

    def ShowLoading(self, forceOn=0):
        try:
            self.loadingWheel.forcedOn = forceOn
            self.loadingWheel.Show()
        except:
            log.LogError('Failed to show the loading wheel')

    def HideLoading(self, forceOff=0):
        try:
            if not self.loadingWheel.forcedOn or forceOff:
                self.loadingWheel.Hide()
                self.loadingWheel.forcedOn = 0
        except:
            log.LogError('Failed to hide the loading wheel')

    def _ConstructSeasonInfo(self):
        try:
            if sm.GetService('seasonService').is_season_active():
                self.seasonSidebar = SeasonCharacterSelectionSidebar(
                    parent=self.selectionScreen,
                    redeemable_items_panel_height=self.topBorder.height)
        except Exception:
            log.LogTraceback(
                'Failed to construct Scope Network sidebar in character selection'
            )

    def _LoadSeasonInfo(self):
        try:
            if self.seasonSidebar and not self.seasonSidebar.destroyed:
                self.seasonSidebar.load_data()
        except Exception:
            log.LogTraceback(
                'Failed to load data for Scope Network sidebar in character selection'
            )
Esempio n. 6
0
class VgsDetailContainer(Container):
    default_name = 'VgsDetailContainer'
    default_alignMode = None
    default_state = uiconst.UI_PICKCHILDREN
    frameColor = Color.GRAY9

    def ApplyAttributes(self, attributes):
        Container.ApplyAttributes(self, attributes)
        self.vgsUiController = attributes.vgsUiController
        self.offer = attributes.offer
        self.align = uiconst.TOALL
        fullWidth, fullHeight = self.GetAbsoluteSize()
        self.backgroundBottomContainer = uicontrols.ContainerAutoSize(
            parent=self,
            name='backgroundBottomContainer',
            align=uiconst.TOBOTTOM_NOPUSH,
            state=uiconst.UI_PICKCHILDREN,
            width=fullWidth)
        self.backgroundTopContainer = Container(parent=self,
                                                name='backgroundTopContainer',
                                                align=uiconst.TOBOTTOM,
                                                state=uiconst.UI_PICKCHILDREN,
                                                height=fullHeight,
                                                width=fullWidth)
        self.offerContainer = Container(parent=self.backgroundTopContainer,
                                        name='offerContainer',
                                        state=uiconst.UI_NORMAL,
                                        align=uiconst.CENTER,
                                        width=CONTAINER_WIDTH,
                                        height=TOP_PANEL_HEIGHT +
                                        BOTTOM_PANEL_HEIGHT,
                                        bgColor=BACKGROUND_COLOR)
        Fill(bgParent=self.offerContainer,
             color=FRAME_COLOR,
             padding=[-FRAME_WIDTH] * 4,
             fillCenter=True)
        ExitButton(parent=self.offerContainer,
                   align=uiconst.TOPRIGHT,
                   onClick=self.CloseOffer,
                   top=EXIT_BUTTON_PADDING,
                   left=EXIT_BUTTON_PADDING)
        self.preview = VgsOfferPreview(parent=self.offerContainer,
                                       align=uiconst.TOTOP,
                                       height=TOP_PANEL_HEIGHT,
                                       offer=self.offer)
        self.CreateBottomLayout(self.offer, attributes.aurumBalance)
        self.CreateFakeRedeemPanel()

    def CreateBottomLayout(self, offer, aurumBalance):
        self.bottomContainer = Container(name='bottomContainer',
                                         parent=self.offerContainer,
                                         align=uiconst.TOTOP,
                                         clipChildren=True,
                                         height=BOTTOM_PANEL_HEIGHT)
        Fill(align=uiconst.TOALL,
             bgParent=self.bottomContainer,
             color=HEADER_BG_COLOR)
        GradientSprite(align=uiconst.TOALL,
                       bgParent=self.bottomContainer,
                       rgbData=((0.0, (0.0, 0.0, 0.0)), (1.0, (0.0, 0.0,
                                                               0.0))),
                       alphaData=((0.0, 0.8), (0.2, 0.6), (0.6, 0.0)),
                       rotation=math.pi * 0.4)
        self.purchaseDetailsPanel = PurchaseDetailsPanel(
            parent=self.bottomContainer,
            offer=offer,
            aurumBalance=aurumBalance,
            buyOfferCallback=self.vgsUiController.BuyOffer,
            previewCallback=self.OnPreviewType,
            state=uiconst.UI_PICKCHILDREN,
            width=CONTAINER_WIDTH)
        self.activeBottomPanel = self.purchaseDetailsPanel
        self.purchaseProgressPanel = PurchaseProgressPanel(
            parent=self.bottomContainer, width=CONTAINER_WIDTH)
        self.purchaseSuccessPanel = PurchaseResultPanel(
            parent=self.bottomContainer,
            closeOfferCallback=self.CloseOffer,
            iconForegroundTexturePath=
            'res:/UI/Texture/vgs/purchase_success_fg.png',
            iconBackgroundTexturePath=
            'res:/UI/Texture/vgs/purchase_success_bg.png',
            textTitle=localization.GetByLabel(
                'UI/VirtualGoodsStore/Purchase/Completed'),
            audioEventName='store_purchase_success',
            width=CONTAINER_WIDTH)
        self.purchaseFailurePanel = PurchaseResultPanel(
            parent=self.bottomContainer,
            closeOfferCallback=self.CloseOffer,
            iconForegroundTexturePath=
            'res:/UI/Texture/vgs/purchase_fail_fg.png',
            iconBackgroundTexturePath=
            'res:/UI/Texture/vgs/purchase_fail_bg.png',
            textTitle=localization.GetByLabel(
                'UI/VirtualGoodsStore/Purchase/Failed'),
            audioEventName='store_purchase_failure',
            width=CONTAINER_WIDTH)
        VgsLabelSmall(
            parent=self.purchaseFailurePanel,
            align=uiconst.TOTOP,
            text='<center>%s</center>' % localization.GetByLabel(
                'UI/VirtualGoodsStore/Purchase/FailureReasonUnknown'),
            padding=(TEXT_PADDING, TEXT_PADDING, TEXT_PADDING, 0))

    def CreateRedeemPanel(self, offer, offerQuantity):
        self.redeemContainer = StaticRedeemContainer(
            parent=self.purchaseSuccessPanel,
            name='offerRedeemQueueContent',
            align=uiconst.TOTOP,
            padTop=TEXT_PADDING,
            redeemTokens=GetSortedTokens(offer.productQuantities),
            offerQuantity=offerQuantity,
            clipChildren=False,
            containerWidth=CONTAINER_WIDTH,
            dragEnabled=False,
            minimizeTokens=True)
        self.successDescriptionText = VgsLabelSmall(
            parent=self.purchaseSuccessPanel,
            align=uiconst.TOTOP,
            text='<center>%s</center>' % localization.GetByLabel(
                'UI/VirtualGoodsStore/Purchase/NewPurchaseInstruction'),
            padding=(TEXT_PADDING, TEXT_PADDING, TEXT_PADDING, 0))
        self.successDescriptionText.opacity = 0.0

    def CreateFakeRedeemPanel(self):
        instructionText = '<url=localsvc:service=vgsService&method=ShowRedeemUI>%s</url>' % (
            localization.GetByLabel(
                'UI/RedeemWindow/ClickToInitiateRedeeming'), )
        self.fakeRedeemingPanel = RedeemPanel(
            parent=self.backgroundBottomContainer,
            name='fakeRedeemPanel',
            align=uiconst.TOBOTTOM,
            dragEnabled=False,
            redeemButtonBackgroundColor=REDEEM_BUTTON_BACKGROUND_COLOR,
            redeemButtonFillColor=REDEEM_BUTTON_FILL_COLOR,
            buttonClick=None,
            instructionText=instructionText)
        self.fakeRedeemingPanel.UpdateDisplay(animate=False)
        self.fakeRedeemingPanel.HidePanel(animate=False)
        self.vgsUiController.view.storeContainer.redeemingPanel.HidePanel()
        self.vgsUiController.view.storeContainer.redeemingPanel.SetListenToRedeemQueueUpdatedEvents(
            False)

    def OnPreviewType(self, typeID):
        self.preview.typeID = typeID

    def OpenFakeRedeemPanel(self):
        self.fakeRedeemingPanel.ExpandPanel(animate=True, showNewItems=False)

    def SwitchToProgressPanel(self):
        self.SwitchToPanel(self.purchaseProgressPanel)

    def SwitchToSuccessPanel(self, offerQuantity):
        self.CreateRedeemPanel(self.offer, offerQuantity)
        self.SwitchToPanel(self.purchaseSuccessPanel)
        self.OpenFakeRedeemPanel()
        self.fakeRedeemingPanel.AddRedeemContainerContent(self.redeemContainer)
        uicore.animations.MoveOutTop(self.redeemContainer,
                                     amount=self.redeemContainer.height,
                                     timeOffset=1.0,
                                     sleep=True,
                                     callback=self.redeemContainer.Close)
        uicore.animations.FadeIn(self.successDescriptionText,
                                 duration=1.0,
                                 sleep=True)
        self.fakeRedeemingPanel.HidePanel(animate=True)

    def SwitchToFailurePanel(self):
        self.SwitchToPanel(self.purchaseFailurePanel)

    def HasSuccessfullyBoughtItem(self):
        return self.activeBottomPanel == self.purchaseSuccessPanel

    def SwitchToPanel(self, newPanel):
        newPanel.OnPanelActivated()
        uicore.animations.MoveOutLeft(self.activeBottomPanel,
                                      CONTAINER_WIDTH,
                                      duration=PROGRESS_TRANSITION_TIME)
        self.activeBottomPanel = newPanel
        self.activeBottomPanel.state = uiconst.UI_PICKCHILDREN
        uicore.animations.MoveInFromRight(self.activeBottomPanel,
                                          CONTAINER_WIDTH,
                                          duration=PROGRESS_TRANSITION_TIME,
                                          sleep=True)

    def CloseOffer(self, *args):
        uthread.new(sm.GetService('vgsService').GetUiController().CloseOffer)

    def PrepareClose(self):
        self.preview.PrepareClose()

    def _OnResize(self, *args):
        if not hasattr(self, 'backgroundTopContainer'):
            return
        self.backgroundTopContainer.height = self.parent.GetAbsoluteSize()[1]