def requestDialog(self, dialogId=None):
        self.endDialog()
        if not dialogId:
            availableDialogs = []
            npcDialogs = DialogDict.get(self.getUniqueId())
            if npcDialogs:
                for dialogId in npcDialogs:
                    firstDialogProcess = npcDialogs.get(dialogId).get(0)[0]
                    if firstDialogProcess.prereq and firstDialogProcess.avCanParticipate(
                            localAvatar):
                        availableDialogs.append(dialogId)

        else:
            availableDialogs = [dialogId]
        localAvatar.b_setGameState('NPCInteract', localArgs=[self, True, True])
        self.accept('endDialogNPCInteract', self.endDialog)
        self.dialogProcessMaster = DialogProcessMaster(self, availableDialogs)
        taskMgr.doMethodLater(0.25, self.startDialog,
                              'startDialogProcessMaster')
    def requestDialog(self, dialogId = None):
        self.endDialog()
        if not dialogId:
            availableDialogs = []
            npcDialogs = DialogDict.get(self.getUniqueId())
            if npcDialogs:
                for dialogId in npcDialogs:
                    firstDialogProcess = npcDialogs.get(dialogId).get(0)[0]
                    if firstDialogProcess.prereq and firstDialogProcess.avCanParticipate(localAvatar):
                        availableDialogs.append(dialogId)
                        continue


        else:
            availableDialogs = [
                dialogId]
        localAvatar.b_setGameState('NPCInteract', localArgs = [
            self,
            True,
            True])
        self.accept('endDialogNPCInteract', self.endDialog)
        self.dialogProcessMaster = DialogProcessMaster(self, availableDialogs)
        taskMgr.doMethodLater(0.25, self.startDialog, 'startDialogProcessMaster')
예제 #3
0
class DistributedQuestGiver(Avatar.Avatar):
    notify = directNotify.newCategory('DistributedQuestGiver')
    NoOffer = 0
    LadderOffer = 1
    QuestOffer = 2
    InteractOffer = 3
    BranchOffer = 4
    QuestIconWorkTexture = None
    QuestIconStoryTexture = None
    QuestIconProgressTexture = None
    QuestIconCompleteTexture = None
    QuestIconDontCare = 1
    QuestIconStory = 2
    QuestIconWork = 3
    QuestIconNew = 1
    QuestIconProgress = 2
    QuestIconComplete = 3
    
    def __init__(self):
        self.playingQuestString = False
        self.dialogOpen = False
        self.newOffer = False
        self.offers = None
        self.offerType = self.NoOffer
        self.dialogFlag = 0
        self.firstDialog = True
        self.newDialog = False
        self.npcMoviePlayer = None
        self.quitButton = 0
        self.nametagIcon = None
        self.nametagIconGlow = None
        self.containerId = None
        self.dialogAnimSet = None
        self.animationIval = None
        self.resetQuest = None
        self.resetBranch = None
        self.selectedOffer = None
        self.dialogProcessMaster = None
        self.dialogQuestOffer = None

    
    def generate(self):
        DistributedQuestGiver.notify.debug('generate(%s)' % self.doId)
        self.questMenuGUI = None
        self.questDetailGUI = None
        self.questRewardGUI = None
        self.branchMenuGUI = None
        self.questDetailCamera = None

    
    def announceGenerate(self):
        DistributedQuestGiver.notify.debug('announceGenerate(%s)' % self.doId)

    
    def disable(self):
        DistributedQuestGiver.notify.debug('disable(%s)' % self.doId)
        if self.npcMoviePlayer:
            self.npcMoviePlayer.cleanup()
            self.npcMoviePlayer = None
        
        self.cleanUpQuestMenu()
        self.cleanUpQuestDetails()
        self.cleanUpBranchMenu()
        self.ignore('endDialogNPCInteract')
        self.ignore('lastSubtitlePage')

    
    def cleanUpQuestMenu(self):
        if self.questMenuGUI:
            self.questMenuGUI.destroy()
            self.questMenuGUI = None
        

    
    def cleanUpBranchMenu(self):
        self.resetBranch = None
        self.selectedOffer = None
        if self.branchMenuGUI:
            self.branchMenuGUI.destroy()
            self.branchMenuGUI = None
        

    
    def cleanUpQuestDetails(self, hide = False):
        if self.questDetailGUI:
            if hide:
                self.questDetailGUI.hidePanelAndDestroy()
            else:
                self.questDetailGUI.destroy()
            self.questDetailGUI = None
        
        if self.questRewardGUI:
            if hide:
                self.questRewardGUI.hidePanelAndDestroy()
            else:
                self.questRewardGUI.destroy()
            self.questRewardGUI = None
        
        if not hide and self.questDetailCamera:
            self.questDetailCamera.finish()
            self.questDetailCamera = None
        

    
    def delete(self):
        DistributedQuestGiver.notify.debug('delete(%s)' % self.doId)

    
    def offerOptions(self):
        self.notify.warning('offerOptions() needs override!')

    
    def cancelInteraction(self, av):
        self.notify.warning('cancelInteraction() needs override!')

    
    def hasOpenGUI(self):
        self.notify.warning('hasOpenGUI() needs override!')
        return False

    
    def hasQuestOffers(self):
        AvailableQuests = []
        inventory = localAvatar.getInventory()
        prereqExcludes = base.config.GetString('exclude-prereq-quests', '')
        for (questId, questDNA) in QuestDB.QuestDict.items():
            if len(prereqExcludes):
                if questId in prereqExcludes:
                    continue
                
            
            prereqs = questDNA.getPrereqs()
            passed = True
            for prereq in prereqs:
                if not prereq.giverCanGive(self.getUniqueId()):
                    passed = False
                    break
                
                if not prereq.avIsReady(localAvatar):
                    passed = False
                    break
                
                if questDNA.minLevel > localAvatar.level:
                    passed = False
                    break
                
                if not base.cr.questDependency.checkDependency(questId, localAvatar.getQuestLadderHistory(), 1):
                    passed = False
                    break
                
                boolWeapLvlCheck = (questDNA.weapLvlType != None) & (questDNA.minWeapLevel > 0)
                if boolWeapLvlCheck & (questDNA.minWeapLevel > getLevelFromTotalReputation(questDNA.weapLvlType, inventory.getReputation(questDNA.weapLvlType))[0]):
                    passed = False
                    break
                
                if questDNA.getVelvetRoped() and not Freebooter.getPaidStatus(localAvatar.getDoId()):
                    passed = False
                    break
                
                if questDNA.getAcquireOnce():
                    history = localAvatar.getQuestLadderHistory()
                    questLadderId = base.cr.questDynMap.findQuestLadderInt(questId)
                    containsLadderId = history.count(questLadderId)
                    if containsLadderId:
                        passed = False
                        break
                    
                
                if questDNA.getHoliday() is not None:
                    holidayId = questDNA.getHoliday()
                    if base.cr.newsManager and not base.cr.newsManager.getHoliday(holidayId):
                        passed = False
                        break
                    
                not base.cr.newsManager.getHoliday(holidayId)
            
            if prereqs and passed:
                AvailableQuests.append(questDNA)
                continue
        
        if len(AvailableQuests):
            inventory = localAvatar.getInventory()
            if inventory:
                toRemove = []
                questList = inventory.getQuestList()
                for questDNA in AvailableQuests:
                    questId = questDNA.getQuestId()
                    found = False
                    for quest in questList:
                        if questId == quest.getQuestId() or localAvatar.questStatus.hasLadderQuestId(questId):
                            found = True
                            continue
                    
                    if found:
                        toRemove.append(questDNA)
                        continue
                
                for questDNA in toRemove:
                    AvailableQuests.remove(questDNA)
                
            
        
        for quest in localAvatar.getQuests():
            if quest and quest.getTimeLimit() and quest.canBeReturnedTo(self.getQuestGiverId()):
                return True
                continue
        
        return len(AvailableQuests) > 0

    
    def receiveOffer(self, offerType):
        self.newOffer = True
        self.offerType = offerType

    
    def clearOffer(self):
        self.newOffer = False
        self.offerType = self.NoOffer

    
    def displayNewQuests(self):
        self.cleanUpQuestDetails()
        while len(localAvatar.currentStoryQuests) and localAvatar.currentStoryQuests[0].getGiverId() != self.uniqueId:
            if localAvatar.currentStoryQuests[0].getGiverId() == '0':
                break
            
            localAvatar.currentStoryQuests.remove(localAvatar.currentStoryQuests[0])
        if len(localAvatar.currentStoryQuests):
            storyQuest = localAvatar.currentStoryQuests[0]
            self.presentQuestGiven(storyQuest)
            localAvatar.currentStoryQuests.remove(storyQuest)
        

    
    def presentOffer(self):
        if self.newOffer == False:
            while len(localAvatar.currentStoryQuests) and localAvatar.currentStoryQuests[0].getGiverId() != self.uniqueId:
                localAvatar.currentStoryQuests.remove(localAvatar.currentStoryQuests[0])
            if len(localAvatar.currentStoryQuests):
                storyQuest = localAvatar.currentStoryQuests[0]
                self.presentQuestGiven(storyQuest)
                localAvatar.currentStoryQuests.remove(storyQuest)
            
            return None
        
        if self.offerType == self.QuestOffer:
            self.presentQuestOffer(self.offers)
        elif self.offerType == self.LadderOffer:
            self.presentQuestOffer(self.offers, ladder = True)
        elif self.offerType == self.InteractOffer:
            self.offerOptions(self.dialogFlag)
        elif self.offerType == self.NoOffer:
            self.notify.warning('offerType == No Offer')
        
        self.clearOffer()

    
    def setQuestOffer(self, offers):
        self.receiveOffer(self.QuestOffer)
        self.offers = offers
        for quest in localAvatar.getQuests():
            if quest.getTimeLimit() and quest.canBeReturnedTo(self.getQuestGiverId()):
                questOffer = QuestOffer.QuestTimerResetOffer.create(quest.getQuestId(), localAvatar, timerReset = True)
                offers.append(questOffer)
            
            branchParent = quest.getBranchParent(localAvatar)
            if branchParent and branchParent.getGiverId() == self.getQuestGiverId():
                questOffer = QuestOffer.QuestBranchResetOffer.create(quest.getQuestId(), localAvatar, branchReset = True)
                offers.append(questOffer)
                continue
        
        if not self.playingQuestString:
            self.presentQuestOffer(self.offers)
        

    
    def setQuestLadderOffer(self, offers, quitButton):
        self.receiveOffer(self.LadderOffer)
        self.offers = offers
        self.quitButton = quitButton
        if not self.playingQuestString:
            self.presentQuestOffer(self.offers, ladder = True)
        

    
    def presentQuestOffer(self, offers, ladder = False):
        if self.questMenuGUI:
            DistributedQuestGiver.notify.warning('setQuestOffer: old questMenu GUI still around')
            self.cleanUpQuestMenu()
        
        self.cleanUpQuestDetails()
        
        def handleSelection(offer, self = self, offers = offers):
            self.cleanUpQuestMenu()
            if offer == QuestConstants.CANCEL_QUEST:
                index = QuestConstants.CANCEL_QUEST
            else:
                index = offers.index(offer)
            self.sendOfferResponse(index, ladder)

        
        def handleOption(option, offer):
            base.test = self
            self.ignore('lastSubtitlePage')
            self.adjustNPCCamera('back')
            if option == PLocalizer.Accept:
                handleSelection(offer)
            elif self.questMenuGUI:
                self.questMenuGUI.show()
            
            self.cleanUpQuestDetails(hide = True)

        
        def displayQuestDetails(offer):
            self.questDetailGUI = QuestDetailGUI(offer, None)
            self.questDetailGUI.showPanel()
            base.questdet = self.questDetailGUI

        
        def displayBranchDetails(offer):
            self.selectedOffer = offer
            self.cleanUpQuestDetails()
            self.questDetailGUI = QuestDetailGUI(offer, None)
            self.questDetailGUI.showPanel()
            base.questdet = self.questDetailGUI

        
        def displayBranchOptions(offer, callback, descCallback):
            self.branchMenuGUI = BranchMenuGUI.BranchMenuGUI(offer, callback, descCallback)

        
        def handleBranchOption(option):
            if option == PLocalizer.Accept:
                if self.selectedOffer:
                    self.sendOfferResponse(0, ladder, self.selectedOffer)
                
            
            self.adjustNPCCamera('back')
            self.cleanUpQuestDetails(hide = True)
            self.cleanUpBranchMenu()
            if self.questMenuGUI:
                self.questMenuGUI.show()
            

        
        def describeQuest(offer):
            self.adjustNPCCamera('forward')
            questDNA = offer.getQuestDNA()
            if questDNA:
                if isinstance(offer, QuestOffer.QuestTimerResetOffer):
                    self.requestQuestReset(offer.getQuestId())
                    return None
                elif isinstance(offer, QuestOffer.QuestBranchResetOffer):
                    self.requestBranchReset(offer.getQuestId())
                    return None
                
                questStr = questDNA.getStringBefore()
                if questDNA.isBranch():
                    self.acceptOnce('lastSubtitlePage', displayBranchOptions, [
                        offer,
                        None,
                        displayBranchDetails])
                    localAvatar.guiMgr.subtitler.setPageChat(questStr, options = [
                        PLocalizer.Decline,
                        PLocalizer.Accept], callback = handleBranchOption)
                else:
                    self.acceptOnce('lastSubtitlePage', displayQuestDetails, [
                        offer])
                    localAvatar.guiMgr.subtitler.setPageChat(questStr, options = [
                        PLocalizer.Decline,
                        PLocalizer.Accept], callback = handleOption, extraArgs = [
                        offer])
            

        
        def questFull(arg):
            self.cleanUpQuestMenu()
            self.sendOfferResponse(QuestConstants.CANCEL_QUEST, ladder)

        inv = base.localAvatar.getInventory()
        numWorkQuests = 0
        if inv:
            questList = inv.getQuestList()
            for questId in questList:
                if not QuestLadderDB.getFamePath(questId):
                    numWorkQuests += 1
                    continue
            
        
        hasStoryQuest = False
        for offer in offers:
            if QuestLadderDB.getFamePath(offer.getQuestId()):
                hasStoryQuest = True
                continue
        
        if not hasStoryQuest and numWorkQuests > QuestConstants.MAXIMUM_MERC_WORK:
            self.questMenuGUI = PDialog.PDialog(text = PLocalizer.QuestFull, style = OTPDialog.Acknowledge, command = questFull)
        else:
            self.questMenuGUI = QuestMenuGUI.QuestMenuGUI(offers, handleSelection, describeQuest)
        localAvatar.currentStoryQuests = []
        self.clearOffer()

    
    def presentBranchReset(self, declineOption = True):
        if not self.resetBranch:
            return None
        
        
        def displayBranchOptions(offer, callback, descCallback):
            self.branchMenuGUI = BranchMenuGUI.BranchMenuGUI(offer, callback, descCallback)

        
        def displayBranchDetails(offer):
            self.selectedOffer = offer
            self.cleanUpQuestDetails()
            self.questDetailGUI = QuestDetailGUI(offer, None)
            self.questDetailGUI.showPanel()
            base.questdet = self.questDetailGUI
            subtitleOptions = [
                PLocalizer.Accept]
            if declineOption:
                subtitleOptions = [
                    PLocalizer.Decline,
                    PLocalizer.Accept]
            
            localAvatar.guiMgr.subtitler.setPageChat('Is that your choice?', options = subtitleOptions, callback = handleBranchOption)

        
        def handleBranchOption(option):
            if option == PLocalizer.Accept:
                if self.selectedOffer:
                    self.sendOfferResponse(0, offer = self.selectedOffer)
                
            else:
                self.offerOptions(False)
            self.adjustNPCCamera('back')
            self.cleanUpQuestDetails(hide = True)
            self.cleanUpBranchMenu()
            self.cleanUpQuestMenu()

        offer = QuestOffer.QuestOffer.create(self.resetBranch.getName(), localAvatar)
        if declineOption:
            subtitleOptions = [
                PLocalizer.Decline]
            self.acceptOnce('lastSubtitlePage', displayBranchOptions, [
                offer,
                None,
                displayBranchDetails])
            localAvatar.guiMgr.subtitler.setPageChat('', options = subtitleOptions, callback = handleBranchOption)
        else:
            subtitleOptions = []
            displayBranchOptions(offer, None, displayBranchDetails)
        self.ignore('doneChatPage')

    
    def presentQuestReset(self):
        if not self.resetQuest:
            return None
        
        
        def handleOption(option):
            if option == PLocalizer.Accept:
                self.resetQuest.startTimer()
            
            self.resetQuest = None
            self._DistributedQuestGiver__handleDoneChatPage(0)

        self.questDetailGUI = QuestDetailGUI(None, None, self.resetQuest.questDNA)
        self.questDetailGUI.showPanel()
        localAvatar.guiMgr.subtitler.setPageChat('', options = [
            PLocalizer.Accept], callback = handleOption)

    
    def presentQuestGiven(self, quest):
        self.resetBranch = None
        if self.resetBranch:
            container = localAvatar.questStatus.getContainer(quest.getQuestId())
            if container.parent and container.parent.getFirstQuestId() == quest.getQuestId():
                self.presentBranchReset(False)
                return None
            else:
                self.resetBranch = None
        
        
        def handleOption(option):
            if len(localAvatar.currentStoryQuests):
                self.cleanUpQuestDetails(hide = True)
                while len(localAvatar.currentStoryQuests) and localAvatar.currentStoryQuests[0].getGiverId() != self.uniqueId:
                    localAvatar.currentStoryQuests.remove(localAvatar.currentStoryQuests[0])
            
            if len(localAvatar.currentStoryQuests):
                storyQuest = localAvatar.currentStoryQuests[0]
                self.presentQuestGiven(storyQuest)
                localAvatar.currentStoryQuests.remove(storyQuest)
            elif hasattr(quest, 'questDNA') and quest.questDNA.getTimeLimit():
                quest.startTimer()
            
            self._DistributedQuestGiver__handleDoneChatPage(0)

        self.questDetailGUI = QuestDetailGUI(None, None, quest)
        self.questDetailGUI.showPanel()
        localAvatar.guiMgr.subtitler.setPageChat('', options = [
            PLocalizer.Accept], callback = handleOption)
        base.questdet = self.questDetailGUI
        self.ignore('doneChatPage')

    
    def adjustNPCCamera(self, direction):
        dummy = NodePath('dummy')
        dummy.reparentTo(camera)
        if direction == 'forward':
            dummy.setH(dummy, -15)
            dummy.setY(dummy, 0.75)
            duration = 0.69999999999999996
        else:
            dummy.setY(dummy, -0.75)
            dummy.setH(dummy, 15)
            duration = 0.5
        dummy.wrtReparentTo(camera.getParent())
        (camH, dummyH) = getShortestRotation(camera.getH(), dummy.getH())
        self.questDetailCamera = Parallel(LerpFunc(camera.setH, duration = duration, fromData = camH, toData = dummyH, blendType = 'easeInOut'), LerpFunc(camera.setY, duration = duration, fromData = camera.getY(), toData = dummy.getY(), blendType = 'easeInOut'))
        dummy.removeNode()
        self.questDetailCamera.start()

    
    def getOfferedQuests(self):
        return list(self.offers)

    
    def sendOfferResponse(self, index, ladder = False, offer = None):
        if index == QuestConstants.CANCEL_QUEST:
            self.dialogOpen = False
        
        if offer:
            self.sendUpdate('assignBranchOffer', [
                offer])
        else:
            self.sendUpdate('setOfferResponse', [
                index,
                ladder])
        self.offers = None
        self.clearOffer()

    
    def b_setPageNumber(self, paragraph, pageNumber):
        self.setPageNumber(paragraph, pageNumber)
        self.d_setPageNumber(paragraph, pageNumber)

    
    def d_setPageNumber(self, paragraph, pageNumber):
        pass

    
    def playQuestString(self, questStr, timeout = False, quitButton = 1, useChatBubble = False, confirm = False, animSet = None):
        self.notify.debug('playQuestString %s, %s, %s, %s' % (timeout, quitButton, useChatBubble, confirm))
        if questStr.find('quest_') == 0:
            nmp = QuestParser.NPCMoviePlayer(questStr, localAvatar, self)
            nmp.play()
            self.npcMoviePlayer = nmp
        else:
            self.firstDialog = False
            self.dialogAnimSet = animSet
            if questStr:
                if timeout:
                    if useChatBubble:
                        self.setPageChat(localAvatar.doId, 0, questStr, 0, extraChatFlags = CFSpeech | CFTimeout, pageButton = False)
                    else:
                        base.localAvatar.guiMgr.subtitler.setPageChat(questStr, timeout = timeout)
                    return None
                else:
                    self.playingQuestString = True
                    if self.newOffer == False:
                        questStr += '\x07'
                    
                    base.localAvatar.guiMgr.subtitler.setPageChat(questStr, confirm = confirm)
                    self.dialogOpen = True
                self.playAnimation(0)
                if quitButton == 1 or confirm:
                    self.accept('doneChatPage', self._DistributedQuestGiver__handleDoneChatPage)
                
                if base.localAvatar.guiMgr.subtitler.getNumChatPages() == 1:
                    self._DistributedQuestGiver__handleNextChatPage(0, 0)
                else:
                    self.accept('nextChatPage', self._DistributedQuestGiver__handleNextChatPage)
            

    
    def _DistributedQuestGiver__handleNextChatPage(self, pageNumber, elapsed):
        self.notify.debug('handleNextChatPage pageNumber = %s, elapsed = %s' % (pageNumber, elapsed))
        if pageNumber == base.localAvatar.guiMgr.subtitler.getNumChatPages() - 1:
            self.ignore('nextChatPage')
            self.playingQuestString = False
            self.presentBranchReset()
            self.presentQuestReset()
            self.presentOffer()
        
        self.playAnimation(pageNumber)

    
    def _DistributedQuestGiver__handleDoneChatPage(self, elapsed):
        self.ignore('nextChatPage')
        self.ignore('doneChatPage')
        self.playingQuestString = False
        self.dialogOpen = False
        if self.newDialog:
            self.playDialog()
        
        if not self.hasOpenGUI():
            self.interactMode = 1
            self.cancelInteraction(base.localAvatar)
        
        self.cancelInteraction(base.localAvatar)

    
    def playAnimation(self, index):
        if self.animationIval:
            self.animationIval.finish()
            self.animationIval = None
        
        if self.dialogAnimSet:
            if len(self.dialogAnimSet) > index and self.dialogAnimSet[index]:
                self.animationIval = Sequence(Wait(0.5), Func(self.gameFSM.request, 'Emote'), Func(self.playEmote, self.dialogAnimSet[index]))
                self.animationIval.start()
            
        

    
    def playDialog(self):
        self.notify.warning('playDialog() needs override!')

    
    def setQuestsCompleted(self, menuFlag, completedContainerIds, completedChainedQuestIds, completedQuestIds, completedQuestDoIds):
        questStr = ''
        self.cleanUpQuestDetails()
        
        def handleOption(option, questStr, menuFlag, confirm, animSet):
            self.cleanUpQuestDetails(hide = True)
            self.playQuestString(questStr, quitButton = menuFlag, confirm = True, animSet = animSet)

        if len(completedContainerIds):
            if completedContainerIds[0] in [
                'c3visitJack']:
                return None
            
            if len(completedContainerIds) > 1:
                self.notify.warning('Multiple simultaneous completed quest containers for the same NPC: %s!' % completedContainerIds)
            
            containerId = completedContainerIds[0]
            self.containerId = containerId
            container = QuestLadderDB.getContainer(containerId)
            if container:
                dialogId = container.getDialogAfter()
                if dialogId:
                    self.requestDialog(dialogId)
                    return None
                
                questStr = container.getStringAfter()
                animSet = container.getAnimSetAfter()
                localAvatar.b_setGameState('NPCInteract', localArgs = [
                    self,
                    False,
                    False])
                if hasattr(self, '_questRewardsEarned'):
                    self.questRewardGUI = QuestRewardGUI(container, self._questRewardsEarned)
                    localAvatar.guiMgr.subtitler.setPageChat('', options = [
                        PLocalizer.Continue], callback = handleOption, extraArgs = [
                        questStr,
                        menuFlag,
                        True,
                        animSet])
                else:
                    handleOption(questStr, menuFlag, True, animSet)
                return None
            else:
                self.notify.warning('%s not in QuestLadderDB!' % containerId)
        
        if len(completedChainedQuestIds):
            pass
        1
        if len(completedQuestIds):
            if len(completedContainerIds) == 0:
                questId = completedQuestIds[0]
                quest = QuestDB.QuestDict.get(questId)
                if quest:
                    questStr = quest.getStringAfter()
                    animSet = quest.getAnimSetAfter()
                    self.notify.debug('%s stringAfter: %s' % (questId, questStr))
                    if hasattr(self, '_questRewardsEarned'):
                        print 'GOT questRewardsEarned: %s' % self._questRewardsEarned
                        self.questRewardGUI = QuestRewardGUI(quest, self._questRewardsEarned)
                        localAvatar.guiMgr.subtitler.setPageChat('', options = [
                            PLocalizer.Continue], callback = handleOption, extraArgs = [
                            questStr,
                            menuFlag,
                            True,
                            animSet])
                    else:
                        handleOption(questStr, menuFlag, True, animSet)
                else:
                    self.notify.warning('%s not in QuestDB!' % questId)
            
            localAvatar.b_setGameState('NPCInteract', localArgs = [
                self,
                True,
                False])
        
        if len(completedQuestIds) == 0 and len(completedChainedQuestIds) == 0 and len(completedContainerIds) == 0:
            if not self.hasOpenGUI():
                self.cancelInteraction(base.localAvatar)
            
        

    
    def requestQuestReset(self, questId):
        self.resetQuest = localAvatar.getQuestById(questId)
        if self.resetQuest:
            questStr = self.resetQuest.questDNA.getStringBefore()
            self.cleanUpQuestDetails(hide = True)
            self.playQuestString(questStr, quitButton = True, confirm = True)
            localAvatar.b_setGameState('NPCInteract', localArgs = [
                self,
                True,
                False])
        

    
    def requestBranchReset(self, questId):
        quest = localAvatar.getQuestById(questId)
        self.resetBranch = quest.getBranchParent(localAvatar)
        resetBranchDNA = QuestLadderDB.getContainer(self.resetBranch.getQuestId())
        questStr = resetBranchDNA.getStringBefore()
        self.cleanUpQuestDetails(hide = True)
        self.playQuestString(questStr, quitButton = False, confirm = True)
        localAvatar.b_setGameState('NPCInteract', localArgs = [
            self,
            True,
            False])

    
    def requestDialog(self, dialogId = None):
        self.endDialog()
        if not dialogId:
            availableDialogs = []
            npcDialogs = DialogDict.get(self.getUniqueId())
            if npcDialogs:
                for dialogId in npcDialogs:
                    firstDialogProcess = npcDialogs.get(dialogId).get(0)[0]
                    if firstDialogProcess.prereq and firstDialogProcess.avCanParticipate(localAvatar):
                        availableDialogs.append(dialogId)
                        continue
                
            
        else:
            availableDialogs = [
                dialogId]
        localAvatar.b_setGameState('NPCInteract', localArgs = [
            self,
            True,
            True])
        self.accept('endDialogNPCInteract', self.endDialog)
        self.dialogProcessMaster = DialogProcessMaster(self, availableDialogs)
        taskMgr.doMethodLater(0.25, self.startDialog, 'startDialogProcessMaster')

    
    def startDialog(self, task = None):
        if self.dialogProcessMaster:
            self.dialogProcessMaster.start()
        

    
    def endDialog(self):
        taskMgr.remove('startDialogProcessMaster')
        self.ignore('endDialogNPCInteract')
        if self.dialogProcessMaster:
            self.dialogProcessMaster.stop()
            self.dialogProcessMaster = None
        

    
    def requestDialogInteraction(self, dialogId):
        self.sendUpdate('requestDialogInteraction', [
            dialogId])

    
    def endDialogInteraction(self, dialogId):
        self.sendUpdate('endDialogInteraction', [
            dialogId])

    
    def requestDialogQuestAdvancement(self, questId, dialogId):
        self.sendUpdate('requestDialogQuestAdvancement', [
            questId,
            dialogId])

    
    def requestDialogQuestAssignment(self, questId, dialogId):
        self.sendUpdate('requestDialogQuestAssignment', [
            questId,
            dialogId])

    
    def requestDialogQuestOffer(self, questId, dialogId):
        self.sendUpdate('requestDialogQuestOffer', [
            questId,
            dialogId])

    
    def setDialogQuestOffer(self, questOffer):
        self.dialogQuestOffer = questOffer
        messenger.send('setDialogQuestOffer')

    
    def showDialogQuestOffer(self):
        if self.dialogQuestOffer:
            self.questDetailGUI = QuestDetailGUI(self.dialogQuestOffer, None)
            self.questDetailGUI.showPanel()
        

    
    def assignDialogQuestOffer(self):
        if self.dialogQuestOffer:
            self.sendUpdate('assignDialogQuestOffer')
        

    
    def showQuestRewards(self):
        if hasattr(self, '_questRewardsEarned') and self.containerId:
            container = QuestLadderDB.getContainer(self.containerId)
            self.questRewardGUI = QuestRewardGUI(container, self._questRewardsEarned)
        

    
    def hideQuestRewards(self):
        if self.questRewardGUI:
            self.questRewardGUI.destroy()
            self.questRewardGUI = None
        

    
    def requestNPCHostile(self, npcId, dialogId):
        self.sendUpdate('requestNPCHostile', [
            npcId,
            dialogId])

    
    def playDialogMovie(self, dialogId, doneCallback = None, oldLocalAvState = None):
        movieChoice = InteractGlobals.getNPCTutorial(dialogId)
        if movieChoice == None:
            movieChoice = dialogId
        
        globalClock.tick()
        self.currentDialogMovie = QuestParser.NPCMoviePlayer(movieChoice, localAvatar, self)
        self.currentDialogMovie.overrideOldAvState(oldLocalAvState)
        self.currentDialogMovie.play()
        self.acceptOnce('dialogFinish', self.stopDialogMovie, extraArgs = [
            doneCallback])

    
    def stopDialogMovie(self, doneCallback):
        if hasattr(self, 'currentDialogMovie'):
            self.currentDialogMovie.npc.showName()
            self.currentDialogMovie.npc.nametag3d.setZ(0)
            self.currentDialogMovie.finishUpAll()
            del self.currentDialogMovie
            self.sendUpdate('dialogMovieComplete')
            if doneCallback:
                doneCallback()
            
        

    
    def swapCurrentDialogMovie(self, newDialogMovie):
        if hasattr(self, 'currentDialogMovie'):
            if newDialogMovie:
                oldAvState = self.currentDialogMovie.overrideOldAvState(None)
                newDialogMovie.overrideOldAvState(oldAvState)
            
            self.currentDialogMovie.finishUpAll()
        
        self.currentDialogMovie = newDialogMovie

    
    def getQuestGiverId(self):
        return self.getUniqueId()

    
    def hasQuestOffersForLocalAvatar(self):
        av = localAvatar
        inventory = av.getInventory()
        selfId = self.getQuestGiverId()
        if inventory:
            numInProgress = 0
            for quest in inventory.getQuestList():
                questType = self.QuestIconDontCare
                if quest.tasks is None:
                    self.notify.warning('quest %s: does not contain a dna; potential for crash.' % quest.getQuestId())
                    return False
                
                for (task, taskState) in zip(quest.tasks, quest.taskStates):
                    if isinstance(task, QuestTaskDNA.VisitTaskDNA):
                        if task.npcId == selfId:
                            questStatus = self.QuestIconComplete
                            return (questType, questStatus)
                        
                    task.npcId == selfId
                
                if quest.canBeReturnedTo(selfId):
                    isComplete = False
                    if quest.isComplete():
                        container = localAvatar.questStatus.getContainer(quest.getQuestId())
                        if container and container.parent and container.parent.isChoice():
                            isComplete = True
                            for q in container.parent.getContainers():
                                if q.quest and not q.quest.isComplete():
                                    isComplete = False
                                    continue
                            
                        else:
                            isComplete = True
                    
                    if isComplete:
                        questStatus = self.QuestIconComplete
                        return (questType, questStatus)
                    else:
                        numInProgress += 1
            
        else:
            self.notify.warning('avatar does not have inventory yet')
            return False
        offerDict = { }
        fromQuests = []
        prereqExcludes = base.config.GetString('exclude-prereq-quests', '')
        for (questId, questDNA) in QuestDB.QuestDict.items():
            if prereqExcludes and questId in prereqExcludes:
                continue
            
            passed = True
            for prereq in questDNA.prereqs:
                if not prereq.giverCanGive(selfId):
                    passed = False
                    break
                
                if not prereq.avIsReady(localAvatar):
                    passed = False
                    break
                
                if questDNA.minLevel > localAvatar.level:
                    passed = False
                    break
                
                if not base.cr.questDependency.checkDependency(questId, localAvatar.getQuestLadderHistory(), 1):
                    passed = False
                    break
                
                boolWeapLvlCheck = (questDNA.weapLvlType != None) & (questDNA.minWeapLevel > 0)
                if boolWeapLvlCheck & (questDNA.minWeapLevel > getLevelFromTotalReputation(questDNA.weapLvlType, inventory.getReputation(questDNA.weapLvlType))[0]):
                    passed = False
                    break
                
                if questDNA.getAcquireOnce():
                    history = localAvatar.getQuestLadderHistory()
                    questLadderId = base.cr.questDynMap.findQuestLadderInt(questId)
                    containsLadderId = history.count(questLadderId)
                    if containsLadderId:
                        passed = False
                        break
                    
                
                if questDNA.getHoliday() is not None:
                    holidayId = questDNA.getHoliday()
                    if base.cr.newsManager and not base.cr.newsManager.getHoliday(holidayId):
                        passed = False
                        break
                    
                not base.cr.newsManager.getHoliday(holidayId)
            
            if questDNA.prereqs and passed:
                fromQuests.append(questDNA)
                continue
        
        if len(fromQuests):
            inventory = av.getInventory()
            if inventory:
                questsLeft = []
                questList = inventory.getQuestList()
                for questDNA in fromQuests:
                    questId = questDNA.questId
                    if not av.questStatus.hasLadderQuestId(questId):
                        continue
                        if _[1] not in [ x.questId for x in questList ]:
                            questsLeft.append(questDNA)
                            continue
                    []
                
                fromQuests = questsLeft
            
        
        if fromQuests:
            questType = self.QuestIconWork
            for quest in fromQuests:
                if QuestLadderDB.getFamePath(quest.questId):
                    questType = self.QuestIconStory
                    break
                    continue
            
            questStatus = self.QuestIconNew
            return (questType, questStatus)
        
        if numInProgress:
            questStatus = self.QuestIconProgress
            return (questType, questStatus)
        
        return False

    
    def loadQuestIcons(self):
        if not DistributedQuestGiver.QuestIconWorkTexture:
            DistributedQuestGiver.QuestIconWorkTexture = loader.loadModel('models/gui/new_work_quest_icon')
            DistributedQuestGiver.QuestIconStoryTexture = loader.loadModel('models/gui/new_story_quest_icon')
            discardNP = DistributedQuestGiver.QuestIconStoryTexture.find('**/pPlane2')
            if not discardNP.isEmpty():
                discardNP.removeNode()
            
            gui = loader.loadModel('models/gui/toplevel_gui')
            DistributedQuestGiver.QuestIconProgressTexture = gui.find('**/quest_pending_icon')
            DistributedQuestGiver.QuestIconCompleteTexture = gui.find('**/reward_waiting_icon')
        

    
    def updateNametagQuestIcon(self, questId = None, item = None, note = None):
        offers = self.hasQuestOffersForLocalAvatar()
        if self.nametagIcon:
            self.nametagIcon.removeNode()
        
        if self.nametagIconGlow:
            self.nametagIconGlow.removeNode()
        
        self.loadQuestIcons()
        if offers:
            (type, status) = offers
            if status == DistributedQuestGiver.QuestIconNew:
                if type == DistributedQuestGiver.QuestIconStory:
                    self.nametagIcon = DistributedQuestGiver.QuestIconStoryTexture.copyTo(self.nametag3d)
                else:
                    self.nametagIcon = DistributedQuestGiver.QuestIconStoryTexture.copyTo(self.nametag3d)
                self.nametagIcon.setScale(3.5)
            elif status == DistributedQuestGiver.QuestIconComplete:
                self.nametagIcon = DistributedQuestGiver.QuestIconCompleteTexture.copyTo(self.nametag3d)
                self.nametagIcon.setScale(12)
            elif status == DistributedQuestGiver.QuestIconProgress:
                self.nametagIcon = DistributedQuestGiver.QuestIconProgressTexture.copyTo(self.nametag3d)
                self.nametagIcon.setScale(12)
            else:
                self.notify.error('invalid quest status: %s or type: %s' % (status, type))
        elif self.nametagIcon:
            self.nametagIcon.detachNode()
        
        if self.nametagIconGlow:
            self.nametagIconGlow.detachNode()
        
        if self.nametagIcon:
            self.nametagIcon.setPos(0, 0, 3.5)
            if self.getNameText() is None:
                base.cr.centralLogger.writeClientEvent('NPC %s, %s: has no nameText, type = %s, status = %s!' % (self, self.getName(), type, status))
                if self.nametagIcon:
                    self.nametagIcon.detachNode()
                
                if self.nametagIconGlow:
                    self.nametagIconGlow.detachNode()
                
                return None
            
            self.nametagIcon.reparentTo(self.getNameText())
            self.nametagIcon.setDepthWrite(0)
            if status == DistributedQuestGiver.QuestIconComplete or status == DistributedQuestGiver.QuestIconNew:
                self.nametagIconGlow = loader.loadModel('models/effects/lanternGlow')
                self.nametagIconGlow.reparentTo(self.nametag.getNameIcon())
                self.nametagIconGlow.setScale(20.0)
                self.nametagIconGlow.setColorScaleOff()
                self.nametagIconGlow.setFogOff()
                self.nametagIconGlow.setLightOff()
                self.nametagIconGlow.setPos(0, -0.050000000000000003, 3.0)
                self.nametagIconGlow.setDepthWrite(0)
                self.nametagIconGlow.node().setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OIncomingAlpha, ColorBlendAttrib.OOne))
                self.nametagIconGlow.setColor(0.84999999999999998, 0.84999999999999998, 0.84999999999999998, 0.84999999999999998)
            
        
        self.loadShopCoin()

    
    def forceDoneChatPage(self):
        self._DistributedQuestGiver__handleDoneChatPage(0)
class DistributedQuestGiver(Avatar.Avatar):
    notify = directNotify.newCategory('DistributedQuestGiver')
    NoOffer = 0
    LadderOffer = 1
    QuestOffer = 2
    InteractOffer = 3
    BranchOffer = 4
    QuestIconWorkTexture = None
    QuestIconStoryTexture = None
    QuestIconProgressTexture = None
    QuestIconCompleteTexture = None
    QuestIconDontCare = 1
    QuestIconStory = 2
    QuestIconWork = 3
    QuestIconNew = 1
    QuestIconProgress = 2
    QuestIconComplete = 3

    def __init__(self):
        self.playingQuestString = False
        self.dialogOpen = False
        self.newOffer = False
        self.offers = None
        self.offerType = self.NoOffer
        self.dialogFlag = 0
        self.firstDialog = True
        self.newDialog = False
        self.npcMoviePlayer = None
        self.quitButton = 0
        self.nametagIcon = None
        self.nametagIconGlow = None
        self.containerId = None
        self.dialogAnimSet = None
        self.animationIval = None
        self.resetQuest = None
        self.resetBranch = None
        self.selectedOffer = None
        self.dialogProcessMaster = None
        self.dialogQuestOffer = None


    def generate(self):
        DistributedQuestGiver.notify.debug('generate(%s)' % self.doId)
        self.questMenuGUI = None
        self.questDetailGUI = None
        self.questRewardGUI = None
        self.branchMenuGUI = None
        self.questDetailCamera = None


    def announceGenerate(self):
        DistributedQuestGiver.notify.debug('announceGenerate(%s)' % self.doId)


    def disable(self):
        DistributedQuestGiver.notify.debug('disable(%s)' % self.doId)
        if self.npcMoviePlayer:
            self.npcMoviePlayer.cleanup()
            self.npcMoviePlayer = None

        self.cleanUpQuestMenu()
        self.cleanUpQuestDetails()
        self.cleanUpBranchMenu()
        self.ignore('endDialogNPCInteract')
        self.ignore('lastSubtitlePage')


    def cleanUpQuestMenu(self):
        if self.questMenuGUI:
            self.questMenuGUI.destroy()
            self.questMenuGUI = None



    def cleanUpBranchMenu(self):
        self.resetBranch = None
        self.selectedOffer = None
        if self.branchMenuGUI:
            self.branchMenuGUI.destroy()
            self.branchMenuGUI = None



    def cleanUpQuestDetails(self, hide = False):
        if self.questDetailGUI:
            if hide:
                self.questDetailGUI.hidePanelAndDestroy()
            else:
                self.questDetailGUI.destroy()
            self.questDetailGUI = None

        if self.questRewardGUI:
            if hide:
                self.questRewardGUI.hidePanelAndDestroy()
            else:
                self.questRewardGUI.destroy()
            self.questRewardGUI = None

        if not hide and self.questDetailCamera:
            self.questDetailCamera.finish()
            self.questDetailCamera = None



    def delete(self):
        DistributedQuestGiver.notify.debug('delete(%s)' % self.doId)


    def offerOptions(self):
        self.notify.warning('offerOptions() needs override!')


    def cancelInteraction(self, av):
        self.notify.warning('cancelInteraction() needs override!')


    def hasOpenGUI(self):
        self.notify.warning('hasOpenGUI() needs override!')
        return False


    def hasQuestOffers(self):
        AvailableQuests = []
        inventory = localAvatar.getInventory()
        prereqExcludes = base.config.GetString('exclude-prereq-quests', '')
        for (questId, questDNA) in QuestDB.QuestDict.items():
            if len(prereqExcludes):
                if questId in prereqExcludes:
                    continue


            prereqs = questDNA.getPrereqs()
            passed = True
            for prereq in prereqs:
                if not prereq.giverCanGive(self.getUniqueId()):
                    passed = False
                    break

                if not prereq.avIsReady(localAvatar):
                    passed = False
                    break

                if questDNA.minLevel > localAvatar.level:
                    passed = False
                    break

                if not base.cr.questDependency.checkDependency(questId, localAvatar.getQuestLadderHistory(), 1):
                    passed = False
                    break

                boolWeapLvlCheck = (questDNA.weapLvlType != None) & (questDNA.minWeapLevel > 0)
                if boolWeapLvlCheck & (questDNA.minWeapLevel > getLevelFromTotalReputation(questDNA.weapLvlType, inventory.getReputation(questDNA.weapLvlType))[0]):
                    passed = False
                    break

                if questDNA.getVelvetRoped() and not Freebooter.getPaidStatus(localAvatar.getDoId()):
                    passed = False
                    break

                if questDNA.getAcquireOnce():
                    history = localAvatar.getQuestLadderHistory()
                    questLadderId = base.cr.questDynMap.findQuestLadderInt(questId)
                    containsLadderId = history.count(questLadderId)
                    if containsLadderId:
                        passed = False
                        break


                if questDNA.getHoliday() is not None:
                    holidayId = questDNA.getHoliday()
                    if base.cr.newsManager and not base.cr.newsManager.getHoliday(holidayId):
                        passed = False
                        break

                not base.cr.newsManager.getHoliday(holidayId)

            if prereqs and passed:
                AvailableQuests.append(questDNA)
                continue

        if len(AvailableQuests):
            inventory = localAvatar.getInventory()
            if inventory:
                toRemove = []
                questList = inventory.getQuestList()
                for questDNA in AvailableQuests:
                    questId = questDNA.getQuestId()
                    found = False
                    for quest in questList:
                        if questId == quest.getQuestId() or localAvatar.questStatus.hasLadderQuestId(questId):
                            found = True
                            continue

                    if found:
                        toRemove.append(questDNA)
                        continue

                for questDNA in toRemove:
                    AvailableQuests.remove(questDNA)



        for quest in localAvatar.getQuests():
            if quest and quest.getTimeLimit() and quest.canBeReturnedTo(self.getQuestGiverId()):
                return True
                continue

        return len(AvailableQuests) > 0


    def receiveOffer(self, offerType):
        self.newOffer = True
        self.offerType = offerType


    def clearOffer(self):
        self.newOffer = False
        self.offerType = self.NoOffer


    def displayNewQuests(self):
        self.cleanUpQuestDetails()
        while len(localAvatar.currentStoryQuests) and localAvatar.currentStoryQuests[0].getGiverId() != self.uniqueId:
            if localAvatar.currentStoryQuests[0].getGiverId() == '0':
                break

            localAvatar.currentStoryQuests.remove(localAvatar.currentStoryQuests[0])
        if len(localAvatar.currentStoryQuests):
            storyQuest = localAvatar.currentStoryQuests[0]
            self.presentQuestGiven(storyQuest)
            localAvatar.currentStoryQuests.remove(storyQuest)



    def presentOffer(self):
        if self.newOffer == False:
            while len(localAvatar.currentStoryQuests) and localAvatar.currentStoryQuests[0].getGiverId() != self.uniqueId:
                localAvatar.currentStoryQuests.remove(localAvatar.currentStoryQuests[0])
            if len(localAvatar.currentStoryQuests):
                storyQuest = localAvatar.currentStoryQuests[0]
                self.presentQuestGiven(storyQuest)
                localAvatar.currentStoryQuests.remove(storyQuest)

            return None

        if self.offerType == self.QuestOffer:
            self.presentQuestOffer(self.offers)
        elif self.offerType == self.LadderOffer:
            self.presentQuestOffer(self.offers, ladder = True)
        elif self.offerType == self.InteractOffer:
            self.offerOptions(self.dialogFlag)
        elif self.offerType == self.NoOffer:
            self.notify.warning('offerType == No Offer')

        self.clearOffer()


    def setQuestOffer(self, offers):
        self.receiveOffer(self.QuestOffer)
        self.offers = offers
        for quest in localAvatar.getQuests():
            if quest.getTimeLimit() and quest.canBeReturnedTo(self.getQuestGiverId()):
                questOffer = QuestOffer.QuestTimerResetOffer.create(quest.getQuestId(), localAvatar, timerReset = True)
                offers.append(questOffer)

            branchParent = quest.getBranchParent(localAvatar)
            if branchParent and branchParent.getGiverId() == self.getQuestGiverId():
                questOffer = QuestOffer.QuestBranchResetOffer.create(quest.getQuestId(), localAvatar, branchReset = True)
                offers.append(questOffer)
                continue

        if not self.playingQuestString:
            self.presentQuestOffer(self.offers)



    def setQuestLadderOffer(self, offers, quitButton):
        self.receiveOffer(self.LadderOffer)
        self.offers = offers
        self.quitButton = quitButton
        if not self.playingQuestString:
            self.presentQuestOffer(self.offers, ladder = True)



    def presentQuestOffer(self, offers, ladder = False):
        if self.questMenuGUI:
            DistributedQuestGiver.notify.warning('setQuestOffer: old questMenu GUI still around')
            self.cleanUpQuestMenu()

        self.cleanUpQuestDetails()

        def handleSelection(offer, self = self, offers = offers):
            self.cleanUpQuestMenu()
            if offer == QuestConstants.CANCEL_QUEST:
                index = QuestConstants.CANCEL_QUEST
            else:
                index = offers.index(offer)
            self.sendOfferResponse(index, ladder)


        def handleOption(option, offer):
            base.test = self
            self.ignore('lastSubtitlePage')
            self.adjustNPCCamera('back')
            if option == PLocalizer.Accept:
                handleSelection(offer)
            elif self.questMenuGUI:
                self.questMenuGUI.show()

            self.cleanUpQuestDetails(hide = True)


        def displayQuestDetails(offer):
            self.questDetailGUI = QuestDetailGUI(offer, None)
            self.questDetailGUI.showPanel()
            base.questdet = self.questDetailGUI


        def displayBranchDetails(offer):
            self.selectedOffer = offer
            self.cleanUpQuestDetails()
            self.questDetailGUI = QuestDetailGUI(offer, None)
            self.questDetailGUI.showPanel()
            base.questdet = self.questDetailGUI


        def displayBranchOptions(offer, callback, descCallback):
            self.branchMenuGUI = BranchMenuGUI.BranchMenuGUI(offer, callback, descCallback)


        def handleBranchOption(option):
            if option == PLocalizer.Accept:
                if self.selectedOffer:
                    self.sendOfferResponse(0, ladder, self.selectedOffer)


            self.adjustNPCCamera('back')
            self.cleanUpQuestDetails(hide = True)
            self.cleanUpBranchMenu()
            if self.questMenuGUI:
                self.questMenuGUI.show()



        def describeQuest(offer):
            self.adjustNPCCamera('forward')
            questDNA = offer.getQuestDNA()
            if questDNA:
                if isinstance(offer, QuestOffer.QuestTimerResetOffer):
                    self.requestQuestReset(offer.getQuestId())
                    return None
                elif isinstance(offer, QuestOffer.QuestBranchResetOffer):
                    self.requestBranchReset(offer.getQuestId())
                    return None

                questStr = questDNA.getStringBefore()
                if questDNA.isBranch():
                    self.acceptOnce('lastSubtitlePage', displayBranchOptions, [
                        offer,
                        None,
                        displayBranchDetails])
                    localAvatar.guiMgr.subtitler.setPageChat(questStr, options = [
                        PLocalizer.Decline,
                        PLocalizer.Accept], callback = handleBranchOption)
                else:
                    self.acceptOnce('lastSubtitlePage', displayQuestDetails, [
                        offer])
                    localAvatar.guiMgr.subtitler.setPageChat(questStr, options = [
                        PLocalizer.Decline,
                        PLocalizer.Accept], callback = handleOption, extraArgs = [
                        offer])



        def questFull(arg):
            self.cleanUpQuestMenu()
            self.sendOfferResponse(QuestConstants.CANCEL_QUEST, ladder)

        inv = base.localAvatar.getInventory()
        numWorkQuests = 0
        if inv:
            questList = inv.getQuestList()
            for questId in questList:
                if not QuestLadderDB.getFamePath(questId):
                    numWorkQuests += 1
                    continue


        hasStoryQuest = False
        for offer in offers:
            if QuestLadderDB.getFamePath(offer.getQuestId()):
                hasStoryQuest = True
                continue

        if not hasStoryQuest and numWorkQuests > QuestConstants.MAXIMUM_MERC_WORK:
            self.questMenuGUI = PDialog.PDialog(text = PLocalizer.QuestFull, style = OTPDialog.Acknowledge, command = questFull)
        else:
            self.questMenuGUI = QuestMenuGUI.QuestMenuGUI(offers, handleSelection, describeQuest)
        localAvatar.currentStoryQuests = []
        self.clearOffer()


    def presentBranchReset(self, declineOption = True):
        if not self.resetBranch:
            return None


        def displayBranchOptions(offer, callback, descCallback):
            self.branchMenuGUI = BranchMenuGUI.BranchMenuGUI(offer, callback, descCallback)


        def displayBranchDetails(offer):
            self.selectedOffer = offer
            self.cleanUpQuestDetails()
            self.questDetailGUI = QuestDetailGUI(offer, None)
            self.questDetailGUI.showPanel()
            base.questdet = self.questDetailGUI
            subtitleOptions = [
                PLocalizer.Accept]
            if declineOption:
                subtitleOptions = [
                    PLocalizer.Decline,
                    PLocalizer.Accept]

            localAvatar.guiMgr.subtitler.setPageChat('Is that your choice?', options = subtitleOptions, callback = handleBranchOption)


        def handleBranchOption(option):
            if option == PLocalizer.Accept:
                if self.selectedOffer:
                    self.sendOfferResponse(0, offer = self.selectedOffer)

            else:
                self.offerOptions(False)
            self.adjustNPCCamera('back')
            self.cleanUpQuestDetails(hide = True)
            self.cleanUpBranchMenu()
            self.cleanUpQuestMenu()

        offer = QuestOffer.QuestOffer.create(self.resetBranch.getName(), localAvatar)
        if declineOption:
            subtitleOptions = [
                PLocalizer.Decline]
            self.acceptOnce('lastSubtitlePage', displayBranchOptions, [
                offer,
                None,
                displayBranchDetails])
            localAvatar.guiMgr.subtitler.setPageChat('', options = subtitleOptions, callback = handleBranchOption)
        else:
            subtitleOptions = []
            displayBranchOptions(offer, None, displayBranchDetails)
        self.ignore('doneChatPage')


    def presentQuestReset(self):
        if not self.resetQuest:
            return None


        def handleOption(option):
            if option == PLocalizer.Accept:
                self.resetQuest.startTimer()

            self.resetQuest = None
            self._DistributedQuestGiver__handleDoneChatPage(0)

        self.questDetailGUI = QuestDetailGUI(None, None, self.resetQuest.questDNA)
        self.questDetailGUI.showPanel()
        localAvatar.guiMgr.subtitler.setPageChat('', options = [
            PLocalizer.Accept], callback = handleOption)


    def presentQuestGiven(self, quest):
        self.resetBranch = None
        if self.resetBranch:
            container = localAvatar.questStatus.getContainer(quest.getQuestId())
            if container.parent and container.parent.getFirstQuestId() == quest.getQuestId():
                self.presentBranchReset(False)
                return None
            else:
                self.resetBranch = None


        def handleOption(option):
            if len(localAvatar.currentStoryQuests):
                self.cleanUpQuestDetails(hide = True)
                while len(localAvatar.currentStoryQuests) and localAvatar.currentStoryQuests[0].getGiverId() != self.uniqueId:
                    localAvatar.currentStoryQuests.remove(localAvatar.currentStoryQuests[0])

            if len(localAvatar.currentStoryQuests):
                storyQuest = localAvatar.currentStoryQuests[0]
                self.presentQuestGiven(storyQuest)
                localAvatar.currentStoryQuests.remove(storyQuest)
            elif hasattr(quest, 'questDNA') and quest.questDNA.getTimeLimit():
                quest.startTimer()

            self._DistributedQuestGiver__handleDoneChatPage(0)

        self.questDetailGUI = QuestDetailGUI(None, None, quest)
        self.questDetailGUI.showPanel()
        localAvatar.guiMgr.subtitler.setPageChat('', options = [
            PLocalizer.Accept], callback = handleOption)
        base.questdet = self.questDetailGUI
        self.ignore('doneChatPage')


    def adjustNPCCamera(self, direction):
        dummy = NodePath('dummy')
        dummy.reparentTo(camera)
        if direction == 'forward':
            dummy.setH(dummy, -15)
            dummy.setY(dummy, 0.75)
            duration = 0.69999999999999996
        else:
            dummy.setY(dummy, -0.75)
            dummy.setH(dummy, 15)
            duration = 0.5
        dummy.wrtReparentTo(camera.getParent())
        (camH, dummyH) = getShortestRotation(camera.getH(), dummy.getH())
        self.questDetailCamera = Parallel(LerpFunc(camera.setH, duration = duration, fromData = camH, toData = dummyH, blendType = 'easeInOut'), LerpFunc(camera.setY, duration = duration, fromData = camera.getY(), toData = dummy.getY(), blendType = 'easeInOut'))
        dummy.removeNode()
        self.questDetailCamera.start()


    def getOfferedQuests(self):
        return list(self.offers)


    def sendOfferResponse(self, index, ladder = False, offer = None):
        if index == QuestConstants.CANCEL_QUEST:
            self.dialogOpen = False

        if offer:
            self.sendUpdate('assignBranchOffer', [
                offer])
        else:
            self.sendUpdate('setOfferResponse', [
                index,
                ladder])
        self.offers = None
        self.clearOffer()


    def b_setPageNumber(self, paragraph, pageNumber):
        self.setPageNumber(paragraph, pageNumber)
        self.d_setPageNumber(paragraph, pageNumber)


    def d_setPageNumber(self, paragraph, pageNumber):
        pass


    def playQuestString(self, questStr, timeout = False, quitButton = 1, useChatBubble = False, confirm = False, animSet = None):
        self.notify.debug('playQuestString %s, %s, %s, %s' % (timeout, quitButton, useChatBubble, confirm))
        if questStr.find('quest_') == 0:
            nmp = QuestParser.NPCMoviePlayer(questStr, localAvatar, self)
            nmp.play()
            self.npcMoviePlayer = nmp
        else:
            self.firstDialog = False
            self.dialogAnimSet = animSet
            if questStr:
                if timeout:
                    if useChatBubble:
                        self.setPageChat(localAvatar.doId, 0, questStr, 0, extraChatFlags = CFSpeech | CFTimeout, pageButton = False)
                    else:
                        base.localAvatar.guiMgr.subtitler.setPageChat(questStr, timeout = timeout)
                    return None
                else:
                    self.playingQuestString = True
                    base.localAvatar.guiMgr.subtitler.setPageChat(questStr, confirm = confirm)
                    self.dialogOpen = True
                self.playAnimation(0)
                if quitButton == 1 or confirm:
                    self.accept('doneChatPage', self._DistributedQuestGiver__handleDoneChatPage)

                if base.localAvatar.guiMgr.subtitler.getNumChatPages() == 1:
                    self._DistributedQuestGiver__handleNextChatPage(0, 0)
                else:
                    self.accept('nextChatPage', self._DistributedQuestGiver__handleNextChatPage)



    def _DistributedQuestGiver__handleNextChatPage(self, pageNumber, elapsed):
        self.notify.debug('handleNextChatPage pageNumber = %s, elapsed = %s' % (pageNumber, elapsed))
        if pageNumber == base.localAvatar.guiMgr.subtitler.getNumChatPages() - 1:
            self.ignore('nextChatPage')
            self.playingQuestString = False
            self.presentBranchReset()
            self.presentQuestReset()
            self.presentOffer()

        self.playAnimation(pageNumber)


    def _DistributedQuestGiver__handleDoneChatPage(self, elapsed):
        self.ignore('nextChatPage')
        self.ignore('doneChatPage')
        self.playingQuestString = False
        self.dialogOpen = False
        if self.newDialog:
            self.playDialog()

        if not self.hasOpenGUI():
            self.interactMode = 1
            self.cancelInteraction(base.localAvatar)

        self.cancelInteraction(base.localAvatar)


    def playAnimation(self, index):
        if self.animationIval:
            self.animationIval.finish()
            self.animationIval = None

        if self.dialogAnimSet:
            if len(self.dialogAnimSet) > index and self.dialogAnimSet[index]:
                self.animationIval = Sequence(Wait(0.5), Func(self.gameFSM.request, 'Emote'), Func(self.playEmote, self.dialogAnimSet[index]))
                self.animationIval.start()




    def playDialog(self):
        self.notify.warning('playDialog() needs override!')


    def setQuestsCompleted(self, menuFlag, completedContainerIds, completedChainedQuestIds, completedQuestIds, completedQuestDoIds):
        questStr = ''
        self.cleanUpQuestDetails()

        def handleOption(option, questStr, menuFlag, confirm, animSet):
            self.cleanUpQuestDetails(hide = True)
            self.playQuestString(questStr, quitButton = menuFlag, confirm = True, animSet = animSet)

        if len(completedContainerIds):
            if completedContainerIds[0] in [
                'c3visitJack']:
                return None

            if len(completedContainerIds) > 1:
                self.notify.warning('Multiple simultaneous completed quest containers for the same NPC: %s!' % completedContainerIds)

            containerId = completedContainerIds[0]
            self.containerId = containerId
            container = QuestLadderDB.getContainer(containerId)
            if container:
                dialogId = container.getDialogAfter()
                if dialogId:
                    self.requestDialog(dialogId)
                    return None

                questStr = container.getStringAfter()
                animSet = container.getAnimSetAfter()
                localAvatar.b_setGameState('NPCInteract', localArgs = [
                    self,
                    False,
                    False])
                if hasattr(self, '_questRewardsEarned'):
                    self.questRewardGUI = QuestRewardGUI(container, self._questRewardsEarned)
                    localAvatar.guiMgr.subtitler.setPageChat('', options = [
                        PLocalizer.Continue], callback = handleOption, extraArgs = [
                        questStr,
                        menuFlag,
                        True,
                        animSet])
                else:
                    handleOption(questStr, menuFlag, True, animSet)
                return None
            else:
                self.notify.warning('%s not in QuestLadderDB!' % containerId)

        if len(completedChainedQuestIds):
            pass
        1
        if len(completedQuestIds):
            if len(completedContainerIds) == 0:
                questId = completedQuestIds[0]
                quest = QuestDB.QuestDict.get(questId)
                if quest:
                    questStr = quest.getStringAfter()
                    animSet = quest.getAnimSetAfter()
                    self.notify.debug('%s stringAfter: %s' % (questId, questStr))
                    if hasattr(self, '_questRewardsEarned'):
                        print 'GOT questRewardsEarned: %s' % self._questRewardsEarned
                        self.questRewardGUI = QuestRewardGUI(quest, self._questRewardsEarned)
                        localAvatar.guiMgr.subtitler.setPageChat('', options = [
                            PLocalizer.Continue], callback = handleOption, extraArgs = [
                            questStr,
                            menuFlag,
                            True,
                            animSet])
                    else:
                        handleOption(questStr, menuFlag, True, animSet)
                else:
                    self.notify.warning('%s not in QuestDB!' % questId)

            localAvatar.b_setGameState('NPCInteract', localArgs = [
                self,
                True,
                False])

        if len(completedQuestIds) == 0 and len(completedChainedQuestIds) == 0 and len(completedContainerIds) == 0:
            if not self.hasOpenGUI():
                self.cancelInteraction(base.localAvatar)




    def requestQuestReset(self, questId):
        self.resetQuest = localAvatar.getQuestById(questId)
        if self.resetQuest:
            questStr = self.resetQuest.questDNA.getStringBefore()
            self.cleanUpQuestDetails(hide = True)
            self.playQuestString(questStr, quitButton = True, confirm = True)
            localAvatar.b_setGameState('NPCInteract', localArgs = [
                self,
                True,
                False])



    def requestBranchReset(self, questId):
        quest = localAvatar.getQuestById(questId)
        self.resetBranch = quest.getBranchParent(localAvatar)
        resetBranchDNA = QuestLadderDB.getContainer(self.resetBranch.getQuestId())
        questStr = resetBranchDNA.getStringBefore()
        self.cleanUpQuestDetails(hide = True)
        self.playQuestString(questStr, quitButton = False, confirm = True)
        localAvatar.b_setGameState('NPCInteract', localArgs = [
            self,
            True,
            False])


    def requestDialog(self, dialogId = None):
        self.endDialog()
        if not dialogId:
            availableDialogs = []
            npcDialogs = DialogDict.get(self.getUniqueId())
            if npcDialogs:
                for dialogId in npcDialogs:
                    firstDialogProcess = npcDialogs.get(dialogId).get(0)[0]
                    if firstDialogProcess.prereq and firstDialogProcess.avCanParticipate(localAvatar):
                        availableDialogs.append(dialogId)
                        continue


        else:
            availableDialogs = [
                dialogId]
        localAvatar.b_setGameState('NPCInteract', localArgs = [
            self,
            True,
            True])
        self.accept('endDialogNPCInteract', self.endDialog)
        self.dialogProcessMaster = DialogProcessMaster(self, availableDialogs)
        taskMgr.doMethodLater(0.25, self.startDialog, 'startDialogProcessMaster')


    def startDialog(self, task = None):
        if self.dialogProcessMaster:
            self.dialogProcessMaster.start()



    def endDialog(self):
        taskMgr.remove('startDialogProcessMaster')
        self.ignore('endDialogNPCInteract')
        if self.dialogProcessMaster:
            self.dialogProcessMaster.stop()
            self.dialogProcessMaster = None



    def requestDialogInteraction(self, dialogId):
        self.sendUpdate('requestDialogInteraction', [
            dialogId])


    def endDialogInteraction(self, dialogId):
        self.sendUpdate('endDialogInteraction', [
            dialogId])


    def requestDialogQuestAdvancement(self, questId, dialogId):
        self.sendUpdate('requestDialogQuestAdvancement', [
            questId,
            dialogId])


    def requestDialogQuestAssignment(self, questId, dialogId):
        self.sendUpdate('requestDialogQuestAssignment', [
            questId,
            dialogId])


    def requestDialogQuestOffer(self, questId, dialogId):
        self.sendUpdate('requestDialogQuestOffer', [
            questId,
            dialogId])


    def setDialogQuestOffer(self, questOffer):
        self.dialogQuestOffer = questOffer
        messenger.send('setDialogQuestOffer')


    def showDialogQuestOffer(self):
        if self.dialogQuestOffer:
            self.questDetailGUI = QuestDetailGUI(self.dialogQuestOffer, None)
            self.questDetailGUI.showPanel()



    def assignDialogQuestOffer(self):
        if self.dialogQuestOffer:
            self.sendUpdate('assignDialogQuestOffer')



    def showQuestRewards(self):
        if hasattr(self, '_questRewardsEarned') and self.containerId:
            container = QuestLadderDB.getContainer(self.containerId)
            self.questRewardGUI = QuestRewardGUI(container, self._questRewardsEarned)



    def hideQuestRewards(self):
        if self.questRewardGUI:
            self.questRewardGUI.destroy()
            self.questRewardGUI = None



    def requestNPCHostile(self, npcId, dialogId):
        self.sendUpdate('requestNPCHostile', [
            npcId,
            dialogId])


    def playDialogMovie(self, dialogId, doneCallback = None, oldLocalAvState = None):
        movieChoice = InteractGlobals.getNPCTutorial(dialogId)
        if movieChoice == None:
            movieChoice = dialogId

        globalClock.tick()
        self.currentDialogMovie = QuestParser.NPCMoviePlayer(movieChoice, localAvatar, self)
        self.currentDialogMovie.overrideOldAvState(oldLocalAvState)
        self.currentDialogMovie.play()
        self.acceptOnce('dialogFinish', self.stopDialogMovie, extraArgs = [
            doneCallback])


    def stopDialogMovie(self, doneCallback):
        if hasattr(self, 'currentDialogMovie'):
            self.currentDialogMovie.npc.showName()
            self.currentDialogMovie.npc.nametag3d.setZ(0)
            self.currentDialogMovie.finishUpAll()
            del self.currentDialogMovie
            self.sendUpdate('dialogMovieComplete')
            if doneCallback:
                doneCallback()




    def swapCurrentDialogMovie(self, newDialogMovie):
        if hasattr(self, 'currentDialogMovie'):
            if newDialogMovie:
                oldAvState = self.currentDialogMovie.overrideOldAvState(None)
                newDialogMovie.overrideOldAvState(oldAvState)

            self.currentDialogMovie.finishUpAll()

        self.currentDialogMovie = newDialogMovie


    def getQuestGiverId(self):
        return self.getUniqueId()


    def hasQuestOffersForLocalAvatar(self):
        av = localAvatar
        inventory = av.getInventory()
        selfId = self.getQuestGiverId()
        if inventory:
            numInProgress = 0
            for quest in inventory.getQuestList():
                questType = self.QuestIconDontCare
                if quest.tasks is None:
                    self.notify.warning('quest %s: does not contain a dna; potential for crash.' % quest.getQuestId())
                    return False

                for (task, taskState) in zip(quest.tasks, quest.taskStates):
                    if isinstance(task, QuestTaskDNA.VisitTaskDNA):
                        if task.npcId == selfId:
                            questStatus = self.QuestIconComplete
                            return (questType, questStatus)

                    task.npcId == selfId

                if quest.canBeReturnedTo(selfId):
                    isComplete = False
                    if quest.isComplete():
                        container = localAvatar.questStatus.getContainer(quest.getQuestId())
                        if container and container.parent and container.parent.isChoice():
                            isComplete = True
                            for q in container.parent.getContainers():
                                if q.quest and not q.quest.isComplete():
                                    isComplete = False
                                    continue

                        else:
                            isComplete = True

                    if isComplete:
                        questStatus = self.QuestIconComplete
                        return (questType, questStatus)
                    else:
                        numInProgress += 1

        else:
            self.notify.warning('avatar does not have inventory yet')
            return False
        offerDict = { }
        fromQuests = []
        prereqExcludes = base.config.GetString('exclude-prereq-quests', '')
        for (questId, questDNA) in QuestDB.QuestDict.items():
            if prereqExcludes and questId in prereqExcludes:
                continue

            passed = True
            for prereq in questDNA.prereqs:
                if not prereq.giverCanGive(selfId):
                    passed = False
                    break

                if not prereq.avIsReady(localAvatar):
                    passed = False
                    break

                if questDNA.minLevel > localAvatar.level:
                    passed = False
                    break

                if not base.cr.questDependency.checkDependency(questId, localAvatar.getQuestLadderHistory(), 1):
                    passed = False
                    break

                boolWeapLvlCheck = (questDNA.weapLvlType != None) & (questDNA.minWeapLevel > 0)
                if boolWeapLvlCheck & (questDNA.minWeapLevel > getLevelFromTotalReputation(questDNA.weapLvlType, inventory.getReputation(questDNA.weapLvlType))[0]):
                    passed = False
                    break

                if questDNA.getAcquireOnce():
                    history = localAvatar.getQuestLadderHistory()
                    questLadderId = base.cr.questDynMap.findQuestLadderInt(questId)
                    containsLadderId = history.count(questLadderId)
                    if containsLadderId:
                        passed = False
                        break


                if questDNA.getHoliday() is not None:
                    holidayId = questDNA.getHoliday()
                    if base.cr.newsManager and not base.cr.newsManager.getHoliday(holidayId):
                        passed = False
                        break

                not base.cr.newsManager.getHoliday(holidayId)

            if questDNA.prereqs and passed:
                fromQuests.append(questDNA)
                continue

        if len(fromQuests):
            inventory = av.getInventory()
            if inventory:
                questsLeft = []
                questList = inventory.getQuestList()
                for questDNA in fromQuests:
                    questId = questDNA.questId
                    if not av.questStatus.hasLadderQuestId(questId):
                        continue
                        if _[1] not in [ x.questId for x in questList ]:
                            questsLeft.append(questDNA)
                            continue
                    []

                fromQuests = questsLeft


        if fromQuests:
            questType = self.QuestIconWork
            for quest in fromQuests:
                if QuestLadderDB.getFamePath(quest.questId):
                    questType = self.QuestIconStory
                    break
                    continue

            questStatus = self.QuestIconNew
            return (questType, questStatus)

        if numInProgress:
            questStatus = self.QuestIconProgress
            return (questType, questStatus)

        return False


    def loadQuestIcons(self):
        if not DistributedQuestGiver.QuestIconWorkTexture:
            DistributedQuestGiver.QuestIconWorkTexture = loader.loadModel('models/gui/new_work_quest_icon')
            DistributedQuestGiver.QuestIconStoryTexture = loader.loadModel('models/gui/new_story_quest_icon')
            discardNP = DistributedQuestGiver.QuestIconStoryTexture.find('**/pPlane2')
            if not discardNP.isEmpty():
                discardNP.removeNode()

            gui = loader.loadModel('models/gui/toplevel_gui')
            DistributedQuestGiver.QuestIconProgressTexture = gui.find('**/quest_pending_icon')
            DistributedQuestGiver.QuestIconCompleteTexture = gui.find('**/reward_waiting_icon')



    def updateNametagQuestIcon(self, questId = None, item = None, note = None):
        offers = self.hasQuestOffersForLocalAvatar()
        if self.nametagIcon:
            self.nametagIcon.removeNode()

        if self.nametagIconGlow:
            self.nametagIconGlow.removeNode()

        self.loadQuestIcons()
        if offers:
            (type, status) = offers
            if status == DistributedQuestGiver.QuestIconNew:
                if type == DistributedQuestGiver.QuestIconStory:
                    self.nametagIcon = DistributedQuestGiver.QuestIconStoryTexture.copyTo(self.nametag3d)
                else:
                    self.nametagIcon = DistributedQuestGiver.QuestIconStoryTexture.copyTo(self.nametag3d)
                self.nametagIcon.setScale(3.5)
            elif status == DistributedQuestGiver.QuestIconComplete:
                self.nametagIcon = DistributedQuestGiver.QuestIconCompleteTexture.copyTo(self.nametag3d)
                self.nametagIcon.setScale(12)
            elif status == DistributedQuestGiver.QuestIconProgress:
                self.nametagIcon = DistributedQuestGiver.QuestIconProgressTexture.copyTo(self.nametag3d)
                self.nametagIcon.setScale(12)
            else:
                self.notify.error('invalid quest status: %s or type: %s' % (status, type))
        elif self.nametagIcon:
            self.nametagIcon.detachNode()

        if self.nametagIconGlow:
            self.nametagIconGlow.detachNode()

        if self.nametagIcon:
            self.nametagIcon.setPos(0, 0, 3.5)
            if self.getNameText() is None:
                base.cr.centralLogger.writeClientEvent('NPC %s, %s: has no nameText, type = %s, status = %s!' % (self, self.getName(), type, status))
                if self.nametagIcon:
                    self.nametagIcon.detachNode()

                if self.nametagIconGlow:
                    self.nametagIconGlow.detachNode()

                return None

            self.nametagIcon.reparentTo(self.getNameText())
            self.nametagIcon.setDepthWrite(0)
            if status == DistributedQuestGiver.QuestIconComplete or status == DistributedQuestGiver.QuestIconNew:
                self.nametagIconGlow = loader.loadModel('models/effects/lanternGlow')
                self.nametagIconGlow.reparentTo(self.nametag.getNameIcon())
                self.nametagIconGlow.setScale(20.0)
                self.nametagIconGlow.setColorScaleOff()
                self.nametagIconGlow.setFogOff()
                self.nametagIconGlow.setLightOff()
                self.nametagIconGlow.setPos(0, -0.050000000000000003, 3.0)
                self.nametagIconGlow.setDepthWrite(0)
                self.nametagIconGlow.node().setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OIncomingAlpha, ColorBlendAttrib.OOne))
                self.nametagIconGlow.setColor(0.84999999999999998, 0.84999999999999998, 0.84999999999999998, 0.84999999999999998)


        self.loadShopCoin()


    def forceDoneChatPage(self):
        self._DistributedQuestGiver__handleDoneChatPage(0)