Esempio n. 1
0
class WaveGUI(NodePath):
    def __init__(self):
        NodePath.__init__(self, 'wave-gui')
        self.reparentTo(base.a2dBottomCenter)
        self.setBin('fixed', 60)
        self.setTransparency(True, 1)
        self.setAlphaScale(0.75, 1)
        self.setZ(0.1)
        self.frame = DirectFrame(image='materials/ui/wave_ui_base.png',
                                 parent=self,
                                 relief=None,
                                 image_scale=(.373, 1, .094))
        self.waveText = OnscreenText(text="Wave 4",
                                     pos=(0, 0.0175, 0),
                                     scale=0.06,
                                     parent=self.frame)
        self.progress = DirectWaitBar(scale=(.324, 1, .3),
                                      relief=None,
                                      barColor=(1, 0.75, 0, 1),
                                      parent=self.frame,
                                      pos=(0, 0, -0.0293))
        self.progress.setBin('fixed', 61)
        self.progress['range'] = 50
        self.progress['value'] = 35
        self.progressText = OnscreenText(text=str(self.progress['value']) +
                                         " / " + str(self.progress['range']),
                                         scale=0.04,
                                         parent=self.frame,
                                         pos=(0, -0.04, 0))
        self.progressText.setBin('fixed', 62)
        self.hide()

    def doHide(self):
        Sequence(
            LerpColorScaleInterval(self,
                                   1.0, (1, 1, 1, 0), (1, 1, 1, 0.75),
                                   override=1), Func(self.hide)).start()

    def doShow(self):
        Sequence(
            Func(self.show),
            LerpColorScaleInterval(self,
                                   1.0, (1, 1, 1, 0.75), (1, 1, 1, 0),
                                   override=1)).start()

    def incProgress(self):
        self.adjustProgress(self.progress['value'] + 1)

    def adjustForWave(self, waveNum, suits):
        self.waveText['text'] = "Wave {0}".format(waveNum)
        self.progress['range'] = suits
        self.adjustProgress(0)

    def adjustProgress(self, progress):
        self.progress['value'] = progress
        self.progressText['text'] = str(self.progress['value']) + " / " + str(
            self.progress['range'])
class ToonPanel(DirectFrame):
    notify = directNotify.newCategory("ToonPanel")

    animal2HeadData = {
        'dog': (0.125, 0.04),
        'duck': (0.1, 0.025),
        'cat': (0.115, 0.04),
        'rabbit': (0.115, 0.04),
        'horse': (0.115, 0.06),
        'monkey': (0.115, 0.06),
        'pig': (0.115, 0.07),
        'mouse': (0.09, 0.02),
        'bear': (0.125, 0.05)
    }

    State2Text = {
        'status': ('Seeing if %s is available...',
                   '%s is busy right now; try again later.'),
        'teleport': ('Trying to go to %s...', 'Could not go to %s.'),
        'friend': ('Asking %s to be your friend...', '%s said no, thank you.',
                   'You are now friends with %s!'),
        'remove':
        ('Are you sure you want to remove %s from your friends list?',
         '%s left your friends list.')
    }

    def __init__(self):
        DirectFrame.__init__(self, scale=1.2)
        self['image'] = DGG.getDefaultDialogGeom()
        self['image_hpr'] = (0, 0, -90)
        self['image_scale'] = (0.67, 0.9, 0.325)
        self['image_color'] = (1, 1, 0.75, 1)
        self['image_pos'] = (0, 0, -0.09)
        self['relief'] = None
        self.reparentTo(base.a2dTopRight)
        self.setPos(-0.235, 0.0, -0.325)
        self.hide()
        self.head = None
        self.laffMeter = None
        self.exitButton = None
        self.friendButton = None
        self.teleportButton = None
        self.whisperButton = None
        self.nameText = None
        self.actionFrame = None
        self.actionFrameText = None
        self.actionFrameButton = None
        self.actionFrameButton2 = None
        self.avatarInfo = None
        self.action = None
        self.locationText = None
        self.shardText = None
        self.detailsExitBtn = None

        self.fsm = ClassicFSM.ClassicFSM('ToonPanel', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('waitOnAvatarInfoResponse',
                        self.enterWaitOnAvatarInfoResponse,
                        self.exitWaitOnAvatarInfoResponse, ['panel']),
            State.State('panel', self.enterPanel, self.exitPanel, ['off'])
        ], 'off', 'off')
        self.fsm.enterInitialState()

        self.actionFSM = ClassicFSM.ClassicFSM('ToonPanelActionFSM', [
            State.State('off', self.enterOff, self.exitOff),
            State.State(
                'waitOnAvatarStatusResponse',
                self.enterWaitOnAvatarStatusResponse,
                self.exitWaitOnAvatarStatusResponse, [
                    'waitOnAvatarTeleportResponse',
                    'waitOnAvatarFriendListResponse', 'avatarBusy', 'off'
                ]),
            State.State('avatarBusy', self.enterAvatarBusy,
                        self.exitAvatarBusy, ['off']),
            State.State('waitOnAvatarTeleportResponse',
                        self.enterWaitOnAvatarTeleportResponse,
                        self.exitWaitOnAvatarTeleportResponse, ['unableToTP']),
            State.State('unableToTP', self.enterUnableToTP,
                        self.exitUnableToTP, ['off']),
            State.State('waitOnAvatarFriendListResponse',
                        self.enterWaitOnAvatarFriendListResponse,
                        self.exitWaitOnAvatarFriendListResponse,
                        ['fRequestA', 'fRequestR']),
            State.State('fRequestA', self.enterFriendRequestAccepted,
                        self.exitFriendRequestAccepted, ['off']),
            State.State('fRequestR', self.enterFriendRequestRejected,
                        self.exitFriendRequestRejected, ['off']),
            State.State('removeFriendConfirm', self.enterRemoveFriendConfirm,
                        self.exitRemoveFriendConfirm,
                        ['off', 'removedFriend']),
            State.State('removedFriend', self.enterRemovedFriend,
                        self.exitRemovedFriend, ['off'])
        ], 'off', 'off')
        self.actionFSM.enterInitialState()

    def makeMoreDetailsPanel(self):
        self.actionFSM.request('off')
        self.removeMoreDetailsPanel()
        self.removeActionPanel()
        self.makeActionPanel()
        zoneId = self.avatarInfo[5]
        shardId = self.avatarInfo[6]
        isOnline = self.avatarInfo[7]
        shardName = 'Unknown District'
        hoodName = ZoneUtil.getHoodId(zoneId, 1)
        for district in base.cr.activeDistricts.values():
            if district.doId == shardId:
                shardName = district.getDistrictName()
                break
        if not isOnline:
            hoodName = 'Offline'
            shardName = 'Offline'
        self.locationText = OnscreenText('Location: {0}'.format(hoodName),
                                         parent=self.actionFrame,
                                         pos=(-0.3, 0.05, 0),
                                         align=TextNode.ALeft,
                                         scale=0.04)
        self.shardText = OnscreenText('District: {0}'.format(shardName),
                                      parent=self.actionFrame,
                                      pos=(-0.3, 0.0, 0),
                                      align=TextNode.ALeft,
                                      scale=0.04)
        self.detailsExitBtn = DirectButton(geom=CIGlobals.getCancelBtnGeom(),
                                           parent=self.actionFrame,
                                           relief=None,
                                           scale=0.8,
                                           pos=(-0.3, 0.0, -0.175),
                                           command=self.removeMoreDetailsPanel)

    def removeMoreDetailsPanel(self):
        if self.locationText:
            self.locationText.destroy()
            self.locationText = None
        if self.shardText:
            self.shardText.destroy()
            self.shardText = None
        if self.detailsExitBtn:
            self.detailsExitBtn.destroy()
            self.detailsExitBtn = None
        self.removeActionPanel()

    def maybeUpdateFriendButton(self):
        if self.friendButton:
            if self.avatarInfo:
                if not self.avatarInfo[0] in base.localAvatar.friends:
                    self.friendButton['text'] = 'Add Friend'
                    self.friendButton['extraArgs'] = [
                        'waitOnAvatarFriendListResponse'
                    ]
                else:
                    self.friendButton['text'] = 'Remove Friend'
                    self.friendButton['extraArgs'] = ['removeFriendConfirm']

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterUnableToTP(self):
        pass

    def exitUnableToTP(self):
        pass

    def enterWaitOnAvatarTeleportResponse(self):
        self.setActionText(self.State2Text['teleport'][0] %
                           self.getAvatarName())
        self.makeButtons('Cancel')
        self.acceptOnce('gotAvatarTeleportResponse',
                        self.handleTeleportResponse)
        base.cr.friendsManager.d_iWantToTeleportToAvatar(self.avatarInfo[0])

    def handleTeleportResponse(self, avatarId, shardId, zoneId):
        if self.avatarInfo[0] == avatarId:
            requestStatus = {}
            whereName = ZoneUtil.getWhereName(zoneId)
            loaderName = ZoneUtil.getLoaderName(zoneId)
            requestStatus['zoneId'] = zoneId
            if base.localAvatar.parentId == shardId:
                requestStatus['shardId'] = None
            else:
                requestStatus['shardId'] = shardId
            requestStatus['hoodId'] = ZoneUtil.getHoodId(zoneId, 1)
            requestStatus['where'] = whereName
            requestStatus['loader'] = loaderName
            requestStatus['how'] = 'teleportIn'
            requestStatus['avId'] = avatarId
            base.cr.playGame.getPlace().fsm.request('teleportOut',
                                                    [requestStatus])
            self.cleanup()

    def exitWaitOnAvatarTeleportResponse(self):
        self.ignore('gotAvatarTeleportResponse')
        self.clearActionText()
        self.clearActionButtons()

    def setActionText(self, text):
        self.actionFrameText.setText(text)

    def clearActionText(self):
        self.actionFrameText.setText("")

    def makeButtons(self, button1, button2=None):
        button2GeomFunc = {
            'Cancel': CIGlobals.getCancelBtnGeom,
            'No': CIGlobals.getCancelBtnGeom,
            'Okay': CIGlobals.getOkayBtnGeom,
            'Yes': CIGlobals.getOkayBtnGeom
        }
        if button1 and not button2:
            button1Pos = (0, 0, -0.1)
        elif button1 and button2:
            button1Pos = (-0.1, 0, -0.1)
        button2Pos = (0.1, 0, -0.1)
        if button1:
            self.actionFrameButton = DirectButton(
                text=button1,
                geom=button2GeomFunc[button1](),
                parent=self.actionFrame,
                pos=button1Pos,
                text_scale=0.045,
                text_pos=(0, -0.08),
                command=self.actionButtonPressed,
                extraArgs=[1],
                relief=None,
                geom_scale=0.75)
        if button2:
            self.actionFrameButton2 = DirectButton(
                text=button2,
                geom=button2GeomFunc[button2](),
                parent=self.actionFrame,
                pos=button2Pos,
                text_scale=0.045,
                text_pos=(0, -0.08),
                command=self.actionButtonPressed,
                extraArgs=[2],
                relief=None,
                geom_scale=0.75)

    def actionButtonPressed(self, buttonNum):
        currentState = self.actionFSM.getCurrentState().getName()
        if buttonNum == 1:
            if currentState in [
                    'waitOnAvatarStatusResponse',
                    'waitOnAvatarTeleportResponse',
                    'waitOnAvatarFriendListResponse', 'avatarBusy',
                    'unableToTP', 'fRequestA', 'fRequestR',
                    'removeFriendConfirm', 'removedFriend'
            ]:
                if currentState == 'waitOnAvatarFriendListResponse':
                    base.cr.friendsManager.d_iCancelledFriendRequest(
                        self.avatarInfo[0])
                elif currentState == 'removeFriendConfirm':
                    self.actionFSM.request('removedFriend')
                    return
                self.actionFSM.request('off')
                self.removeActionPanel()
                self.action = None
        elif buttonNum == 2:
            self.actionFSM.request('off')
            self.removeActionPanel()
            self.action = None

    def clearActionButtons(self):
        if self.actionFrameButton2:
            self.actionFrameButton2.destroy()
            self.actionFrameButton2 = None
        if self.actionFrameButton:
            self.actionFrameButton.destroy()
            self.actionFrameButton = None

    def enterAvatarBusy(self):
        self.setActionText(self.State2Text['status'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitAvatarBusy(self):
        self.clearActionText()
        self.clearActionButtons()

    def getAvatarName(self):
        if self.avatarInfo:
            return self.avatarInfo[1]

    def enterWaitOnAvatarStatusResponse(self):
        self.acceptOnce('gotAvatarStatus', self.handleAvatarStatusResponse)
        base.cr.friendsManager.d_requestAvatarStatus(self.avatarInfo[0])
        self.setActionText(self.State2Text['status'][0] % self.getAvatarName())
        self.makeButtons('Cancel')

    def handleAvatarStatusResponse(self, avatarId, status):
        if avatarId == self.avatarInfo[0]:

            # Busy
            if status == 1:
                self.actionFSM.request('avatarBusy')

            # Not busy
            else:
                self.actionFSM.request(self.action)
        else:
            self.acceptOnce('gotAvatarStatus', self.handleAvatarStatusResponse)

    def exitWaitOnAvatarStatusResponse(self):
        self.ignore('gotAvatarStatus')
        self.clearActionText()
        self.clearActionButtons()

    def enterWaitOnAvatarFriendListResponse(self):
        self.acceptOnce('friendRequestAccepted',
                        self.handleFriendRequestAccepted)
        self.acceptOnce('friendRequestRejected',
                        self.handleFriendRequestRejected)
        base.cr.friendsManager.d_askAvatarToBeFriends(self.avatarInfo[0])
        self.setActionText(self.State2Text['friend'][0] % self.getAvatarName())
        self.makeButtons('Cancel')

    def handleFriendRequestAccepted(self):
        self.actionFSM.request('fRequestA')

    def handleFriendRequestRejected(self):
        self.actionFSM.request('fRequestR')

    def exitWaitOnAvatarFriendListResponse(self):
        self.ignore('friendRequestAccepted')
        self.ignore('friendRequestRejected')
        self.clearActionText()
        self.clearActionButtons()

    def enterFriendRequestAccepted(self):
        self.setActionText(self.State2Text['friend'][2] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitFriendRequestAccepted(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterFriendRequestRejected(self):
        self.setActionText(self.State2Text['friend'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitFriendRequestRejected(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterRemoveFriendConfirm(self):
        self.setActionText(self.State2Text['remove'][0] % self.getAvatarName())
        self.makeButtons('Yes', 'No')

    def exitRemoveFriendConfirm(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterRemovedFriend(self):
        base.cr.friendsManager.d_iRemovedFriend(self.avatarInfo[0])
        self.setActionText(self.State2Text['remove'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitRemovedFriend(self):
        self.clearActionText()
        self.clearActionButtons()

    def makeActionPanel(self):
        self.actionFrame = DirectFrame(image=DGG.getDefaultDialogGeom(),
                                       image_scale=(0.7, 0.5, 0.45),
                                       image_color=(1, 1, 0.75, 1),
                                       relief=None)
        self.actionFrame.reparentTo(base.a2dTopRight)
        self.actionFrame.setPos(-0.815, 0, -0.31)
        self.actionFrameText = OnscreenText(text="",
                                            parent=self.actionFrame,
                                            scale=0.05,
                                            wordwrap=12,
                                            pos=(0, 0.1))

    def removeActionPanel(self):
        self.clearActionButtons()
        if self.actionFrameText:
            self.actionFrameText.destroy()
            self.actionFrameText = None
        if self.actionFrame:
            self.actionFrame.destroy()
            self.actionFrame = None

    def doAction(self, action):
        self.action = action
        self.actionFSM.requestFinalState()
        self.removeMoreDetailsPanel()
        self.removeActionPanel()
        self.makeActionPanel()
        if action != 'removeFriendConfirm':
            self.actionFSM.request('waitOnAvatarStatusResponse')
        else:
            self.actionFSM.request(action)

    def enterWaitOnAvatarInfoResponse(self):
        self.label = OnscreenText(text='Retrieving Toon\ndetails...',
                                  parent=self,
                                  scale=0.04)
        self.acceptOnce('avatarInfoResponse', self.handleAvatarInfoResponse)
        base.cr.friendsManager.d_requestAvatarInfo(self.avatarInfo[0])

    def handleAvatarInfoResponse(self, name, dna, maxHealth, health, zoneId,
                                 shardId, isOnline, adminToken):
        if self.avatarInfo:
            self.avatarInfo.append(name)
            self.avatarInfo.append(dna)
            self.avatarInfo.append(maxHealth)
            self.avatarInfo.append(health)
            self.avatarInfo.append(zoneId)
            self.avatarInfo.append(shardId)
            self.avatarInfo.append(isOnline)
            self.avatarInfo.append(adminToken)
            self.fsm.request('panel')

    def exitWaitOnAvatarInfoResponse(self):
        self.label.destroy()
        del self.label
        self.ignore('avatarInfoResponse')

    def makePanel(self, avId):
        if self.avatarInfo:
            if self.avatarInfo[0] == avId:
                # They clicked on the same toon without closing the
                # previous panel, maybe they're spamming?
                return

        self.cleanup()

        base.localAvatar.hideFriendButton()

        self.show()
        self.avatarInfo = []
        self.avatarInfo.append(avId)
        self.fsm.request('waitOnAvatarInfoResponse')

    def exitClicked(self):
        self.cleanup()
        base.localAvatar.showFriendButton()

    def cleanup(self):
        self.actionFSM.requestFinalState()
        self.fsm.requestFinalState()
        self.avatarInfo = None

    def enterPanel(self):
        adminToken = self.avatarInfo[8]
        text_color = CIGlobals.TextColorByAdminToken[adminToken]
        self.nameText = OnscreenText(text=self.avatarInfo[1],
                                     parent=self,
                                     pos=(0, 0.2),
                                     scale=0.035,
                                     wordwrap=8,
                                     fg=text_color)
        self.nameText.setBin('gui-popup', 60)

        dna = ToonDNA.ToonDNA()
        dna.setDNAStrand(self.avatarInfo[2])

        self.head = ToonHead.ToonHead(base.cr)
        self.head.generateHead(dna.gender, dna.animal, dna.head, 1)
        self.head.setHeadColor(dna.headcolor)
        self.head.reparentTo(self)
        self.head.setDepthWrite(1)
        self.head.setDepthTest(1)
        self.head.setH(180)
        self.head.setScale(self.animal2HeadData[dna.animal][0])
        self.head.setZ(self.animal2HeadData[dna.animal][1])

        self.laffMeter = LaffOMeter()
        r, g, b, _ = dna.headcolor
        self.laffMeter.generate(r, g, b, dna.animal, self.avatarInfo[3],
                                self.avatarInfo[4])
        self.laffMeter.reparentTo(self)
        self.laffMeter.setBin('gui-popup', 60)
        self.laffMeter.setScale(0.045)
        self.laffMeter.setPos(0, 0, -0.1)

        self.friendButton = DirectButton(
            geom=CIGlobals.getDefaultBtnGeom(),
            text="Add Friend",
            scale=0.58,
            relief=None,
            text_scale=0.058,
            geom_scale=(1.25, 0, 0.9),
            text_pos=(0, -0.0125),
            parent=self,
            pos=(0, 0, -0.12),
            command=self.doAction,
            extraArgs=['waitOnAvatarFriendListResponse'])
        self.friendButton.setPos(0, 0.0, -0.225)
        self.maybeUpdateFriendButton()

        self.teleportButton = DirectButton(
            geom=CIGlobals.getDefaultBtnGeom(),
            text="Teleport",
            scale=0.58,
            relief=None,
            text_scale=0.058,
            geom_scale=(1.25, 0, 0.9),
            text_pos=(0, -0.0125),
            parent=self,
            pos=(0, 0, -0.12),
            command=self.doAction,
            extraArgs=['waitOnAvatarTeleportResponse'])
        self.teleportButton.setPos(0, 0, -0.275)

        self.whisperButton = DirectButton(
            geom=CIGlobals.getDefaultBtnGeom(),
            text="Whisper",
            scale=0.58,
            relief=None,
            text_scale=0.058,
            geom_scale=(1.25, 0, 0.9),
            text_pos=(0, -0.0125),
            parent=self,
            pos=(0, 0, -0.12),
            command=base.localAvatar.handleClickedWhisper,
            extraArgs=[self.avatarInfo[1], self.avatarInfo[0], 1])
        self.whisperButton.setPos(0, 0, -0.325)

        self.exitButton = DirectButton(geom=CIGlobals.getCancelBtnGeom(),
                                       parent=self,
                                       relief=None,
                                       scale=0.6,
                                       pos=(0, 0.0, -0.39),
                                       command=self.exitClicked)
        gui = loader.loadModel("phase_3.5/models/gui/friendslist_gui.bam")
        self.moreDetailsBtn = DirectButton(
            geom=(gui.find('**/Horiz_Arrow_UP'), gui.find('**/Horiz_Arrow_DN'),
                  gui.find('**/Horiz_Arrow_Rllvr'),
                  gui.find('**/Horiz_Arrow_UP')),
            relief=None,
            parent=self,
            pos=(-0.127, 0.0, -0.39),
            geom_hpr=(180, 0, 0),
            command=self.makeMoreDetailsPanel,
            scale=0.77,
            text=('', 'More Details', 'More Details', ''),
            text_scale=0.045,
            text_fg=(1, 1, 1, 1),
            text_shadow=(0, 0, 0, 1),
            text_pos=(-0.08, -0.01),
            text_align=TextNode.ARight)

    def exitPanel(self):
        if self.actionFSM.getCurrentState().getName(
        ) == 'waitOnAvatarFriendListResponse':
            if self.avatarInfo:
                base.cr.friendsManager.d_iCancelledFriendRequest(
                    self.avatarInfo[0])
        self.actionFSM.requestFinalState()
        self.action = None
        self.avatarInfo = None
        self.removeActionPanel()
        self.removeMoreDetailsPanel()
        self.hide()
        if self.nameText:
            self.nameText.destroy()
            self.nameText = None
        if self.head:
            self.head.removeNode()
            self.head.delete()
            self.head = None
        if self.laffMeter:
            self.laffMeter.disable()
            self.laffMeter.delete()
            self.laffMeter = None
        if self.friendButton:
            self.friendButton.destroy()
            self.friendButton = None
        if self.teleportButton:
            self.teleportButton.destroy()
            self.teleportButton = None
        if self.whisperButton:
            self.whisperButton.destroy()
            self.whisperButton = None
        if self.exitButton:
            self.exitButton.destroy()
            self.exitButton = None
        if self.moreDetailsBtn:
            self.moreDetailsBtn.destroy()
            self.moreDetailsBtn = None
Esempio n. 3
0
class GunGameLevelLoader:
    notify = directNotify.newCategory('GunGameLevelLoader')
    LevelData = {'momada': {'name': CIGlobals.ToonBattleOriginalLevel, 
                  'camera': (
                           Point3(0.0, -25.8, 7.59), Vec3(0.0, 0.0, 0.0)), 
                  'models': [
                           'phase_11/models/lawbotHQ/LB_Zone03a.bam',
                           'phase_11/models/lawbotHQ/LB_Zone04a.bam',
                           'phase_11/models/lawbotHQ/LB_Zone7av2.bam',
                           'phase_11/models/lawbotHQ/LB_Zone08a.bam',
                           'phase_11/models/lawbotHQ/LB_Zone13a.bam',
                           'phase_10/models/cashbotHQ/ZONE17a.bam',
                           'phase_10/models/cashbotHQ/ZONE18a.bam',
                           'phase_11/models/lawbotHQ/LB_Zone22a.bam'], 
                  'parents': [
                            render,
                            'EXIT',
                            'EXIT',
                            'EXIT',
                            'ENTRANCE',
                            'ENTRANCE',
                            'ENTRANCE',
                            'EXIT'], 
                  'model_positions': [
                                    Point3(0.0, 0.0, 0.0),
                                    Point3(-1.02, 59.73, 0.0),
                                    Point3(0.0, 74.77, 0.0),
                                    Point3(0.0, 89.37, -13.5),
                                    Point3(16.33, -136.53, 0.0),
                                    Point3(-1.01, -104.4, 0.0),
                                    Point3(0.65, -23.86, 0.0),
                                    Point3(-55.66, -29.01, 0.0)], 
                  'model_orientations': [
                                       Vec3(0.0, 0.0, 0.0),
                                       Vec3(0.0, 0.0, 0.0),
                                       Vec3(90.0, 0.0, 0.0),
                                       Vec3(180.0, 0.0, 0.0),
                                       Vec3(97.0, 0.0, 0.0),
                                       Vec3(359.95, 0.0, 0.0),
                                       Vec3(90.0, 0.0, 0.0),
                                       Vec3(270.0, 0.0, 0.0)], 
                  'spawn_points': [
                                 (
                                  Point3(0, 0, 0), Vec3(0, 0, 0)),
                                 (
                                  Point3(-20, 50, 0), Vec3(0, 0, 0)),
                                 (
                                  Point3(20, 50, 0), Vec3(0, 0, 0)),
                                 (
                                  Point3(0, 120, 0), Vec3(0, 0, 0)),
                                 (
                                  Point3(0, 100, 0), Vec3(180, 0, 0)),
                                 (
                                  Point3(-90, 0, 0), Vec3(0, 0, 0)),
                                 (
                                  Point3(-170, 0, 0), Vec3(0, 0, 0)),
                                 (
                                  Point3(-90, 50, 0), Vec3(0, 0, 0)),
                                 (
                                  Point3(-170, 50, 0), Vec3(0, 0, 0)),
                                 (
                                  Point3(35, 250, 0), Vec3(-90, 0, 0)),
                                 (
                                  Point3(0, 285, 0), Vec3(180, 0, 0)),
                                 (
                                  Point3(-185, 250, 0), Vec3(90, 0, 0))]}, 
       'dg': {'name': CIGlobals.DaisyGardens, 
              'camera': (
                       Point3(-33.13, -3.2, 48.62), Vec3(326.31, 332.68, 0.0)), 
              'dna': [
                    'phase_8/dna/storage_DG.pdna',
                    'phase_8/dna/storage_DG_sz.pdna',
                    'phase_8/dna/daisys_garden_sz.pdna'], 
              'sky': 'TT', 
              'spawn_points': hoodMgr.dropPoints[CIGlobals.DaisyGardens]}, 
       'mml': {'name': CIGlobals.MinniesMelodyland, 
               'camera': (
                        Point3(-54.42, -91.05, 34.89), Vec3(315.29, 336.8, 0.0)), 
               'dna': [
                     'phase_6/dna/storage_MM.pdna',
                     'phase_6/dna/storage_MM_sz.pdna',
                     'phase_6/dna/minnies_melody_land_sz.pdna'], 
               'sky': 'MM', 
               'spawn_points': hoodMgr.dropPoints[CIGlobals.MinniesMelodyland]}, 
       'oz': {'name': CIGlobals.OutdoorZone, 
              'camera': (
                       Point3(-54.42, -91.05, 34.89), Vec3(315.29, 336.8, 0.0)), 
              'dna': [
                    'phase_6/dna/storage_OZ.pdna',
                    'phase_6/dna/storage_OZ_sz.pdna',
                    'phase_6/dna/outdoor_zone_sz.pdna'], 
              'sky': 'TT', 
              'spawn_points': hoodMgr.dropPoints[CIGlobals.OutdoorZone]}, 
       'cbhq': {'name': CIGlobals.CashbotHQ, 
                'camera': (
                         Point3(302.64, 5.0, 15.2), Vec3(135.0, 341.57, 0.0)), 
                'model': 'phase_10/models/cogHQ/CashBotShippingStation.bam', 
                'sky': None, 
                'spawn_points': hoodMgr.dropPoints[CIGlobals.CashbotHQ]}, 
       'sbf': {'name': CIGlobals.SellbotFactory, 
               'camera': (
                        Point3(0, 0, 0), Vec3(0, 0, 0)), 
               'model': 'phase_9/models/cogHQ/SelbotLegFactory.bam', 
               'sky': 'cog', 
               'sky_scale': 10.0, 
               'occluders': 'phase_9/models/cogHQ/factory_sneak_occluders.egg', 
               'spawn_points': {GGG.Teams.BLUE: [
                                               (
                                                Point3(13, 30, 3.73), Point3(0, 0, 0)), (Point3(21, 30, 3.73), Point3(0, 0, 0)), (Point3(29, 30, 3.73), Point3(0, 0, 0)),
                                               (
                                                Point3(13, 20, 3.73), Point3(0, 0, 0)), (Point3(21, 20, 3.73), Point3(0, 0, 0)), (Point3(29, 30, 3.73), Point3(0, 0, 0))], 
                                GGG.Teams.RED: [
                                              (
                                               Point3(-644.43, 378.12, 8.73), Point3(270, 0, 0)), (Point3(-644.43, 370.75, 8.73), Point3(270, 0, 0)), (Point3(-644.43, 363.22, 8.73), Point3(270, 0, 0)),
                                              (
                                               Point3(-659.05, 378.12, 8.73), Point3(270, 0, 0)), (Point3(-659.05, 370.75, 8.73), Point3(270, 0, 0)), (Point3(-659.05, 363.22, 8.73), Point3(270, 0, 0))]}, 
               'flag_points': {GGG.Teams.BLUE: [Point3(213.23, 340.59, 19.73), Point3(90, 0, 0)], GGG.Teams.RED: [
                                             Point3(-543.6, 595.79, 9.73), Point3(270, 0, 0)]}, 
               'flagpoint_points': {GGG.Teams.BLUE: [Point3(-543.6, 595.79, 9.73), Point3(270, 0, 0)], GGG.Teams.RED: [
                                                  Point3(213.23, 340.59, 19.73), Point3(0, 0, 0)]}}, 
       'ttc': {'name': CIGlobals.ToontownCentral, 
               'dna': [
                     'phase_4/dna/storage_TT.pdna',
                     'phase_4/dna/storage_TT_sz.pdna',
                     'phase_4/dna/new_ttc_sz.pdna'], 
               'sky': 'TT', 
               'spawn_points': [
                              (9.90324401855, 91.9139556885, 8.0364112854, -545.909545898, 0.0, 0.0),
                              (77.9181442261, 50.953086853, 7.52815723419, -598.509460449, 0.0, 0.0),
                              (93.7379760742, 6.37303066254, 7.99749088287, -626.209533691, 0.0, 0.0),
                              (39.0383415222, -81.5989837646, 8.01874637604, -694.309265137, 0.0, 0.0),
                              (-19.2093048096, -95.1359481812, 8.07303524017, -731.409240723, 0.0, 0.0),
                              (-84.4093933105, -45.4780502319, 8.06541728973, -781.809143066, 0.0, 0.0),
                              (-92.2512283325, 2.41426730156, 8.03108692169, -811.70916748, 0.0, 0.0),
                              (46.8868179321, 81.3593673706, 8.04793071747, -955.309509277, 0.0, 0.0),
                              (32.3203735352, 90.0017929077, 8.06353855133, -884.409301758, 0.0, 0.0)], 
               'cap_point': Point3(-1.5, 0, 0)}}
    SkyData = {'TT': 'phase_3.5/models/props', 
       'MM': 'phase_6/models/props', 
       'cog': 'phase_9/models/cogHQ', 
       'MovingSkies': [
                     'TT']}

    def __init__(self, mg):
        self.mg = mg
        self.levelName = None
        self.dnaStore = DNAStorage()
        self.loadingText = None
        self.levelGeom = None
        self.skyUtil = None
        self.skyModel = None
        self.occluders = None
        self.momadaAreas = []
        self.momadaAreaName2areaModel = {}
        return

    def getFlagPoint_Point(self, team):
        return self.LevelData[self.levelName]['flagpoint_points'][team]

    def getFlagPoint(self, team):
        return self.LevelData[self.levelName]['flag_points'][team]

    def getCapturePoint(self):
        return self.LevelData[self.levelName]['cap_point']

    def setLevel(self, level):
        self.levelName = level

    def getLevel(self):
        return self.levelName

    def getCameraOfCurrentLevel(self):
        return self.LevelData[self.getLevel()]['camera']

    def getSpawnPoints(self):
        pointData = self.LevelData[self.levelName]['spawn_points']
        if self.levelName == 'momada':
            return pointData
        if self.mg.gameMode in [GGG.GameModes.CASUAL, GGG.GameModes.KOTH]:
            array = []
            for posAndHpr in pointData:
                array.append((
                 Point3(posAndHpr[0], posAndHpr[1], posAndHpr[2]),
                 Vec3(posAndHpr[3], posAndHpr[4], posAndHpr[5])))

        else:
            if self.mg.gameMode == GGG.GameModes.CTF:
                array = pointData[self.mg.team]
        return array

    def getNameOfCurrentLevel(self):
        return self.LevelData[self.getLevel()]['name']

    def load(self):
        self.unload()
        if self.loadingText:
            self.loadingText.destroy()
            self.loadingText = None
        self.loadingText = OnscreenText(text='', font=CIGlobals.getMinnieFont(), fg=(1,
                                                                                     1,
                                                                                     1,
                                                                                     1))
        self.loadingText.setBin('gui-popup', 0)
        base.graphicsEngine.renderFrame()
        base.graphicsEngine.renderFrame()
        if self.levelName == 'momada':
            self.__momadaLoad()
        else:
            if self.levelName in ('cbhq', 'sbf'):
                modelPath = self.LevelData[self.levelName]['model']
                self.levelGeom = loader.loadModel(modelPath)
                self.levelGeom.flattenMedium()
                self.levelGeom.reparentTo(render)
                if self.LevelData[self.levelName]['sky'] != None:
                    self.skyModel = loader.loadModel(self.SkyData['cog'] + '/cog_sky.bam')
                    self.skyUtil = SkyUtil()
                    self.skyUtil.startSky(self.skyModel)
                    self.skyModel.reparentTo(render)
                    self.skyModel.setScale(self.LevelData[self.levelName].get('sky_scale', 1.0))
                if self.LevelData[self.levelName].get('occluders'):
                    self.occluders = loader.loadModel(self.LevelData[self.levelName]['occluders'])
                    for occluderNode in self.occluders.findAllMatches('**/+OccluderNode'):
                        base.render.setOccluder(occluderNode)
                        occluderNode.node().setDoubleSided(True)

                if self.levelName == 'sbf':
                    base.camLens.setFar(250)
            else:
                dnaFiles = self.LevelData[self.levelName]['dna']
                skyType = self.LevelData[self.levelName]['sky']
                skyPhase = self.SkyData[skyType]
                loadDNAFile(self.dnaStore, 'phase_4/dna/storage.pdna')
                for index in range(len(dnaFiles)):
                    if index == len(dnaFiles) - 1:
                        node = loadDNAFile(self.dnaStore, dnaFiles[index])
                        if node.getNumParents() == 1:
                            self.levelGeom = NodePath(node.getParent(0))
                            self.levelGeom.reparentTo(hidden)
                        else:
                            self.levelGeom = hidden.attachNewNode(node)
                        if self.levelName == 'ttc' and dnaFiles[index] == 'phase_4/dna/new_ttc_sz.pdna':
                            self.levelGeom.find('**/prop_gazebo_DNARoot').removeNode()
                        else:
                            self.levelGeom.flattenMedium()
                        gsg = base.win.getGsg()
                        if gsg:
                            self.levelGeom.prepareScene(gsg)
                        self.levelGeom.reparentTo(render)
                    else:
                        loadDNAFile(self.dnaStore, dnaFiles[index])

                children = self.levelGeom.findAllMatches('**/*doorFrameHole*')
                for child in children:
                    child.hide()

                self.skyModel = loader.loadModel(skyPhase + '/' + skyType + '_sky.bam')
                self.skyUtil = SkyUtil()
                self.skyUtil.startSky(self.skyModel)
                self.skyModel.reparentTo(camera)
                ce = CompassEffect.make(NodePath(), CompassEffect.PRot | CompassEffect.PZ)
                self.skyModel.node().setEffect(ce)
        if self.loadingText:
            self.loadingText.destroy()
            self.loadingText = None
        return

    def __momadaLoad(self):

        def attachArea(itemNum):
            name = 'MomadaArea-%s' % itemNum
            area = self.momadaAreaName2areaModel.get(name)
            parents = self.LevelData['momada']['parents']
            parent = parents[itemNum]
            if type(parent) == type(''):
                parent = self.momadaAreas[itemNum - 1].find('**/' + parent)
            pos = self.LevelData['momada']['model_positions'][itemNum]
            hpr = self.LevelData['momada']['model_orientations'][itemNum]
            area.reparentTo(parent)
            area.setPos(pos)
            area.setHpr(hpr)

        _numItems = 0
        name = None
        for item in self.LevelData['momada']['models']:
            name = 'MomadaArea-%s' % _numItems
            area = loader.loadModel(item)
            self.momadaAreas.append(area)
            self.momadaAreaName2areaModel[name] = area
            attachArea(_numItems)
            _numItems += 1
            self.notify.info('Loaded and attached %s momada areas.' % _numItems)

        return

    def unload(self):
        render.clearOccluder()
        if self.levelName == 'sbf':
            base.camLens.setFar(CIGlobals.DefaultCameraFar)
        if self.levelName == 'momada':
            for area in self.momadaAreas:
                self.momadaAreas.remove(area)
                area.removeNode()
                del area

            self.momadaAreas = []
            self.momadaAreaName2areaModel = {}
        else:
            if self.occluders:
                self.occluders.removeNode()
                self.occluders = None
            if self.skyUtil:
                self.skyUtil.stopSky()
                self.skyUtil = None
            if self.skyModel:
                self.skyModel.removeNode()
                self.skyModel = None
            if self.levelGeom:
                self.levelGeom.removeNode()
                self.levelGeom = None
        return

    def cleanup(self):
        self.momadaAreas = None
        self.momadaAreaName2areaModel = None
        if self.dnaStore:
            self.dnaStore.reset_nodes()
            self.dnaStore.reset_hood_nodes()
            self.dnaStore.reset_place_nodes()
            self.dnaStore.reset_hood()
            self.dnaStore.reset_fonts()
            self.dnaStore.reset_DNA_vis_groups()
            self.dnaStore.reset_textures()
            self.dnaStore.reset_block_numbers()
            self.dnaStore.reset_block_zones()
            self.dnaStore.reset_suit_points()
        self.dnaStore = None
        return
class CogInvasionClientRepository(AstronClientRepository):
    notify = directNotify.newCategory("CIClientRepository")
    GameGlobalsId = DO_ID_COGINVASION
    SetZoneDoneEvent = 'CICRSetZoneDone'
    EmuSetZoneDoneEvent = 'CICREmuSetZoneDone'
    SetInterest = 'Set'
    ClearInterest = 'Clear'
    ClearInterestDoneEvent = 'CICRClearInterestDone'
    ITAG_PERM = 'perm'
    ITAG_AVATAR = 'avatar'
    ITAG_SHARD = 'shard'
    ITAG_WORLD = 'world'
    ITAG_GAME = 'game'

    def __init__(self, serverVersion):
        self.serverVersion = serverVersion
        AstronClientRepository.__init__(
            self, ['phase_3/etc/direct.dc', 'phase_3/etc/toon.dc'])
        self.loginFSM = ClassicFSM('login', [
            State('off', self.enterOff, self.exitOff),
            State('connect', self.enterConnect, self.exitConnect),
            State('disconnect', self.enterDisconnect, self.exitDisconnect),
            State('avChoose', self.enterAvChoose, self.exitAvChoose),
            State('playingGame', self.enterPlayingGame, self.exitPlayingGame),
            State('serverUnavailable', self.enterServerUnavailable,
                  self.exitServerUnavailable),
            State('makeAToon', self.enterMakeAToon, self.exitMakeAToon),
            State('submitNewToon', self.enterSubmitNewToon,
                  self.exitSubmitNewToon),
            State('noShards', self.enterNoShards, self.exitNoShards),
            State('waitForSetAvatarResponse',
                  self.enterWaitForSetAvatarResponse,
                  self.exitWaitForSetAvatarResponse),
            State('waitForShardList', self.enterWaitForShardList,
                  self.exitWaitForShardList),
            State('ejected', self.enterEjected, self.exitEjected),
            State('districtReset', self.enterDistrictReset,
                  self.exitDistrictReset),
            State('died', self.enterDied, self.exitDied),
            State('betaInform', self.enterBetaInform, self.exitBetaInform)
        ], 'off', 'off')
        self.loginFSM.enterInitialState()
        self.gameFSM = ClassicFSM('game', [
            State('off', self.enterGameOff, self.exitGameOff),
            State('waitForGameEnterResponse',
                  self.enterWaitForGameEnterResponse,
                  self.exitWaitForGameEnterResponse),
            State('playGame', self.enterPlayGame, self.exitPlayGame),
            State('closeShard', self.enterCloseShard, self.exitCloseShard),
            State('switchShards', self.enterSwitchShards,
                  self.exitSwitchShards)
        ], 'off', 'off')
        self.gameFSM.enterInitialState()
        #self.taskNameAllocator = UniqueIdAllocator(0, 1000000000)
        self.avChooser = AvChooser(self.loginFSM)
        self.playGame = PlayGame(self.gameFSM, "playGameDone")
        self.hoodMgr = HoodMgr()
        self.makeAToon = MakeAToon()
        self.loginToken = os.environ.get("LOGIN_TOKEN")
        self.serverAddress = os.environ.get("GAME_SERVER")
        self.serverURL = URLSpec("http://%s" % self.serverAddress)
        self.parentMgr.registerParent(CIGlobals.SPRender, render)
        self.parentMgr.registerParent(CIGlobals.SPHidden, hidden)
        self.adminAccess = False
        self.localAvChoice = None
        self.SuitsActive = 0
        self.BossActive = 0
        self.accServerTimesNA = 0
        self.maxAccServerTimesNA = 10
        self.setZonesEmulated = 0
        self.old_setzone_interest_handle = None
        self.setZoneQueue = Queue()
        self.accept(self.SetZoneDoneEvent, self._handleEmuSetZoneDone)
        self.handler = None
        self.__currentAvId = 0
        self.myDistrict = None
        self.activeDistricts = {}
        self.shardListHandle = None
        self.uberZoneInterest = None
        self.isShowingPlayerIds = False
        self.doBetaInform = False
        self.dTutorial = None
        self.requestedName = None
        self.whisperNoise = base.loadSfx(
            'phase_3.5/audio/sfx/GUI_whisper_3.ogg')
        self.checkHttp()
        #self.http.addPreapprovedServerCertificateFilename(self.serverURL, Filename('phase_3/etc/gameserver.crt'))
        #self.tournamentMusicChunks = {}
        #self.threadedTaskChain = taskMgr.setupTaskChain("threadedTaskChainForSoundIntervals", numThreads = 2)

        self.attackMgr = base.cl_attackMgr

        base.minigame = None

        self.newToonSlot = None

        base.finalExitCallbacks.insert(0, self.__handleExit)

        self.accountName = os.environ.get('ACCOUNT_NAME', '')
        self.csm = self.generateGlobalObject(DO_ID_CLIENT_SERVICES_MANAGER,
                                             'ClientServicesManager')
        self.friendsManager = self.generateGlobalObject(
            DO_ID_FRIENDS_MANAGER, 'FriendsManager')
        self.uin = self.generateGlobalObject(DO_ID_UNIQUE_INTEREST_NOTIFIER,
                                             'UniqueInterestNotifier')
        self.statsManager = self.generateGlobalObject(DO_ID_STATS_MANAGER,
                                                      'StatsManager')

        self.pingToggle = False
        self.currentPing = None

        self.pingText = OnscreenText("",
                                     align=TextNode.ALeft,
                                     parent=base.a2dBottomLeft,
                                     fg=(1, 1, 1, 1),
                                     shadow=(0, 0, 0, 0.5),
                                     pos=(0.3, 0.09))
        self.pingText.setBin('gsg-popup', 1000)
        self.pingText.hide()

        SpeedHackChecker.startChecking()
        self.loginFSM.request('connect')
        return

    def readerPollUntilEmpty(self, task):
        while self.readerPollOnce():
            pass

        if not metadata.IS_PRODUCTION:
            if ConfigVariableBool('simulated-latency', False).getValue():
                latency = random.uniform(
                    ConfigVariableDouble('simulated-latency-min',
                                         0.125).getValue(),
                    ConfigVariableDouble('simulated-latency-max',
                                         0.15).getValue())
                task.delayTime = latency
                return task.again

        return task.cont

    def togglePing(self):
        self.pingToggle = not self.pingToggle

        if self.pingToggle:
            taskMgr.add(self.__districtPingTask, "CICR.districtPingTask")
            self.showPing()
        else:
            self.hidePing()
            taskMgr.remove("CICR.districtPingTask")

    def showPing(self):
        self.pingText.show()

    def hidePing(self):
        self.pingText.hide()

    def handleNewPing(self):
        if self.currentPing is None:
            display = "?"
        else:
            display = int(round(self.currentPing))

        self.pingText.setText("Ping: {0} ms".format(display))

    def __districtPingTask(self, task):
        if self.myDistrict:
            # Figure out how much network latency there is.
            self.myDistrict.d_ping()

        task.delayTime = 1.0
        return task.again

    def deleteObject(self, doId):
        """
        implementation copied from AstronClientRepository.py

        Brian: modified to also delete owner views

        Removes the object from the client's view of the world.  This
        should normally not be called directly except in the case of
        error recovery, since the server will normally be responsible
        for deleting and disabling objects as they go out of scope.

        After this is called, future updates by server on this object
        will be ignored (with a warning message).  The object will
        become valid again the next time the server sends a generate
        message for this doId.

        This is not a distributed message and does not delete the
        object on the server or on any other client.
        """

        if doId in self.doId2do:
            # If it is in the dictionary, remove it.
            obj = self.doId2do[doId]
            # Remove it from the dictionary
            del self.doId2do[doId]
            # Disable, announce, and delete the object itself...
            # unless delayDelete is on...
            obj.deleteOrDelay()
            if self.isLocalId(doId):
                self.freeDoId(doId)
        elif doId in self.doId2ownerView:
            # If it is in the owner dictionary, remove it.
            obj = self.doId2ownerView[doId]
            # Remove it from the dictionary
            del self.doId2ownerView[doId]
            # Disable, announce, and delete the object itself...
            # unless delayDelete is on...
            obj.deleteOrDelay()
            if self.isLocalId(doId):
                self.freeDoId(doId)
        elif self.cache.contains(doId):
            # If it is in the cache, remove it.
            self.cache.delete(doId)
            if self.isLocalId(doId):
                self.freeDoId(doId)
        elif self.cacheOwner.contains(doId):
            # If it is in the owner cache, remove it.
            self.cacheOwner.delete(doId)
            if self.isLocalId(doId):
                self.freeDoId(doId)
        else:
            # Otherwise, ignore it
            self.notify.warning("Asked to delete non-existent DistObj " +
                                str(doId))

    #def uniqueName(self, idString):
    #	return "%s-%s" % (idString, self.taskNameAllocator.allocate())

    #def removeTask(self, taskName):
    #	div = taskName.split('-')
    #	self.taskNameAllocator.free(div[1])
    #	taskMgr.remove(taskName)

    def __handleExit(self):
        try:
            base.localAvatar.b_setAnimState('teleportOut')
        except:
            pass

        ccoginvasion.CTMusicData.stop_am_update_task()

        self.gameFSM.request('closeShard', ['off'])

    def isChristmas(self):
        return self.holidayManager.getHoliday() == HolidayType.CHRISTMAS

    def showPlayerIds(self):
        print "Showing player ids..."
        self.isShowingPlayerIds = True
        for av in self.doId2do.values():
            if av.__class__.__name__ in [
                    "DistributedPlayerToon", "LocalToon", "DistributedSuit"
            ]:
                av.showAvId()

    def hidePlayerIds(self):
        print "Hiding player ids..."
        self.isShowingPlayerIds = False
        for av in self.doId2do.values():
            if av.__class__.__name__ in [
                    "DistributedPlayerToon", "LocalToon", 'DistributedSuit'
            ]:
                av.showName()

    def sendSetLocation(self, doId, parentId, zoneId):
        dg = PyDatagram()
        dg.addUint16(CLIENT_OBJECT_LOCATION)
        dg.addUint32(doId)
        dg.addUint32(parentId)
        dg.addUint32(zoneId)
        self.send(dg)

    def getNextSetZoneDoneEvent(self):
        return '%s-%s' % (self.EmuSetZoneDoneEvent, self.setZonesEmulated + 1)

    def getLastSetZoneDoneEvent(self):
        return '%s-%s' % (self.EmuSetZoneDoneEvent, self.setZonesEmulated)

    def getQuietZoneLeftEvent(self):
        return 'leftQuietZone-%s' % (id(self), )

    def b_setLocation(self, do, parentId, zoneId):
        self.sendSetLocation(do.doId, parentId, zoneId)
        do.setLocation(parentId, zoneId)

    def sendSetZoneMsg(self, zoneId, visibleZoneList=None):
        event = self.getNextSetZoneDoneEvent()
        self.setZonesEmulated += 1
        parentId = base.localAvatar.defaultShard
        self.sendSetLocation(base.localAvatar.doId, parentId, zoneId)
        localAvatar.setLocation(parentId, zoneId)
        interestZones = zoneId
        if visibleZoneList is not None:
            interestZones = visibleZoneList
        self._addInterestOpToQueue(
            self.SetInterest, [parentId, interestZones, 'OldSetZoneEmulator'],
            event)
        return

    def resetInterestStateForConnectionLoss(self):
        self.old_setzone_interest_handle = None
        self.setZoneQueue.clear()
        return

    def _removeEmulatedSetZone(self, doneEvent):
        self._addInterestOpToQueue(self.ClearInterest, None, doneEvent)
        return

    def _addInterestOpToQueue(self, op, args, event):
        self.setZoneQueue.push([op, args, event])
        if len(self.setZoneQueue) == 1:
            self._sendNextSetZone()

    def _sendNextSetZone(self):
        op, args, event = self.setZoneQueue.top()
        if op == self.SetInterest:
            parentId, interestZones, name = args
            if self.old_setzone_interest_handle is None:
                self.old_setzone_interest_handle = self.addInterest(
                    parentId, interestZones, name, self.SetZoneDoneEvent)
            else:
                self.alterInterest(self.old_setzone_interest_handle, parentId,
                                   interestZones, name, self.SetZoneDoneEvent)
        elif op == self.ClearInterest:
            self.removeInterest(self.old_setzone_interest_handle,
                                self.SetZoneDoneEvent)
            self.old_setzone_interest_handle = None
        else:
            self.notify.error('unknown setZone op: %s' % op)
        return

    def _handleEmuSetZoneDone(self):
        op, args, event = self.setZoneQueue.pop()
        queueIsEmpty = self.setZoneQueue.isEmpty()
        if event is not None:
            messenger.send(event)
        if not queueIsEmpty:
            self._sendNextSetZone()
        return

    def enterSwitchShards(self, shardId, hoodId, zoneId, avId):
        self._switchShardParams = [shardId, hoodId, zoneId, avId]
        self.removeShardInterest(self._handleOldShardGone)

    def _handleOldShardGone(self):
        status = {}
        status['hoodId'] = self._switchShardParams[1]
        status['zoneId'] = self._switchShardParams[2]
        status['avId'] = self._switchShardParams[3]
        self.gameFSM.request('waitForGameEnterResponse',
                             [status, self._switchShardParams[0]])

    def exitSwitchShards(self):
        del self._switchShardParams

    def enterBetaInform(self):
        msg = (
            "Welcome to Cog Invasion Online!\n\nBefore playing, please remember that the game is in Alpha, "
            "and that you may encounter bugs and incomplete features.\n\nIf you happen to encounter any bugs, "
            "please report them to us by using the Contact Us Page at coginvasion.com.\n\nHave fun!"
        )
        self.dialog = GlobalDialog(message=msg,
                                   style=3,
                                   doneEvent="gameEnterChoice")
        self.dialog.show()
        self.acceptOnce("gameEnterChoice", self.handleGameEnterChoice)

    def handleGameEnterChoice(self):
        self.loginFSM.request('avChoose')

    def exitBetaInform(self):
        self.ignore("gameEnterChoice")
        self.dialog.cleanup()
        del self.dialog

    def enterCloseShard(self, nextState='avChoose'):
        self.setNoNewInterests(True)
        self._removeLocalAvFromStateServer(nextState)

    def exitCloseShard(self):
        self.setNoNewInterests(False)
        self.ignore(self.ClearInterestDoneEvent)
        return

    def _removeLocalAvFromStateServer(self, nextState):
        self.sendSetAvatarIdMsg(0)
        self._removeAllOV()
        callback = Functor(self.loginFSM.request, nextState)
        self.removeShardInterest(callback)

    def removeShardInterest(self, callback):
        self._removeCurrentShardInterest(
            Functor(self._removeShardInterestComplete, callback))

    def _removeShardInterestComplete(self, callback):
        self.cache.flush()
        self.doDataCache.flush()

        callback()
        return

    def _removeCurrentShardInterest(self, callback):
        if self.old_setzone_interest_handle is None:
            callback()
            return
        self.acceptOnce(self.ClearInterestDoneEvent,
                        Functor(self._removeCurrentUberZoneInterest, callback))
        self._removeEmulatedSetZone(self.ClearInterestDoneEvent)
        return

    def _removeCurrentUberZoneInterest(self, callback):
        self.acceptOnce(self.ClearInterestDoneEvent,
                        Functor(self._removeShardInterestDone, callback))
        self.removeInterest(self.uberZoneInterest, self.ClearInterestDoneEvent)

    def _removeShardInterestDone(self, callback):
        self.uberZoneInterest = None
        callback()
        return

    def _removeAllOV(self):
        owners = self.doId2ownerView.keys()
        for doId in owners:
            self.disableDoId(doId, ownerView=True)

    def enterDied(self):
        self.deathDialog = GlobalDialog(message=CIGlobals.SuitDefeatMsg,
                                        style=2,
                                        doneEvent="deathChoice")
        self.deathDialog.show()
        self.acceptOnce("deathChoice", self.handleDeathChoice)

    def handleDeathChoice(self):
        value = self.deathDialog.getValue()
        if value:
            self.loginFSM.request('avChoose')
        else:
            sys.exit()

    def exitDied(self):
        self.deathDialog.cleanup()
        del self.deathDialog
        self.ignore("deathChoice")

    def enterConnect(self):
        self.connectingDialog = GlobalDialog(message=CIGlobals.ConnectingMsg)
        self.connectingDialog.show()
        self.connect([self.serverURL],
                     successCallback=self.handleConnected,
                     failureCallback=self.handleConnectFail)

    def handleConnected(self):
        self.notify.info("Sending CLIENT_HELLO...")
        self.acceptOnce("CLIENT_HELLO_RESP", self.handleClientHelloResp)
        self.acceptOnce("CLIENT_EJECT", self.handleEjected)
        self.acceptOnce("LOST_CONNECTION", self.handleLostConnection)
        AstronClientRepository.sendHello(self, self.serverVersion)

    def handleLostConnection(self):
        self.deleteAllObjects()
        self.loginFSM.request('disconnect', [1])

    def deleteAllObjects(self):
        for doId in self.doId2do.keys():
            obj = self.doId2do[doId]

            if not isinstance(obj, DistributedObjectGlobal) and not hasattr(
                    obj, 'isDistrict'):
                if hasattr(base,
                           'localAvatar') and doId != base.localAvatar.doId:
                    self.deleteObject(doId)

    def handleEjected(self, errorCode, reason):
        self.notify.info("OMG I WAS EJECTED!")
        self.ignore("LOST_CONNECTION")
        errorMsg = ErrorCode2ErrorMsg.get(errorCode,
                                          None) or UnknownErrorMsg % errorCode
        self.loginFSM.request('ejected', [errorMsg])

    def handleClientHelloResp(self):
        self.notify.info("Got CLIENT_HELLO_RESP!")
        self.acceptOnce(self.csm.getLoginAcceptedEvent(),
                        self.handleLoginAccepted)
        self.csm.d_requestLogin(self.loginToken, self.accountName)

    def handleLoginAccepted(self):
        self.notify.info("Woo-hoo, I am authenticated!")
        base.cr.holidayManager = self.generateGlobalObject(
            DO_ID_HOLIDAY_MANAGER, 'HolidayManager')
        base.cr.nameServicesManager = self.generateGlobalObject(
            DO_ID_NAME_SERVICES_MANAGER, 'NameServicesManager')
        self.loginFSM.request('waitForShardList')

    def handleConnectFail(self, _, __):
        self.notify.info("Could not connect to gameserver, notifying user.")
        self.connectingDialog.cleanup()
        self.connectingDialog = GlobalDialog(
            message=CIGlobals.NoConnectionMsg % self.serverAddress + " " +
            CIGlobals.TryAgain,
            style=2,
            doneEvent="connectFail")
        self.connectingDialog.show()
        self.acceptOnce("connectFail", self.handleConnectFailButton)

    def handleConnectFailButton(self):
        value = self.connectingDialog.getValue()
        if value:
            self.loginFSM.request('connect')
        else:
            sys.exit()

    def exitConnect(self):
        self.ignore("connectFail")
        self.ignore("CLIENT_HELLO_RESP")
        self.ignore(self.csm.getLoginAcceptedEvent())
        self.connectingDialog.cleanup()
        del self.connectingDialog

    def enterEjected(self, errorMsg):
        self.ejectDialog = GlobalDialog(message=errorMsg,
                                        style=3,
                                        doneEvent='ejectDone')
        self.ejectDialog.show()
        self.acceptOnce('ejectDone', sys.exit)

    def exitEjected(self):
        self.ignore('ejectDone')
        self.ejectDialog.cleanup()
        del self.ejectDialog

    def enterServerUnavailable(self):
        self.notify.info(CIGlobals.ServerUnavailable)
        self.serverNA = GlobalDialog(message=CIGlobals.ServerUnavailable,
                                     style=4,
                                     doneEvent="serverNAEvent")
        self.serverNA.show()
        self.acceptOnce("serverNAEvent", sys.exit)
        self.startServerNAPoll()

    def startServerNAPoll(self):
        self.notify.info("Starting server poll...")
        self.accServerTimesNA = 1
        taskMgr.add(self.serverNAPoll, "serverNAPoll")

    def serverNAPoll(self, task):
        dg = PyDatagram()
        dg.addUint16(ACC_IS_SERVER_UP)
        self.send(dg)
        task.delayTime = 3.0
        return Task.again

    def __handleServerNAResp(self, resp):
        if resp == ACC_SERVER_UP:
            taskMgr.remove("serverNAPoll")
            # Enter the previous state that we were in, which should have
            # been some state where we communicate with the acc server.
            self.loginFSM.request(self.loginFSM.getLastState().getName())
        else:
            self.accServerTimesNA += 1
            if self.accServerTimesNA >= self.maxAccServerTimesNA:
                taskMgr.remove("serverNAPoll")
                self.notify.info(
                    "Giving up on polling account server after %s times." %
                    self.accServerTimesNA)
                self.loginFSM.request("disconnect", enterArgList=[1])
                self.accServerTimesNA = 0

    def exitServerUnavailable(self):
        self.ignore("serverNAEvent")
        self.serverNA.cleanup()
        del self.serverNA

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def playTheme(self):
        base.playMusic(CIGlobals.getThemeSong(), looping=1)

    def enterAvChoose(self, newToonSlot=None):
        ModelPool.garbageCollect()
        TexturePool.garbageCollect()
        self.avChooser.load()
        self.avChooser.enter(newToonSlot)
        if newToonSlot is None:
            self.playTheme()
        self.accept("enterMakeAToon", self.__handleMakeAToonReq)
        self.accept("avChooseDone", self.__handleAvChooseDone)

    def __handleMakeAToonReq(self, slot):
        self.loginFSM.request('makeAToon', [slot])

    def __handleAvChooseDone(self, avChoice):
        print "------- AvChooseDone -------"
        print "Toon name: %s" % avChoice.getName()
        print "Slot:      %s" % avChoice.getSlot()
        print "DNA:       %s" % avChoice.getDNA()
        self.loginFSM.request("waitForSetAvatarResponse", [avChoice])

    def exitAvChoose(self):
        self.avChooser.exit()
        self.avChooser.unload()
        self.ignore("enterMakeAToon")
        self.ignore("avChooseDone")

    def handlePlayGame(self, msgType, di):
        if msgType == CLIENT_ENTER_OBJECT_REQUIRED_OTHER_OWNER:
            self.handleGenerateWithRequiredOtherOwner(msgType, di)
        else:
            AstronClientRepository.handleDatagram(self, di)

    def enterPlayingGame(self):
        zoneId = localAvatar.getLastHood()
        hoodId = ZoneUtil.getHoodId(zoneId)
        status = {"hoodId": hoodId, "zoneId": zoneId, "avId": self.localAvId}
        shardId = self.myDistrict.doId
        self.gameFSM.request('waitForGameEnterResponse', [status, shardId])

    def exitPlayingGame(self):
        self.deleteAllObjects()
        self.handler = None
        self.gameFSM.request('off')
        camera.reparentTo(render)
        camera.setPos(0, 0, 0)
        camera.setHpr(0, 0, 0)
        self.localAvChoice = None
        if loader.inBulkBlock:
            loader.endBulkLoad(loader.blockName)

    def enterNoShards(self):
        self.noShardDialog = GlobalDialog(message=CIGlobals.NoShardsMsg + " " +
                                          CIGlobals.TryAgain,
                                          style=2,
                                          doneEvent='noShardsDone')
        self.noShardDialog.show()
        self.acceptOnce('noShardsDone', self.handleNoShardsDone)

    def handleNoShardsDone(self):
        value = self.noShardDialog.getValue()
        if value:
            self.loginFSM.request('waitForShardList')
        else:
            sys.exit()

    def exitNoShards(self):
        self.noShardDialog.cleanup()
        del self.noShardDialog
        self.ignore('noShardsDone')

    def enterWaitForShardList(self):
        self.shardListHandle = self.addTaggedInterest(
            self.GameGlobalsId,
            ZoneUtil.DistrictZone,
            self.ITAG_PERM,
            'localShardList',
            event='shardList_complete')
        self.acceptOnce('shardList_complete', self._handleShardListComplete)

    def _handleShardListComplete(self):
        if self._shardsAreAvailable():
            self.myDistrict = self._chooseAShard()
            if self.doBetaInform:
                self.loginFSM.request('betaInform')
            else:
                self.loginFSM.request('avChoose')
            taskMgr.add(self.monitorDistrict, "monitorMyDistrict")
        else:
            self.loginFSM.request('noShards')

    def monitorDistrict(self, task):
        if self.myDistrict is None and self.isConnected():
            self.loginFSM.request('districtReset')
            return task.done
        return task.cont

    def _shardsAreAvailable(self):
        for shard in self.activeDistricts.values():
            if shard.available:
                return True
        return False

    def _chooseAShard(self):
        choices = []
        for shard in self.activeDistricts.values():
            choices.append(shard)
        return random.choice(choices)

    def exitWaitForShardList(self):
        self.ignore('shardList_complete')

    def enterDistrictReset(self):
        self.districtResetDialog = GlobalDialog(
            message=CIGlobals.DistrictResetMsg,
            style=3,
            doneEvent='distresetdone')
        self.districtResetDialog.show()
        self.acceptOnce('distresetdone', sys.exit)

    def exitDistrictReset(self):
        self.districtResetDialog.cleanup()
        del self.districtResetDialog

    def enterWaitForSetAvatarResponse(self, choice):
        #self.acceptOnce(self.csm.getSetAvatarEvent(), self.__handleSetAvatarResponse)
        self.sendSetAvatarMsg(choice)

    def enterLoadDone(self):
        self.loginFSM.request("playingGame")

    def __handleSetAvatarResponse(self, avId, di):
        print "Entering game..."
        enterLoad = EnterLoad(self.enterLoadDone)
        dclass = self.dclassesByName['DistributedPlayerToon']
        localAvatar = LocalToon.LocalToon(base.cr)
        localAvatar.dclass = dclass
        base.localAvatar = localAvatar
        __builtins__['localAvatar'] = base.localAvatar
        localAvatar.doId = avId
        self.localAvId = avId
        parentId = None
        zoneId = None
        localAvatar.setLocation(parentId, zoneId)
        localAvatar.generateInit()
        localAvatar.generate()
        dclass.receiveUpdateBroadcastRequiredOwner(localAvatar, di)
        localAvatar.announceGenerate()
        localAvatar.postGenerateMessage()
        self.doId2do[avId] = localAvatar

        # TEMPORARY:
        #localAvatar.hoodsDiscovered = [1000, 2000, 3000, 4000, 5000, 9000]
        #localAvatar.teleportAccess = [1000, 2000, 3000, 4000, 5000, 9000]

        enterLoad.load()
        del enterLoad

    def exitWaitForSetAvatarResponse(self):
        self.ignore(self.csm.getSetAvatarEvent())

    def enterWaitForGameEnterResponse(self, status, shardId):
        if shardId is not None:
            district = self.activeDistricts[shardId]
        else:
            district = None
        if not district:
            self.loginFSM.request('noShards')
            return
        else:
            self.myDistrict = district
        self.notify.info("Entering shard %s" % shardId)
        localAvatar.setLocation(shardId, status['zoneId'])
        localAvatar.defaultShard = shardId
        self.handleEnteredShard(status)
        return

    def handleEnteredShard(self, status):
        self.uberZoneInterest = self.addInterest(localAvatar.defaultShard,
                                                 ZoneUtil.UberZone, 'uberZone',
                                                 'uberZoneInterestComplete')
        self.acceptOnce('uberZoneInterestComplete',
                        self.uberZoneInterestComplete, [status])

    def uberZoneInterestComplete(self, status):
        self.__gotTimeSync = 0
        if self.timeManager is None:
            print "No time manager"
            DistributedSmoothNode.globalActivateSmoothing(0, 0)
            self.gotTimeSync(status)
        else:
            print "Time manager found"
            DistributedSmoothNode.globalActivateSmoothing(1, 0)
            #h = HashVal()
            #hashPrcVariables(h)
            #pyc = HashVal()
            #if not __dev__:
            #	self.hashFiles(pyc)
            #self.timeManager.d_setSignature(self.userSignature, h.asBin(), pyc.asBin())
            #self.timeManager.sendCpuInfo()

            self.timeManager.lastAttempt = -self.timeManager.minWait * 2
            if self.timeManager.synchronize('startup'):
                self.accept('gotTimeSync', self.gotTimeSync, [status])
            else:
                self.gotTimeSync(status)
        return

    def getPing(self):
        if self.myDistrict:
            return self.myDistrict.currentPing
        return 0

    def exitWaitForGameEnterResponse(self):
        self.ignore('uberZoneInterestComplete')
        return

    def gotTimeSync(self, status):
        self.notify.info('gotTimeSync')
        self.ignore('gotTimeSync')
        self.__gotTimeSync = 1
        self.prepareToEnter(status)

    def prepareToEnter(self, status):
        if not self.__gotTimeSync:
            self.notify.info("still waiting for time sync")
            return
        self.gameFSM.request('playGame', [status])

    def enterMakeAToon(self, slot):
        base.stopMusic()
        self.makeAToon.setSlot(slot)
        self.makeAToon.loadEnviron()
        self.makeAToon.load()
        self.makeAToon.matFSM.request('genderShop')
        self.acceptOnce("quitCreateAToon", self.__handleMakeAToonQuit)
        self.acceptOnce("createAToonFinished", self.__handleMakeAToonDone)

    def __handleMakeAToonQuit(self):
        self.loginFSM.request("avChoose")

    def __handleMakeAToonDone(self, dnaStrand, slot, name):
        self.loginFSM.request('submitNewToon',
                              enterArgList=[dnaStrand, slot, name])

    def exitMakeAToon(self):
        self.makeAToon.setSlot(-1)
        self.makeAToon.enterExit(None)
        self.ignore("quitCreateAToon")
        self.ignore("createAToonFinished")

    def enterSubmitNewToon(self, dnaStrand, slot, name, skipTutorial=0):
        self.newToonSlot = slot
        self.submittingDialog = GlobalDialog(message=CIGlobals.Submitting)
        self.submittingDialog.show()
        self.acceptOnce(self.csm.getToonCreatedEvent(),
                        self.__handleSubmitNewToonResp)
        self.csm.sendSubmitNewToon(dnaStrand, slot, name, skipTutorial)

    def __handleSubmitNewToonResp(self, avId):
        # Now that our toon exists in the database, we can add send over the name we wanted to NameServicesManagerUD.
        if self.requestedName is not None:
            self.nameServicesManager.d_requestName(self.requestedName, avId)
            self.requestedName = None

        self.loginFSM.request('avChoose', [self.newToonSlot])

    def exitSubmitNewToon(self):
        self.newToonSlot = None
        self.ignore(self.csm.getToonCreatedEvent())
        self.submittingDialog.cleanup()
        del self.submittingDialog

    def enterGameOff(self):
        pass

    def exitGameOff(self):
        pass

    def enterPlayGame(self, status):
        base.stopMusic()
        base.transitions.noFade()
        if self.localAvChoice is None:
            self.notify.error(
                "called enterPlayGame() without self.localAvChoice being set!")
            return
        if localAvatar.getTutorialCompleted() == 1:
            zoneId = status['zoneId']
            hoodId = status['hoodId']
            avId = status['avId']
            self.playGame.load()
            self.playGame.enter(hoodId, zoneId, avId)
        else:
            self.sendQuietZoneRequest()
            localAvatar.sendUpdate('createTutorial')
        self.myDistrict.d_joining()

    def tutorialCreated(self, zoneId):
        # zoneId = the zone the tutorial resides in
        # tutId = the doId of the tutorial
        requestStatus = {'zoneId': zoneId}
        self.tutQuietZoneState = QuietZoneState('tutQuietZoneDone')
        self.tutQuietZoneState.load()
        self.tutQuietZoneState.enter(requestStatus)
        self.acceptOnce('tutQuietZoneDone', self.__handleTutQuietZoneDone)

    def __handleTutQuietZoneDone(self):
        # We've entered the zone that the tutorial is in.
        self.tutQuietZoneState.exit()
        self.tutQuietZoneState.unload()
        del self.tutQuietZoneState

    def exitPlayGame(self):
        self.ignore('tutQuietZoneDone')
        if hasattr(self, 'tutQuietZoneDone'):
            self.tutQuietZoneState.exit()
            self.tutQuietZoneState.unload()
            del self.tutQuietZoneState
        base.stopMusic()
        self.playGame.exit()
        self.playGame.unload()

    def enterDisconnect(self, isPlaying, booted=0, bootReason=None):
        self.notify.info(
            "Disconnect details: isPlaying = %s, booted = %s, bootReason = %s"
            % (isPlaying, booted, bootReason))
        style = 3
        if isPlaying == 1:
            if not booted:
                msg = CIGlobals.DisconnectionMsg
        else:
            if not booted:
                msg = CIGlobals.JoinFailureMsg
        if self.isConnected():
            self.sendDisconnect()
        self.disconnectDialog = GlobalDialog(message=msg,
                                             style=style,
                                             doneEvent="disconnectDone")
        self.disconnectDialog.show()
        if style == 3:
            self.acceptOnce("disconnectDone", sys.exit)
        else:
            self.acceptOnce("disconnectDone", self.handleDisconnectDone)

    def handleDisconnectDone(self):
        value = self.disconnectDialog.getValue()
        if value:
            self.loginFSM.request('connect')
        else:
            sys.exit()

    def exitDisconnect(self):
        self.ignore("disconnectDone")
        self.disconnectDialog.cleanup()
        del self.disconnectDialog

    def renderFrame(self):
        gsg = base.win.getGsg()
        if gsg:
            render2d.prepareScene(gsg)
        base.graphicsEngine.renderFrame()

    def renderFrames(self):
        base.graphicsEngine.renderFrame()
        base.graphicsEngine.renderFrame()

    def handleDatagram(self, di):
        if self.notify.getDebug():
            print "ClientRepository received datagram:"
            #di.getDatagram().dumpHex(ostream)
        msgType = self.getMsgType()
        self.currentSenderId = None
        if self.handler is None:
            self.astronHandle(di)
        else:
            self.handler(msgType, di)
        self.considerHeartbeat()

    def astronHandle(self, di):
        AstronClientRepository.handleDatagram(self, di)

    def handleQuietZoneGenerateWithRequired(self, di):
        doId = di.getUint32()
        parentId = di.getUint32()
        zoneId = di.getUint32()
        classId = di.getUint16()
        dclass = self.dclassesByNumber[classId]
        if dclass.getClassDef().neverDisable:
            dclass.startGenerate()
            distObj = self.generateWithRequiredFields(dclass, doId, di,
                                                      parentId, zoneId)
            dclass.stopGenerate()

    def handleQuietZoneGenerateWithRequiredOther(self, di):
        doId = di.getUint32()
        parentId = di.getUint32()
        zoneId = di.getUint32()
        classId = di.getUint16()
        dclass = self.dclassesByNumber[classId]
        if dclass.getClassDef().neverDisable:
            dclass.startGenerate()
            distObj = self.generateWithRequiredOtherFields(
                dclass, doId, di, parentId, zoneId)
            dclass.stopGenerate()

    def handleQuietZoneUpdateField(self, di):
        di2 = DatagramIterator(di)
        doId = di2.getUint32()
        if doId in self.deferredDoIds:
            args, deferrable, dg0, updates = self.deferredDoIds[doId]
            dclass = args[2]
            if not dclass.getClassDef().neverDisable:
                return
        else:
            do = self.getDo(doId)
            if do:
                if not do.neverDisable:
                    return
        AstronClientRepository.handleUpdateField(self, di)

    def handleDelete(self, di):
        doId = di.getUint32()
        self.deleteObject(doId)

    def _abandonShard(self):
        for doId, obj in self.doId2do.items():
            if obj.parentId == localAvatar.defaultShard and obj is not localAvatar:
                self.deleteObject(doId)

    def handleEnterObjectRequiredOwner(self, di):
        if self.loginFSM.getCurrentState().getName(
        ) == 'waitForSetAvatarResponse':
            doId = di.getUint32()
            parentId = di.getUint32()
            zoneId = di.getUint32()
            dclassId = di.getUint16()
            self.__handleSetAvatarResponse(doId, di)
        else:
            AstronClientRepository.handleEnterObjectRequiredOwner(self, di)

    def addTaggedInterest(self,
                          parentId,
                          zoneId,
                          mainTag,
                          desc,
                          otherTags=[],
                          event=None):
        return self.addInterest(parentId, zoneId, desc, event)

    def sendSetAvatarMsg(self, choice):
        avId = choice.getAvId()
        self.sendSetAvatarIdMsg(avId)
        self.localAvChoice = choice

    def sendSetAvatarIdMsg(self, avId):
        if avId != self.__currentAvId:
            self.__currentAvId = avId
            self.csm.sendSetAvatar(avId)

    def sendQuietZoneRequest(self):
        self.sendSetZoneMsg(ZoneUtil.QuietZone)
Esempio n. 5
0
class DistributedMinigame(DistributedObject.DistributedObject, Timer.Timer):
    def __init__(self, cr):
        try:
            self.DistributedMinigame_initialized
            return
        except:
            self.DistributedMinigame_initialized = 1

        DistributedObject.DistributedObject.__init__(self, cr)
        Timer.Timer.__init__(self)
        self.headPanels = HeadPanels()
        self.finalScoreUI = FinalScoreGUI()
        self.fsm = ClassicFSM('DistributedMinigame', [
            State('start', self.enterStart, self.exitStart, ['waitForOthers']),
            State('waitForOthers', self.enterWaitForOthers,
                  self.exitWaitForOthers, ['play']),
            State('play', self.enterPlay, self.exitPlay, ['gameOver']),
            State('gameOver', self.enterGameOver, self.exitGameOver, ['off']),
            State('off', self.enterOff, self.exitOff)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.cr = cr
        self.localAv = base.localAvatar
        self.localAvId = self.localAv.doId
        self.musicPath = 'phase_4/audio/bgm/trolley_song.mid'
        self.winSfx = base.loadSfx('phase_4/audio/sfx/MG_win.ogg')
        self.loseSfx = base.loadSfx('phase_4/audio/sfx/MG_lose.ogg')
        self.prizeHigh = base.loadSfx('phase_6/audio/sfx/KART_Applause_1.ogg')
        self.prizeLow = base.loadSfx('phase_6/audio/sfx/KART_Applause_4.ogg')
        self.music = None
        self.description = ''
        self.descDialog = None
        self.winnerPrize = 0
        self.loserPrize = 0
        self.winnerMsg = 'Winner!\nYou have earned: %s Jellybeans'
        self.loserMsg = 'Loser!\nYou have earned: %s Jellybeans'
        self.allWinnerMsgs = [
            'Nice try!\nYou have earned: %s', 'Good job!\nYou have earned: %s',
            'Way to go!\nYou have earned: %s', 'Awesome!\nYou have earned: %s'
        ]
        self.timer = None
        self.timeLbl = None
        self.alertText = None
        self.alertPulse = None
        self.popupSound = None
        self.gameOverLbl = OnscreenText(text="TIME'S\nUP!",
                                        scale=0.25,
                                        font=CIGlobals.getMickeyFont(),
                                        fg=(1, 0, 0, 1))
        self.gameOverLbl.setBin('gui-popup', 60)
        self.gameOverLbl.hide()
        return

    def getTeamDNAColor(self, team):
        pass

    def showAlert(self, text):
        self.stopPulse()
        base.playSfx(self.popupSound)
        self.alertText.setText(text)
        self.alertPulse = getAlertPulse(self.alertText)
        self.alertPulse.start()

    def stopPulse(self):
        if self.alertPulse:
            self.alertPulse.finish()
            self.alertPulse = None
        return

    def enterFinalScores(self):
        self.finalScoreUI.load()
        self.finalScoreUI.showFinalScores()

    def exitFinalScores(self):
        self.finalScoreUI.hideFinalScores()
        self.finalScoreUI.unload()

    def finalScores(self, avIdList, scoreList):
        self.finalScoreUI.handleFinalScores(avIdList, scoreList)

    def generateHeadPanel(self, gender, head, headtype, color, doId, name):
        self.headPanels.generate(gender, head, headtype, color, doId, name)

    def updateHeadPanelValue(self, doId, direction):
        self.headPanels.updateValue(doId, direction)

    def setTimerTime(self, time):
        self.setTime(time)

    def createTimer(self):
        Timer.Timer.load(self)

    def deleteTimer(self):
        Timer.Timer.unload(self)

    def setDescription(self, desc):
        self.description = desc

    def getDescription(self):
        return self.description

    def enterStart(self):
        self.descDialog = GlobalDialog(style=3,
                                       message=self.getDescription(),
                                       doneEvent='gameDescAck')
        self.acceptOnce('gameDescAck', self.handleDescAck)

    def handleDescAck(self):
        self.d_ready()
        self.fsm.request('waitForOthers')

    def exitStart(self):
        self.ignore('gameDescAck')
        self.descDialog.cleanup()
        del self.descDialog

    def enterWaitForOthers(self):
        self.waitLbl = DirectLabel(text='Waiting for other players...',
                                   relief=None,
                                   text_fg=(1, 1, 1, 1),
                                   text_scale=0.08,
                                   text_shadow=(0, 0, 0, 1))
        return

    def exitWaitForOthers(self):
        self.waitLbl.destroy()
        del self.waitLbl

    def setLoserPrize(self, prize):
        self.loserPrize = prize

    def setWinnerPrize(self, prize):
        self.winnerPrize = prize

    def getLoserPrize(self):
        return self.loserPrize

    def getWinnerPrize(self):
        return self.winnerPrize

    def winner(self):
        self.winSfx.play()
        self.localAv.b_setAnimState('happy')
        Sequence(Wait(3.5), Func(self.displayGameOver, 'winner')).start()

    def showPrize(self, amt):
        self.winSfx.play()
        self.localAv.b_setAnimState('happy')
        Sequence(Wait(3.5), Func(self.displayGameOver, 'showPrize',
                                 amt)).start()

    def loser(self):
        self.loseSfx.play()
        self.localAv.b_setAnimState('neutral')
        Sequence(Wait(3.5), Func(self.displayGameOver, 'loser')).start()

    def displayGameOver(self, scenario, amt=None):
        if scenario == 'winner':
            msg = self.winnerMsg % self.winnerPrize
            self.prizeHigh.play()
        else:
            if scenario == 'loser':
                msg = self.loserMsg % self.loserPrize
                self.prizeLow.play()
            else:
                if scenario == 'showPrize':
                    msg = random.choice(self.allWinnerMsgs) % amt
                    self.prizeHigh.play()
        self.gameOverDialog = GlobalDialog(message=msg,
                                           style=3,
                                           doneEvent='gameOverAck')
        self.acceptOnce('gameOverAck', self.__handleGameOverAck)
        self.gameOverDialog.show()

    def deleteGameOverDialog(self):
        self.ignore('gameOverAck')
        if hasattr(self, 'gameOverDialog'):
            self.gameOverDialog.cleanup()
            del self.gameOverDialog

    def __handleGameOverAck(self):
        self.fsm.requestFinalState()
        Sequence(Func(base.transitions.irisOut, 1.0), Wait(1.2),
                 Func(self.d_leaving),
                 Func(self.headBackToMinigameArea)).start()

    def headBackToMinigameArea(self):
        whereName = ZoneUtil.getWhereName(CIGlobals.MinigameAreaId)
        loaderName = ZoneUtil.getLoaderName(CIGlobals.MinigameAreaId)
        requestStatus = {
            'zoneId': CIGlobals.MinigameAreaId,
            'hoodId': CIGlobals.MinigameArea,
            'where': whereName,
            'how': 'teleportIn',
            'avId': base.localAvatar.doId,
            'shardId': None,
            'loader': loaderName
        }
        self.cr.playGame.hood.fsm.request('quietZone', [requestStatus])
        return

    def abort(self):
        self.headBackToMinigameArea()

    def load(self, showDesc=True):
        if showDesc:
            self.fsm.request('start')
        base.transitions.irisIn()

    def d_leaving(self):
        self.sendUpdate('leaving', [])

    def allPlayersReady(self):
        self.fsm.request('play')

    def enterPlay(self):
        self.playMinigameMusic()

    def exitPlay(self):
        self.stopMinigameMusic()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterGameOver(self, winner, winnerDoId, allPrize):
        if winner:
            if self.localAvId in winnerDoId:
                self.winner()
            else:
                self.loser()
        else:
            self.showPrize(allPrize)

    def exitGameOver(self):
        self.deleteGameOverDialog()

    def gameOver(self, winner=0, winnerDoId=[], allPrize=0):
        self.fsm.request('gameOver', [winner, winnerDoId, allPrize])

    def setMinigameMusic(self, path):
        self.musicPath = path

    def getMinigameMusic(self):
        return self.musicPath

    def playMinigameMusic(self):
        self.stopMinigameMusic()
        self.music = base.loadMusic(self.musicPath)
        self.music.setLoop(True)
        self.music.setVolume(0.8)
        self.music.play()

    def stopMinigameMusic(self):
        if self.music:
            self.music.stop()
            self.music = None
        return

    def d_ready(self):
        self.sendUpdate('ready', [])

    def announceGenerate(self):
        DistributedObject.DistributedObject.announceGenerate(self)
        base.minigame = self
        self.alertText = getAlertText()
        self.popupSound = base.loadSfx(
            'phase_3/audio/sfx/GUI_balloon_popup.ogg')
        NametagGlobals.setWant2dNametags(False)

    def disable(self):
        base.localAvatar.getGeomNode().setColorScale(VBase4(1, 1, 1, 1))
        if hasattr(self, 'gameOverLbl') and self.gameOverLbl:
            self.gameOverLbl.destroy()
        self.gameOverLbl = None
        NametagGlobals.setWant2dNametags(True)
        base.localAvatar.setPosHpr(0, 0, 0, 0, 0, 0)
        self.fsm.requestFinalState()
        del self.fsm
        self.winSfx = None
        self.loseSfx = None
        self.prizeHigh = None
        self.prizeLow = None
        self.headPanels.delete()
        self.headPanels = None
        self.finalScoreUI.unload()
        self.finalScoreUI = None
        base.minigame = None
        DistributedObject.DistributedObject.disable(self)
        return
class Slot(DirectFrame):
    def __init__(self, baseGui, index, pos, parent):
        DirectFrame.__init__(
            self,
            pos=pos,
            parent=parent,
            image=loader.loadTexture('phase_3.5/maps/slot_%s_%s.png' %
                                     (str(index), 'idle')),
            scale=0.15,
            frameSize=(-1, 1, -1, 1),
            frameColor=(0, 0, 0, 0),
            sortOrder=0)
        self.initialiseoptions(Slot)
        self.gui = baseGui
        self.index = index
        self.hoverObj = None
        self.gagImage = None
        self.gag = None
        self.mouseRlvrSfx = base.loadSfx('phase_3/audio/sfx/GUI_rollover.ogg')
        self.soundRecharged = base.loadSfx(
            'phase_3.5/audio/sfx/tt_s_gui_sbk_cdrSuccess.ogg')
        self.infoText = OnscreenText(text='No\nAmmo',
                                     fg=(1, 0, 0, 1),
                                     parent=self,
                                     scale=0.5,
                                     shadow=(0, 0, 0, 1),
                                     align=TextNode.ACenter,
                                     pos=(0, 0.1))
        self.infoText.setBin('unsorted', 100)
        self.infoText.hide()
        self.rechargeBar = DirectWaitBar(value=0,
                                         range=100,
                                         frameColor=(1, 1, 1, 1),
                                         barColor=(0.286, 0.901, 1, 1),
                                         relief=DGG.RAISED,
                                         borderWidth=(0.04, 0.04),
                                         pos=(-1.25, 0, 0),
                                         hpr=(0, 0, -90),
                                         parent=self,
                                         frameSize=(-0.85, 0.85, -0.12, 0.12))
        self.rechargeBar.setBin('fixed', 60)
        self.rechargeBar.hide()
        self.gagLabel = OnscreenText(text='Birthday Cake',
                                     fg=(1, 1, 1, 1),
                                     parent=self,
                                     scale=0.25,
                                     shadow=(0, 0, 0, 1),
                                     align=TextNode.ACenter,
                                     pos=(0, -0.9),
                                     mayChange=1)
        self.gagLabel.setBin('fixed', 50)
        self.gagLabel.hide()
        battleGui = loader.loadModel('phase_3.5/models/gui/battle_gui.bam')
        arrow = battleGui.find('**/PckMn_BackBtn')
        arrowRlvr = battleGui.find('**/PckMn_BackBtn_Rlvr')
        arrowDn = battleGui.find('**/PckMn_BackBtn_Dn')
        self.leftArrow = DirectButton(geom=(arrow, arrowDn, arrowRlvr, arrow),
                                      parent=self,
                                      pos=(-0.925, -2.0, -1.02),
                                      relief=None,
                                      scale=2,
                                      command=self.updateLoadout,
                                      extraArgs=[0],
                                      geom3_color=(0.5, 0.5, 0.5, 1.0))
        self.leftArrow.setBin('fixed', 60)
        self.rightArrow = DirectButton(geom=(arrow, arrowDn, arrowRlvr, arrow),
                                       parent=self,
                                       pos=(0.925, -2.0, -1.02),
                                       hpr=(180, 0, 0),
                                       relief=None,
                                       scale=2,
                                       command=self.updateLoadout,
                                       extraArgs=[1],
                                       geom3_color=(0.5, 0.5, 0.5, 1.0))
        self.rightArrow.setBin('fixed', 60)
        self.hoverObj = DirectButton(relief=None,
                                     parent=self,
                                     frameSize=self['frameSize'])
        self.setBin('transparent', 30)
        self.setOutlineImage('idle')
        self.hoverObj.guiItem.setActive(True)
        self.hoverObj.bind(DGG.WITHIN, self.mouseEntered)
        self.hoverObj.bind(DGG.WITHOUT, self.mouseExited)
        self.hoverObj.bind(DGG.B1CLICK, self.gui.click_setWeapon, [self])
        return

    def toggleArrows(self, left, right):
        if left:
            self.leftArrow['state'] = DGG.NORMAL
        else:
            self.leftArrow['state'] = DGG.DISABLED
        if right:
            self.rightArrow['state'] = DGG.NORMAL
        else:
            self.rightArrow['state'] = DGG.DISABLED

    def updateArrows(self):
        if not self.gag:
            self.toggleArrows(False, False)
        else:
            track = GagGlobals.TrackGagNamesByTrackName.get(
                GagGlobals.getTrackOfGag(self.gag.getID()))
            index = None
            useTrack = []
            for name in track:
                gag = self.gui.backpack.getGagByID(
                    GagGlobals.getIDByName(name))
                if gag == self.gag or gag not in self.gui.backpack.getLoadout(
                ):
                    useTrack.append(name)

            index = useTrack.index(self.gag.getName())
            if index == 0:
                self.toggleArrows(False, True)
            else:
                if index > 0 and index < len(useTrack) - 1:
                    gagId = GagGlobals.getIDByName(useTrack[index + 1])
                    if not self.gui.backpack.hasGag(gagId):
                        self.toggleArrows(True, False)
                else:
                    if index == len(useTrack) - 1:
                        self.toggleArrows(True, False)
                    else:
                        self.toggleArrows(True, True)
        return

    def updateLoadout(self, forward):
        if self.gag and self.gag.getState() in [
                GagState.RECHARGING, GagState.LOADED
        ]:
            track = GagGlobals.TrackGagNamesByTrackName.get(
                GagGlobals.getTrackOfGag(self.gag.getID()))
            index = None
            useTrack = []
            for name in track:
                gag = self.gui.backpack.getGagByID(
                    GagGlobals.getIDByName(name))
                if gag == self.gag or gag not in self.gui.backpack.getLoadout(
                ):
                    useTrack.append(name)

            index = useTrack.index(self.gag.getName())
            if forward == 1:
                nextGagIndex = index + 1
            else:
                nextGagIndex = index - 1
            if nextGagIndex < 0 or nextGagIndex >= len(useTrack):
                return
            gagId = GagGlobals.getIDByName(useTrack[nextGagIndex])
            loadout = self.gui.backpack.getLoadout()
            if self.gui.backpack.hasGag(gagId) and self.gag in loadout:
                self.hideInfoText()
                if self.gag not in loadout:
                    return
                loadout[loadout.index(
                    self.gag)] = self.gui.backpack.getGagByID(gagId)
                self.gui.backpack.setLoadout(loadout)
        return

    def showNoAmmo(self):
        self.infoText['text'] = 'No\nAmmo'
        self.infoText['scale'] = 0.5
        self.infoText['fg'] = (1, 0, 0, 1)
        self.infoText['pos'] = (0, 0.1)
        self.infoText.show()
        if self.gag and self.gag.getState() == GagState.RECHARGING:
            self.rechargeBar.show()

    def showRecharging(self):
        self.infoText['text'] = 'Recharging...'
        self.infoText['scale'] = 0.315
        self.infoText['fg'] = (0.286, 0.901, 1, 1)
        self.infoText['pos'] = (0, 0)
        self.infoText.show()
        self.rechargeBar.show()

    def __tickRecharge(self):
        if not self.gag:
            self.ignoreAll()
        else:
            elapsedTime = float(self.gag.getRechargeElapsedTime())
            totalTime = float(self.gag.getRechargeTime())
            barValue = int(
                float(elapsedTime / totalTime) * self.rechargeBar['range'])
            self.rechargeBar['value'] = barValue
            if barValue == 0:
                self.gui.setWeapon(self, playSound=False)
                self.setOutlineImage('no_ammo')
                self.showRecharging()
            else:
                if barValue >= 100:
                    base.playSfx(self.soundRecharged)
                    slotImage = 'idle'
                    if base.localAvatar.getBackpack().getSupply(
                            self.gag.getID()) <= 0:
                        slotImage = 'no_ammo'
                    else:
                        if self.gui.getActiveSlot() == self:
                            slotImage = 'selected'
                    Sequence(Wait(0.5), Func(self.setOutlineImage,
                                             slotImage)).start()

    def hideInfoText(self):
        self.infoText.hide()
        self.rechargeBar.hide()

    def setSlotImage(self, gagImage):
        if self.gagImage:
            self.gagImage.destroy()
            self.gagImage = None
        self.gagImage = OnscreenImage(image=gagImage, parent=self)
        self.gagImage.setTransparency(TransparencyAttrib.MAlpha)
        return

    def setOutline(self):
        self.setTransparency(TransparencyAttrib.MAlpha)

    def setOutlineImage(self, image):
        phase = 'phase_3.5/maps/'
        if hasattr(self, '_optionInfo'):
            self['image'] = loader.loadTexture(phase + 'slot_%s_%s.png' %
                                               (str(self.index), image))
            self.setOutline()
            if image != 'no_ammo':
                if self.gag and base.localAvatar.getBackpack().getSupply(
                        self.gag.getID(
                        )) == 0 or self.gag and self.gag.getState(
                        ) == GagState.RECHARGING:
                    image = 'no_ammo'
            if image == 'no_ammo':
                if self.gag and self.gag.getState() == GagState.RECHARGING:
                    self.showRecharging()
                else:
                    self.showNoAmmo()
                    self.rechargeBar.hide()
                self.setBin('fixed', 40)
                if self.gagImage:
                    self.gagImage.setBin('transparent', 30)
            else:
                self.hideInfoText()
                if self.gagImage:
                    self.gagImage.setBin('fixed', 40)
                self.setBin('transparent', 30)

    def getOutline(self):
        return self.outline

    def mouseEntered(self, cmd):
        if self.gag:
            self.gagLabel.show()
            self.mouseRlvrSfx.play()

    def mouseExited(self, cmd):
        self.gagLabel.hide()

    def setGag(self, gag):
        if type(gag) == types.IntType:
            gag = self.gui.backpack.getGagByID(gag)
        self.ignoreAll()
        self.gag = gag
        if gag:
            self.show()
            self.setSlotImage(self.gag.getImage())
            self.gagLabel['text'] = self.gag.getName()
            self.accept('%s-Recharge-Tick' % str(self.gag.getID()),
                        self.__tickRecharge)
        else:
            self.hide()
            self.gagLabel['text'] = ''
        self.updateArrows()

    def getGag(self):
        return self.gag
Esempio n. 7
0
class GunGameLevelLoader:
    notify = directNotify.newCategory('GunGameLevelLoader')
    LevelData = {'momada': {'name': CIGlobals.ToonBattleOriginalLevel,
                'camera': (Point3(0.0, -25.8, 7.59), Vec3(0.0, 0.0, 0.0)),
                'models': ['phase_11/models/lawbotHQ/LB_Zone03a.bam',
                           'phase_11/models/lawbotHQ/LB_Zone04a.bam',
                           'phase_11/models/lawbotHQ/LB_Zone7av2.bam',
                           'phase_11/models/lawbotHQ/LB_Zone08a.bam',
                           'phase_11/models/lawbotHQ/LB_Zone13a.bam',
                           'phase_10/models/cashbotHQ/ZONE17a.bam',
                           'phase_10/models/cashbotHQ/ZONE18a.bam',
                           'phase_11/models/lawbotHQ/LB_Zone22a.bam'],
                'parents': [render,
                            'EXIT',
                            'EXIT',
                            'EXIT',
                            'ENTRANCE',
                            'ENTRANCE',
                            'ENTRANCE',
                            'EXIT'],
                'model_positions': [Point3(0.0, 0.0, 0.0),
                                    Point3(-1.02, 59.73, 0.0),
                                    Point3(0.0, 74.77, 0.0),
                                    Point3(0.0, 89.37, -13.5),
                                    Point3(16.33, -136.53, 0.0),
                                    Point3(-1.01, -104.4, 0.0),
                                    Point3(0.65, -23.86, 0.0),
                                    Point3(-55.66, -29.01, 0.0)],
                'model_orientations': [Vec3(0.0, 0.0, 0.0),
                                       Vec3(0.0, 0.0, 0.0),
                                       Vec3(90.0, 0.0, 0.0),
                                       Vec3(180.0, 0.0, 0.0),
                                       Vec3(97.0, 0.0, 0.0),
                                       Vec3(359.95, 0.0, 0.0),
                                       Vec3(90.0, 0.0, 0.0),
                                       Vec3(270.0, 0.0, 0.0)],
                'spawn_points': [(Point3(0, 0, 0), Vec3(0, 0, 0)),
                                 (Point3(-20, 50, 0), Vec3(0, 0, 0)),
                                 (Point3(20, 50, 0), Vec3(0, 0, 0)),
                                 (Point3(0, 120, 0), Vec3(0, 0, 0)),
                                 (Point3(0, 100, 0), Vec3(180, 0, 0)),
                                 (Point3(-90, 0, 0), Vec3(0, 0, 0)),
                                 (Point3(-170, 0, 0), Vec3(0, 0, 0)),
                                 (Point3(-90, 50, 0), Vec3(0, 0, 0)),
                                 (Point3(-170, 50, 0), Vec3(0, 0, 0)),
                                 (Point3(35, 250, 0), Vec3(-90, 0, 0)),
                                 (Point3(0, 285, 0), Vec3(180, 0, 0)),
                                 (Point3(-185, 250, 0), Vec3(90, 0, 0))]},
     'dg': {'name': CIGlobals.DaisyGardens,
            'camera': (Point3(-33.13, -3.2, 48.62), Vec3(326.31, 332.68, 0.0)),
            'dna': ['phase_8/dna/storage_DG.dna', 'phase_8/dna/storage_DG_sz.dna', 'phase_8/dna/daisys_garden_sz.dna'],
            'sky': 'TT',
            'spawn_points': hoodMgr.dropPoints[CIGlobals.DaisyGardens]},
     'mml': {'name': CIGlobals.MinniesMelodyland,
             'camera': (Point3(-54.42, -91.05, 34.89), Vec3(315.29, 336.8, 0.0)),
             'dna': ['phase_6/dna/storage_MM.dna', 'phase_6/dna/storage_MM_sz.dna', 'phase_6/dna/minnies_melody_land_sz.dna'],
             'sky': 'MM',
             'spawn_points': hoodMgr.dropPoints[CIGlobals.MinniesMelodyland]},
     'oz': {'name': CIGlobals.OutdoorZone,
            'camera': (Point3(-54.42, -91.05, 34.89), Vec3(315.29, 336.8, 0.0)),
            'dna': ['phase_6/dna/storage_OZ.dna', 'phase_6/dna/storage_OZ_sz.dna', 'phase_6/dna/outdoor_zone_sz.dna'],
            'sky': 'TT',
            'spawn_points': hoodMgr.dropPoints[CIGlobals.OutdoorZone]},
     'cbhq': {'name': CIGlobals.CashbotHQ,
              'camera': (Point3(302.64, 5.0, 15.2), Vec3(135.0, 341.57, 0.0)),
              'model': 'phase_10/models/cogHQ/CashBotShippingStation.bam',
              'sky': None,
              'spawn_points': hoodMgr.dropPoints[CIGlobals.CashbotHQ]}}
    SkyData = {'TT': 'phase_3.5/models/props',
     'MM': 'phase_6/models/props',
     'cog': 'phase_9/models/cogHQ',
     'MovingSkies': ['TT']}

    def __init__(self):
        self.levelName = None
        self.dnaStore = DNAStorage()
        self.loadingText = None
        self.levelGeom = None
        self.skyUtil = None
        self.skyModel = None
        self.momadaAreas = []
        self.momadaAreaName2areaModel = {}
        return

    def setLevel(self, level):
        self.levelName = level

    def getLevel(self):
        return self.levelName

    def getCameraOfCurrentLevel(self):
        return self.LevelData[self.getLevel()]['camera']

    def getSpawnPoints(self):
        pointData = self.LevelData[self.levelName]['spawn_points']
        if self.levelName == 'momada':
            return pointData
        else:
            array = []
            for posAndHpr in pointData:
                array.append((Point3(posAndHpr[0], posAndHpr[1], posAndHpr[2]), Vec3(posAndHpr[3], posAndHpr[4], posAndHpr[5])))

            return array

    def getNameOfCurrentLevel(self):
        return self.LevelData[self.getLevel()]['name']

    def load(self):
        self.unload()
        if self.loadingText:
            self.loadingText.destroy()
            self.loadingText = None
        self.loadingText = OnscreenText(text='Loading ' + self.getNameOfCurrentLevel() + '...', font=CIGlobals.getMinnieFont(), fg=(1, 1, 1, 1))
        self.loadingText.setBin('gui-popup', 0)
        base.graphicsEngine.renderFrame()
        base.graphicsEngine.renderFrame()
        if self.levelName == 'momada':
            self.__momadaLoad()
        elif self.levelName in ('cbhq',):
            modelPath = self.LevelData[self.levelName]['model']
            self.levelGeom = loader.loadModel(modelPath)
            self.levelGeom.flattenMedium()
            self.levelGeom.reparentTo(render)
            if self.LevelData[self.levelName]['sky'] != None:
                self.skyModel = loader.loadModel(self.SkyData['cog'] + '/cog_sky.bam')
                self.skyUtil = SkyUtil()
                self.skyUtil.startSky(self.skyModel)
                self.skyModel.reparentTo(render)
        else:
            dnaFiles = self.LevelData[self.levelName]['dna']
            skyType = self.LevelData[self.levelName]['sky']
            skyPhase = self.SkyData[skyType]
            loader.loadDNAFile(self.dnaStore, 'phase_4/dna/storage.dna')
            for index in range(len(dnaFiles)):
                if index == len(dnaFiles) - 1:
                    node = loader.loadDNAFile(self.dnaStore, dnaFiles[index])
                    if node.getNumParents() == 1:
                        self.levelGeom = NodePath(node.getParent(0))
                        self.levelGeom.reparentTo(hidden)
                    else:
                        self.levelGeom = hidden.attachNewNode(node)
                    self.levelGeom.flattenMedium()
                    gsg = base.win.getGsg()
                    if gsg:
                        self.levelGeom.prepareScene(gsg)
                    self.levelGeom.reparentTo(render)
                else:
                    loader.loadDNAFile(self.dnaStore, dnaFiles[index])

            self.skyModel = loader.loadModel(skyPhase + '/' + skyType + '_sky.bam')
            self.skyUtil = SkyUtil()
            self.skyUtil.startSky(self.skyModel)
            self.skyModel.reparentTo(camera)
            ce = CompassEffect.make(NodePath(), CompassEffect.PRot | CompassEffect.PZ)
            self.skyModel.node().setEffect(ce)
        if self.loadingText:
            self.loadingText.destroy()
            self.loadingText = None
        return

    def __momadaLoad(self):

        def attachArea(itemNum):
            name = 'MomadaArea-%s' % itemNum
            area = self.momadaAreaName2areaModel.get(name)
            parents = self.LevelData['momada']['parents']
            parent = parents[itemNum]
            if type(parent) == type(''):
                parent = self.momadaAreas[itemNum - 1].find('**/' + parent)
            pos = self.LevelData['momada']['model_positions'][itemNum]
            hpr = self.LevelData['momada']['model_orientations'][itemNum]
            area.reparentTo(parent)
            area.setPos(pos)
            area.setHpr(hpr)

        _numItems = 0
        name = None
        for item in self.LevelData['momada']['models']:
            name = 'MomadaArea-%s' % _numItems
            area = loader.loadModel(item)
            self.momadaAreas.append(area)
            self.momadaAreaName2areaModel[name] = area
            attachArea(_numItems)
            _numItems += 1
            self.notify.info('Loaded and attached %s momada areas.' % _numItems)

        return

    def unload(self):
        if self.levelName == 'momada':
            for area in self.momadaAreas:
                self.momadaAreas.remove(area)
                area.removeNode()
                del area

            self.momadaAreas = []
            self.momadaAreaName2areaModel = {}
        else:
            if self.skyUtil:
                self.skyUtil.stopSky()
                self.skyUtil = None
            if self.skyModel:
                self.skyModel.removeNode()
                self.skyModel = None
            if self.levelGeom:
                self.levelGeom.removeNode()
                self.levelGeom = None
        return

    def cleanup(self):
        self.momadaAreas = None
        self.momadaAreaName2areaModel = None
        self.dnaStore.resetAll()
        self.dnaStore = None
        return
Esempio n. 8
0
class ChoiceWidget(DirectFrame):
    notify = directNotify.newCategory("ChoiceWidget")

    def __init__(self,
                 parent,
                 options,
                 pos=(0, 0, 0),
                 command=None,
                 widgetName="",
                 choiceTextScale=0.08,
                 desc="",
                 settingKeyName=None,
                 mode=AUTO,
                 requirement=None):
        """ 
        Generates an ordered choice widget with the specified parameters.
        
        Parameters:
        
        parent: Pretty much self-explanatory, this is the parent of the widget.
        If an object with a `book` attribute is passed in, it will use that instead.
        
        options: A list of options that the user can select with the GUI.
        
        pos: Pretty much self-explanatory.
        
        command: Function that should be executed whenever a game setting is updated.
        The newly saved choice is passed to the specified function.
        
        widgetName: The label shown to the left of the widget identifying what the widget
        is for.
        
        choiceTextScale: The scale of the text which displays which option the user has
        currently selected.
        
        desc: Optional description of what the choices displayed by this widget are for.
        
        settingKeyName: The name of the key inside of the game settings map that this choice
        widget works with. This MUST be set if trying to simulate a game setting changer widget.
        
        mode: This is the kind of widget this is going to be. Use one of the following:
            - AUTO:
                - The system will attempt to figure out what the type of choices are available.
                    * 2 options automatically looks like a true/false widget *
            - MULTICHOICE:
                - This overrides the system in case there are two options but true/false functionality
                isn't wanted.
            - DEGREE:
                - This means that the choice widget deals with x in front of some sort of degree value that should
                - be stripped away when selecting choices. This is used for the antialiasing choice widget.
        
        """
        self.requirement = requirement
        self.options = options
        self.command = command
        self.currentChoiceIndex = 0
        self.origChoice = None
        self.userChoice = None
        self.settingKeyName = settingKeyName
        self.mode = mode

        # Let's update the options if we specified a setting key name.
        if self.settingKeyName and len(self.settingKeyName) > 0:
            settingsMgr = CIGlobals.getSettingsMgr()
            settingInst = settingsMgr.getSetting(self.settingKeyName)

            if not settingInst:
                raise ValueError("Setting \"{0}\" could not be found!".format(
                    self.settingKeyName))
            else:
                self.options = settingInst.getOptions()
                desc = settingInst.getDescription()

        widgetParent = parent
        if hasattr(parent, 'book'):
            widgetParent = parent.book

        DirectFrame.__init__(self, parent=widgetParent, pos=pos)

        bg = loader.loadModel('phase_3/models/gui/ChatPanel.bam')

        self.selFrame = DirectFrame(pos=(0.4, 0, 0),
                                    frameColor=(1.0, 1.0, 1.0, 1.0),
                                    image=bg,
                                    relief=None,
                                    image_scale=(0.22, 0.11, 0.11),
                                    image_pos=(-0.107, 0.062, 0.062),
                                    parent=self)

        self.choiceText = OnscreenText(text="Hello!",
                                       align=TextNode.ACenter,
                                       parent=self.selFrame,
                                       pos=(0, -0.01),
                                       scale=choiceTextScale)
        self.fwdBtn = CIGlobals.makeDirectionalBtn(1,
                                                   self.selFrame,
                                                   pos=(0.2, 0, 0),
                                                   command=self.__goFwd)
        self.bckBtn = CIGlobals.makeDirectionalBtn(0,
                                                   self.selFrame,
                                                   pos=(-0.2, 0, 0),
                                                   command=self.__goBck)

        self.lbl = OnscreenText(text=widgetName + ":",
                                pos=(-0.7, 0, 0),
                                align=TextNode.ALeft,
                                parent=self)

        if len(desc) > 0:
            self.desc = OnscreenText(text=desc,
                                     pos=(0.0, -0.1, 0.0),
                                     parent=self.selFrame,
                                     scale=0.05,
                                     bg=DESC_BACKGROUND_COLOR,
                                     mayChange=False)
            self.desc.setBin('gui-popup', 40)
            self.desc.hide()

            # Let's bind our events on the selection frame for the description.
            self.selFrame['state'] = DGG.NORMAL
            self.selFrame.bind(DGG.ENTER,
                               self.__setDescVisible,
                               extraArgs=[True])
            self.selFrame.bind(DGG.EXIT,
                               self.__setDescVisible,
                               extraArgs=[False])

        self.initialiseoptions(ChoiceWidget)

        self.reset()

        bg.detachNode()
        del bg

    def reset(self):
        """ Resets the selected choice to the very first option, or, if representing choices for a game setting,
        resets the widget to the currently saved setting. """

        # The index of the original display choice.
        destIndex = 0

        if self.settingKeyName:
            # This widget is supposed to be used to change game settings. Let's lookup the currently saved game setting.
            self.origChoice = self.__getCurrentSetting().getValue()

            try:
                if self.mode == DEGREE and not self.origChoice == 0:
                    destIndex = self.options.index('x{0}'.format(
                        str(self.origChoice)))
                elif (self.mode == AUTO
                      and len(self.options) == 2) or isinstance(
                          self.origChoice, (int, long)):
                    destIndex = int(self.origChoice)
                elif isinstance(self.origChoice, (list, tuple)):
                    destIndex = self.options.index('{0}x{1}'.format(
                        str(self.origChoice[0]), str(self.origChoice[1])))
                elif self.origChoice in self.options:
                    destIndex = self.options.index(self.origChoice)
                elif self.origChoice.title() in self.options:
                    destIndex = self.options.index(self.origChoice.title())
            except:
                # We couldn't determine the right index for the original choice. Let's ignore any errors and default
                # to the very first choice when we reset.
                pass
        else:
            # If this widget is not being used to simulate changing game settings, let's use the first value in options as the original choice.
            self.origChoice = self.options[0]
        self.userChoice = self.origChoice
        self.goto(destIndex)

    def saveSetting(self):
        """ If `settingKeyName` was set, this updates the game setting key with the choice selected with the widget. However, 
        if `settingKeyName` was not set, it will send the command specified with the current user choice. """
        willUpdateChoice = (self.userChoice != self.origChoice)
        if self.settingKeyName and willUpdateChoice:
            settingInst = CIGlobals.getSettingsMgr().getSetting(
                self.settingKeyName)

            if settingInst:
                settingInst.setValue(self.userChoice)

            self.reset()

        if self.command and willUpdateChoice:
            # Let's send the command with the newly saved choice.
            self.command(self.userChoice)

    def __getCurrentSetting(self):
        return CIGlobals.getSettingsMgr().getSetting(self.settingKeyName)

    def __setDescVisible(self, visible, _):
        if visible:
            CIGlobals.getRolloverSound().play()
            self.desc.show()
        else:
            self.desc.hide()

    def cleanup(self):
        if hasattr(self, 'choiceText'):
            self.choiceText.destroy()
            del self.choiceText
        if hasattr(self, 'fwdBtn'):
            self.fwdBtn.destroy()
            del self.fwdBtn
        if hasattr(self, 'bckBtn'):
            self.bckBtn.destroy()
            del self.bckBtn
        if hasattr(self, 'lbl'):
            self.lbl.destroy()
            del self.lbl
        if hasattr(self, 'selFrame'):
            self.selFrame.destroy()
            del self.selFrame
        if hasattr(self, 'desc'):
            self.desc.destroy()
            del self.desc
        del self.options
        del self.command
        del self.currentChoiceIndex
        del self.settingKeyName
        del self.origChoice
        del self.userChoice
        del self.mode
        del self.requirement
        self.destroy()

    def goto(self, index):
        self.currentChoiceIndex = index
        self.updateDirectionalBtns()
        self.__setCurrentData(False)

    def __setCurrentData(self, doCmd=True):
        self.choiceText.setText(self.options[self.currentChoiceIndex])
        if (doCmd):

            # Let's update the internal user choice.
            if self.mode == AUTO and len(self.options) == 2:
                # If we only have two options, we must be working with on/off choices.
                self.userChoice = bool(self.currentChoiceIndex)
            elif self.mode == INDEX:
                self.userChoice = self.currentChoiceIndex
            elif self.mode == DEGREE or self.mode == RESOLUTION:
                # We're working with either a degree based option or a resolution option.
                data = self.options[self.currentChoiceIndex].split('x')

                if CIGlobals.isEmptyString(data[0]):
                    # This is a degree-based option.
                    if self.currentChoiceIndex != 0:
                        self.userChoice = int(data[1])
                    else:
                        self.userChoice = 0
                else:
                    # This is a screen resolution option.
                    self.userChoice = [int(data[0]), int(data[1])]
            else:
                self.userChoice = self.options[self.currentChoiceIndex]

    def updateDirectionalBtns(self):
        if self.requirement and callable(self.requirement):
            if not self.requirement():
                # The requirement to modify this choice widget was not met.
                for btn in [self.fwdBtn, self.bckBtn]:
                    btn['state'] = DGG.DISABLED
                    btn.setColorScale(DISABLED_COLOR)
                return

        self.fwdBtn['state'] = DGG.NORMAL
        self.bckBtn['state'] = DGG.NORMAL
        self.fwdBtn.setColorScale(1, 1, 1, 1)
        self.bckBtn.setColorScale(1, 1, 1, 1)
        if self.currentChoiceIndex == 0:
            self.bckBtn['state'] = DGG.DISABLED
            self.bckBtn.setColorScale(DISABLED_COLOR)
        elif self.currentChoiceIndex == len(self.options) - 1:
            self.fwdBtn['state'] = DGG.DISABLED
            self.fwdBtn.setColorScale(DISABLED_COLOR)

    def __goFwd(self):
        if self.currentChoiceIndex < len(self.options) - 1:
            self.currentChoiceIndex += 1
            self.__setCurrentData()
        self.updateDirectionalBtns()

    def __goBck(self):
        if self.currentChoiceIndex > 0:
            self.currentChoiceIndex -= 1
            self.__setCurrentData()
        self.updateDirectionalBtns()
Esempio n. 9
0
class ToonPanel(DirectFrame):
    notify = directNotify.newCategory('ToonPanel')
    animal2HeadData = {'dog': (0.125, 0.04),
     'duck': (0.1, 0.025),
     'cat': (0.115, 0.04),
     'rabbit': (0.115, 0.04),
     'horse': (0.115, 0.06),
     'monkey': (0.115, 0.06),
     'pig': (0.115, 0.07),
     'mouse': (0.09, 0.02),
     'bear': (0.125, 0.05)}
    State2Text = {'status': ('Seeing if %s is available...', '%s is busy right now; try again later.'),
     'teleport': ('Trying to go to %s...', 'Could not go to %s.'),
     'friend': ('Asking %s to be your friend...', '%s said no, thank you.', 'You are now friends with %s!'),
     'remove': ('Are you sure you want to remove %s from your friends list?', '%s left your friends list.')}

    def __init__(self):
        DirectFrame.__init__(self, scale=1.2)
        self['image'] = DGG.getDefaultDialogGeom()
        self['image_hpr'] = (0, 0, -90)
        self['image_scale'] = (0.62, 0.9, 0.325)
        self['image_color'] = (1, 1, 0.75, 1)
        self['image_pos'] = (0, 0, -0.065)
        self['relief'] = None
        self.reparentTo(base.a2dTopRight)
        self.setPos(-0.235, 0.0, -0.325)
        self.hide()
        self.head = None
        self.laffMeter = None
        self.exitButton = None
        self.friendButton = None
        self.teleportButton = None
        self.nameText = None
        self.actionFrame = None
        self.actionFrameText = None
        self.actionFrameButton = None
        self.actionFrameButton2 = None
        self.avatarInfo = None
        self.action = None
        self.fsm = ClassicFSM.ClassicFSM('ToonPanel', [State.State('off', self.enterOff, self.exitOff), State.State('waitOnAvatarInfoResponse', self.enterWaitOnAvatarInfoResponse, self.exitWaitOnAvatarInfoResponse, ['panel']), State.State('panel', self.enterPanel, self.exitPanel, ['off'])], 'off', 'off')
        self.fsm.enterInitialState()
        self.actionFSM = ClassicFSM.ClassicFSM('ToonPanelActionFSM', [State.State('off', self.enterOff, self.exitOff),
         State.State('waitOnAvatarStatusResponse', self.enterWaitOnAvatarStatusResponse, self.exitWaitOnAvatarStatusResponse, ['waitOnAvatarTeleportResponse',
          'waitOnAvatarFriendListResponse',
          'avatarBusy',
          'off']),
         State.State('avatarBusy', self.enterAvatarBusy, self.exitAvatarBusy, ['off']),
         State.State('waitOnAvatarTeleportResponse', self.enterWaitOnAvatarTeleportResponse, self.exitWaitOnAvatarTeleportResponse, ['unableToTP']),
         State.State('unableToTP', self.enterUnableToTP, self.exitUnableToTP, ['off']),
         State.State('waitOnAvatarFriendListResponse', self.enterWaitOnAvatarFriendListResponse, self.exitWaitOnAvatarFriendListResponse, ['fRequestA', 'fRequestR']),
         State.State('fRequestA', self.enterFriendRequestAccepted, self.exitFriendRequestAccepted, ['off']),
         State.State('fRequestR', self.enterFriendRequestRejected, self.exitFriendRequestRejected, ['off']),
         State.State('removeFriendConfirm', self.enterRemoveFriendConfirm, self.exitRemoveFriendConfirm, ['off', 'removedFriend']),
         State.State('removedFriend', self.enterRemovedFriend, self.exitRemovedFriend, ['off'])], 'off', 'off')
        self.actionFSM.enterInitialState()
        return

    def maybeUpdateFriendButton(self):
        if self.friendButton:
            if self.avatarInfo:
                if self.avatarInfo[0] not in base.localAvatar.friends:
                    self.friendButton['text'] = 'Add Friend'
                    self.friendButton['extraArgs'] = ['waitOnAvatarFriendListResponse']
                else:
                    self.friendButton['text'] = 'Remove Friend'
                    self.friendButton['extraArgs'] = ['removeFriendConfirm']

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterUnableToTP(self):
        pass

    def exitUnableToTP(self):
        pass

    def enterWaitOnAvatarTeleportResponse(self):
        self.setActionText(self.State2Text['teleport'][0] % self.getAvatarName())
        self.makeButtons('Cancel')
        self.acceptOnce('gotAvatarTeleportResponse', self.handleTeleportResponse)
        base.cr.friendsManager.d_iWantToTeleportToAvatar(self.avatarInfo[0])

    def handleTeleportResponse(self, avatarId, shardId, zoneId):
        if self.avatarInfo[0] == avatarId:
            requestStatus = {}
            whereName = ZoneUtil.getWhereName(zoneId)
            loaderName = ZoneUtil.getLoaderName(zoneId)
            requestStatus['zoneId'] = zoneId
            if base.localAvatar.parentId == shardId:
                requestStatus['shardId'] = None
            else:
                requestStatus['shardId'] = shardId
            requestStatus['hoodId'] = ZoneUtil.getHoodId(zoneId, 1)
            requestStatus['where'] = whereName
            requestStatus['loader'] = loaderName
            requestStatus['how'] = 'teleportIn'
            requestStatus['avId'] = avatarId
            base.cr.playGame.getPlace().fsm.request('teleportOut', [requestStatus])
            self.cleanup()
        return

    def exitWaitOnAvatarTeleportResponse(self):
        self.ignore('gotAvatarTeleportResponse')
        self.clearActionText()
        self.clearActionButtons()

    def setActionText(self, text):
        self.actionFrameText.setText(text)

    def clearActionText(self):
        self.actionFrameText.setText('')

    def makeButtons(self, button1, button2 = None):
        button2GeomFunc = {'Cancel': CIGlobals.getCancelBtnGeom,
         'No': CIGlobals.getCancelBtnGeom,
         'Okay': CIGlobals.getOkayBtnGeom,
         'Yes': CIGlobals.getOkayBtnGeom}
        if button1 and not button2:
            button1Pos = (0, 0, -0.1)
        elif button1 and button2:
            button1Pos = (-0.1, 0, -0.1)
        button2Pos = (0.1, 0, -0.1)
        if button1:
            self.actionFrameButton = DirectButton(text=button1, geom=button2GeomFunc[button1](), parent=self.actionFrame, pos=button1Pos, text_scale=0.045, text_pos=(0, -0.08), command=self.actionButtonPressed, extraArgs=[1], relief=None, geom_scale=0.75)
        if button2:
            self.actionFrameButton2 = DirectButton(text=button2, geom=button2GeomFunc[button2](), parent=self.actionFrame, pos=button2Pos, text_scale=0.045, text_pos=(0, -0.08), command=self.actionButtonPressed, extraArgs=[2], relief=None, geom_scale=0.75)
        return

    def actionButtonPressed(self, buttonNum):
        currentState = self.actionFSM.getCurrentState().getName()
        if buttonNum == 1:
            if currentState in ('waitOnAvatarStatusResponse', 'waitOnAvatarTeleportResponse', 'waitOnAvatarFriendListResponse', 'avatarBusy', 'unableToTP', 'fRequestA', 'fRequestR', 'removeFriendConfirm', 'removedFriend'):
                if currentState == 'waitOnAvatarFriendListResponse':
                    base.cr.friendsManager.d_iCancelledFriendRequest(self.avatarInfo[0])
                elif currentState == 'removeFriendConfirm':
                    self.actionFSM.request('removedFriend')
                    return
                self.actionFSM.request('off')
                self.removeActionPanel()
                self.action = None
        elif buttonNum == 2:
            self.actionFSM.request('off')
            self.removeActionPanel()
            self.action = None
        return

    def clearActionButtons(self):
        if self.actionFrameButton2:
            self.actionFrameButton2.destroy()
            self.actionFrameButton2 = None
        if self.actionFrameButton:
            self.actionFrameButton.destroy()
            self.actionFrameButton = None
        return

    def enterAvatarBusy(self):
        self.setActionText(self.State2Text['status'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitAvatarBusy(self):
        self.clearActionText()
        self.clearActionButtons()

    def getAvatarName(self):
        if self.avatarInfo:
            return self.avatarInfo[1]

    def enterWaitOnAvatarStatusResponse(self):
        self.acceptOnce('gotAvatarStatus', self.handleAvatarStatusResponse)
        base.cr.friendsManager.d_requestAvatarStatus(self.avatarInfo[0])
        self.setActionText(self.State2Text['status'][0] % self.getAvatarName())
        self.makeButtons('Cancel')

    def handleAvatarStatusResponse(self, avatarId, status):
        if avatarId == self.avatarInfo[0]:
            if status == 1:
                self.actionFSM.request('avatarBusy')
            else:
                self.actionFSM.request(self.action)
        else:
            self.acceptOnce('gotAvatarStatus', self.handleAvatarStatusResponse)

    def exitWaitOnAvatarStatusResponse(self):
        self.ignore('gotAvatarStatus')
        self.clearActionText()
        self.clearActionButtons()

    def enterWaitOnAvatarFriendListResponse(self):
        self.acceptOnce('friendRequestAccepted', self.handleFriendRequestAccepted)
        self.acceptOnce('friendRequestRejected', self.handleFriendRequestRejected)
        base.cr.friendsManager.d_askAvatarToBeFriends(self.avatarInfo[0])
        self.setActionText(self.State2Text['friend'][0] % self.getAvatarName())
        self.makeButtons('Cancel')

    def handleFriendRequestAccepted(self):
        self.actionFSM.request('fRequestA')

    def handleFriendRequestRejected(self):
        self.actionFSM.request('fRequestR')

    def exitWaitOnAvatarFriendListResponse(self):
        self.ignore('friendRequestAccepted')
        self.ignore('friendRequestRejected')
        self.clearActionText()
        self.clearActionButtons()

    def enterFriendRequestAccepted(self):
        self.setActionText(self.State2Text['friend'][2] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitFriendRequestAccepted(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterFriendRequestRejected(self):
        self.setActionText(self.State2Text['friend'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitFriendRequestRejected(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterRemoveFriendConfirm(self):
        self.setActionText(self.State2Text['remove'][0] % self.getAvatarName())
        self.makeButtons('Yes', 'No')

    def exitRemoveFriendConfirm(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterRemovedFriend(self):
        base.cr.friendsManager.d_iRemovedFriend(self.avatarInfo[0])
        self.setActionText(self.State2Text['remove'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitRemovedFriend(self):
        self.clearActionText()
        self.clearActionButtons()

    def makeActionPanel(self):
        self.actionFrame = DirectFrame(image=DGG.getDefaultDialogGeom(), image_scale=(0.7, 0.5, 0.45), image_color=(1, 1, 0.75, 1), relief=None)
        self.actionFrame.reparentTo(base.a2dTopRight)
        self.actionFrame.setPos(-0.815, 0, -0.31)
        self.actionFrameText = OnscreenText(text='', parent=self.actionFrame, scale=0.05, wordwrap=12, pos=(0, 0.1))
        return

    def removeActionPanel(self):
        self.clearActionButtons()
        if self.actionFrameText:
            self.actionFrameText.destroy()
            self.actionFrameText = None
        if self.actionFrame:
            self.actionFrame.destroy()
            self.actionFrame = None
        return

    def doAction(self, action):
        self.action = action
        self.actionFSM.requestFinalState()
        self.removeActionPanel()
        self.makeActionPanel()
        if action != 'removeFriendConfirm':
            self.actionFSM.request('waitOnAvatarStatusResponse')
        else:
            self.actionFSM.request(action)

    def enterWaitOnAvatarInfoResponse(self):
        self.label = OnscreenText(text='Retrieving Toon\ndetails...', parent=self, scale=0.04)
        self.acceptOnce('avatarInfoResponse', self.handleAvatarInfoResponse)
        base.cr.friendsManager.d_requestAvatarInfo(self.avatarInfo[0])

    def handleAvatarInfoResponse(self, name, dna, maxHealth, health):
        if self.avatarInfo:
            self.avatarInfo.append(name)
            self.avatarInfo.append(dna)
            self.avatarInfo.append(maxHealth)
            self.avatarInfo.append(health)
            self.fsm.request('panel')

    def exitWaitOnAvatarInfoResponse(self):
        self.label.destroy()
        del self.label
        self.ignore('avatarInfoResponse')

    def makePanel(self, avId):
        if self.avatarInfo:
            if self.avatarInfo[0] == avId:
                return
        self.cleanup()
        base.localAvatar.hideFriendButton()
        self.show()
        self.avatarInfo = []
        self.avatarInfo.append(avId)
        self.fsm.request('waitOnAvatarInfoResponse')

    def exitClicked(self):
        self.cleanup()
        base.localAvatar.showFriendButton()

    def cleanup(self):
        self.actionFSM.requestFinalState()
        self.fsm.requestFinalState()
        self.avatarInfo = None
        return

    def enterPanel(self):
        self.nameText = OnscreenText(text=self.avatarInfo[1], parent=self, pos=(0, 0.2), scale=0.035, wordwrap=8)
        self.nameText.setBin('gui-popup', 60)
        dna = ToonDNA.ToonDNA()
        dna.setDNAStrand(self.avatarInfo[2])
        self.head = ToonHead.ToonHead(base.cr)
        self.head.generateHead(dna.gender, dna.animal, dna.head, 1)
        self.head.setHeadColor(dna.headcolor)
        self.head.reparentTo(self)
        self.head.setDepthWrite(1)
        self.head.setDepthTest(1)
        self.head.setH(180)
        self.head.setScale(self.animal2HeadData[dna.animal][0])
        self.head.setZ(self.animal2HeadData[dna.animal][1])
        self.laffMeter = LaffOMeter()
        r, g, b, _ = dna.headcolor
        self.laffMeter.generate(r, g, b, dna.animal, self.avatarInfo[3], self.avatarInfo[4])
        self.laffMeter.reparentTo(self)
        self.laffMeter.setBin('gui-popup', 60)
        self.laffMeter.setScale(0.045)
        self.laffMeter.setPos(0, 0, -0.1)
        self.friendButton = DirectButton(geom=CIGlobals.getDefaultBtnGeom(), text='Add Friend', scale=0.58, relief=None, text_scale=0.058, geom_scale=(1.25, 0, 0.9), text_pos=(0, -0.0125), parent=self, pos=(0, 0, -0.12), command=self.doAction, extraArgs=['waitOnAvatarFriendListResponse'])
        self.friendButton.setPos(0, 0.0, -0.225)
        self.maybeUpdateFriendButton()
        self.teleportButton = DirectButton(geom=CIGlobals.getDefaultBtnGeom(), text='Teleport', scale=0.58, relief=None, text_scale=0.058, geom_scale=(1.25, 0, 0.9), text_pos=(0, -0.0125), parent=self, pos=(0, 0, -0.12), command=self.doAction, extraArgs=['waitOnAvatarTeleportResponse'])
        self.teleportButton.setPos(0, 0, -0.275)
        self.exitButton = DirectButton(geom=CIGlobals.getCancelBtnGeom(), parent=self, relief=None, scale=0.6, pos=(-0.127, 0.0, -0.3425), command=self.exitClicked)
        return

    def exitPanel(self):
        if self.actionFSM.getCurrentState().getName() == 'waitOnAvatarFriendListResponse':
            if self.avatarInfo:
                base.cr.friendsManager.d_iCancelledFriendRequest(self.avatarInfo[0])
        self.actionFSM.requestFinalState()
        self.action = None
        self.avatarInfo = None
        self.removeActionPanel()
        self.hide()
        if self.nameText:
            self.nameText.destroy()
            self.nameText = None
        if self.head:
            self.head.removeNode()
            self.head.delete()
            self.head = None
        if self.laffMeter:
            self.laffMeter.disable()
            self.laffMeter.delete()
            self.laffMeter = None
        if self.friendButton:
            self.friendButton.destroy()
            self.friendButton = None
        if self.teleportButton:
            self.teleportButton.destroy()
            self.teleportButton = None
        if self.exitButton:
            self.exitButton.destroy()
            self.exitButton = None
        return
class Credits(DirectObject):

    developers = {'Game Development': ['DuckyDuck1553', 'DecodedLogic']}
    webDevelopers = {
        'Web Development': ['totok', 'DuckyDuck1553', 'DecodedLogic']
    }
    artists = {
        'Artists': [
            'John L. (supertricky)', 'DuckyDuck1553', 'DecodedLogic',
            'Baru (fatigue)', 'Isabel (allyjean)', 'Colorblind', 'loonatic'
        ]
    }
    composers = {'Composers': ['Dylan J.', 'Doc. Dynamite', 'CBiard']}
    communityManager = {'Community Manager': ['Leo (Bradley)']}
    moderators = {
        'Moderation Team':
        ['Mark (Black & White)', 'Jackson M.', 'Gabriel A.', 'Davon M.']
    }
    specialThanks = {
        'Special Thanks': [
            'Jesse Schell', 'rdb', 'Baribal', 'ThomasEgi', 'tobspr',
            'jjkoletar', 'mmavipc', 'CFSWorks', 'loblao', 'HarvTarv',
            'Hawkheart', 'TheRandomDog', 'Joey Z. (joey19982)',
            'Disney Interactive', 'Microsoft', 'YorkeTheMouse', 'Disyer',
            '\n\n\nAnd of course, YOU!\n\n\n'
        ]
    }

    def __init__(self):
        DirectObject.__init__(self)

        base.setBackgroundColor(0, 0, 0)

        self.textParent = base.credits2d.attachNewNode('textParent')
        self.textParent.setBin("gui-popup", 61)
        self.textParent.setDepthWrite(False)
        self.textParent.setTransparency(True)

        self.logoImage = OnscreenImage('phase_3/maps/CogInvasion_Logo.png',
                                       parent=self.textParent,
                                       scale=(0.685, 1.0, 0.325))
        self.logoImage.setTransparency(1)

        text = self.buildCreditsText()
        self.creditsText = OnscreenText(parent=self.textParent,
                                        font=CIGlobals.getToonFont(),
                                        fg=(1, 1, 1, 1),
                                        scale=0.065,
                                        pos=(0, -0.5, 0),
                                        text=text,
                                        shadow=(0, 0, 0, 1))

        self.posInterval = None

        self.backgroundImg = OnscreenImage('phase_3/maps/credits_fade.png',
                                           parent=render2d)
        self.backgroundImg.setTransparency(True)
        self.backgroundImg.setColor(0, 0, 0, 1.0)
        self.backgroundImg.setBin("gui-popup", 62)
        self.backgroundImg.setDepthWrite(False)

        self.exitText = OnscreenText(parent=base.credits2d,
                                     font=CIGlobals.getToonFont(),
                                     fg=(1.0, 0, 0, 1.0),
                                     shadow=(0, 0, 0, 1),
                                     scale=0.085,
                                     pos=(0, -0.96, 0),
                                     text='Press any key to exit')
        self.exitText.hide()
        self.exitText.setBin("gui-popup", 63)
        self.exitText.setDepthWrite(False)
        self.exitText.setTransparency(True)

        self.creditsAudioMgr = AudioManager.createAudioManager()
        self.creditsAudioMgr.setVolume(0.65)
        self.bgm = self.creditsAudioMgr.getSound(
            'phase_4/audio/bgm/new_years_fireworks_music.ogg')

    def buildCreditsText(self):
        def writeNames(message, namesList):
            for name in namesList:
                message = '%s%s\n' % (message, name)
            return message

        message = 'Cog Invasion Online\n{0}\n'.format(
            metadata.getBuildInformation())
        message += '\nCREDITS\n\n'

        # Write the game developers' names
        message += 'Programming\n\n'
        message += '%s\n' % self.developers.keys()[0]
        message = writeNames(message, self.developers.values()[0])
        message += '\n\n'

        # Write the web developers' names
        message += '%s\n' % self.webDevelopers.keys()[0]
        message = writeNames(message, self.webDevelopers.values()[0])

        # Let's begin the art section
        message += '\n\nArt\n\n'

        # Write the artists' names
        message += '%s\n' % self.artists.keys()[0]
        message = writeNames(message, self.artists.values()[0])

        message += '\n\n'

        # Write the composers' names
        message += '%s\n' % self.composers.keys()[0]
        message = writeNames(message, self.composers.values()[0])

        ##########################################
        # Let's begin the community section.
        message += '\n\nCommunity\n\n'

        # Write the community manager names
        message += '%s\n' % self.communityManager.keys()[0]
        message = writeNames(message, self.communityManager.values()[0])
        message += '\n\n'

        # Write the moderators' names
        message += '%s\n' % self.moderators.keys()[0]
        message = writeNames(message, self.moderators.values()[0])

        # Let's begin the Special Thanks section.
        message += '\n\n'

        # Write the special thanks' names
        message += '%s\n' % self.specialThanks.keys()[0]
        message = writeNames(message, self.specialThanks.values()[0])
        message += '\nWe thank the original Toontown Online team.\nNot only for the game, but for the memories.'
        message += "\n\n\n\n\"Don't cry because it's over.\nSmile because it happened.\"\n  - Dr. Seuss"

        return message

    def exit(self, key):
        self.__fadeOut()
        base.taskMgr.doMethodLater(1.1, self.__exitTask, "exitTask")

    def __exitTask(self, task):
        messenger.send('credits-Complete')
        self.ignoreAll()
        self.destroy()
        base.unMuteMusic()
        base.unMuteSfx()
        base.setBackgroundColor(0.05, 0.15, 0.4)
        base.transitions.fadeIn(1.0)
        return task.done

    def watchTextPosition(self, task):
        if self.textParent.getZ() >= 5.187:
            self.exitText.show()
            self.acceptOnce('button', self.exit)
            return task.done
        return task.cont

    def __fadeIn(self):
        Parallel(
            LerpColorScaleInterval(self.textParent, 1.0, (1, 1, 1, 1),
                                   (1, 1, 1, 0)),
            LerpColorScaleInterval(self.backgroundImg, 1.0, (1, 1, 1, 1),
                                   (1, 1, 1, 0)),
            LerpColorScaleInterval(self.exitText, 1.0, (1, 1, 1, 1),
                                   (1, 1, 1, 0))).start()

    def __fadeOut(self):
        Parallel(
            LerpColorScaleInterval(self.textParent, 1.0, (1, 1, 1, 0),
                                   (1, 1, 1, 1)),
            LerpColorScaleInterval(self.backgroundImg, 1.0, (1, 1, 1, 0),
                                   (1, 1, 1, 1)),
            LerpColorScaleInterval(self.exitText, 1.0, (1, 1, 1, 0),
                                   (1, 1, 1, 1))).start()

    def setup(self):
        self.__fadeIn()

        b3 = self.textParent.getTightBounds()
        dimensions = b3[1] - b3[0]
        self.posInterval = self.textParent.posInterval(
            50, Point3(0, 0, dimensions[2] + 2), Point3(0, 0, 0))
        self.posInterval.start()

        self.bgm.setLoop(1)
        self.bgm.play()

        base.buttonThrowers[0].node().setButtonDownEvent('button')
        taskMgr.add(self.watchTextPosition, 'Watch Text Position')

    def destroy(self):
        if self.posInterval:
            self.posInterval.pause()
            self.posInterval = None
        if self.bgm:
            self.bgm.stop()
            self.bgm = None
        if self.backgroundImg:
            self.backgroundImg.destroy()
            self.backgroundImg = None
        if self.creditsText:
            self.creditsText.destroy()
            self.creditsText = None
        if self.exitText:
            self.exitText.destroy()
            self.exitText = None
        if self.logoImage:
            self.logoImage.destroy()
            self.logoImage = None
        if self.textParent:
            self.textParent.removeNode()
            self.textParent = None
        if self.creditsAudioMgr:
            self.creditsAudioMgr.stopAllSounds()
            self.creditsAudioMgr = None
        self.developers = None
        self.webDevelopers = None
        self.artists = None
        self.specialThanks = None
        self.composers = None
        self.communityManager = None
        self.moderators = None
        self.prevMusic = None
class GunGameLevelLoader:
    notify = directNotify.newCategory("GunGameLevelLoader")

    LevelData = {
        # momada means: Mix Of Mint And District Attorney's
        'momada': {
            'name': ZoneUtil.ToonBattleOriginalLevel,
            'camera': (Point3(0.0, -25.80, 7.59), Vec3(0.00, 0.00, 0.00)),
            'models': [
                "phase_11/models/lawbotHQ/LB_Zone03a.bam",
                "phase_11/models/lawbotHQ/LB_Zone04a.bam",
                "phase_11/models/lawbotHQ/LB_Zone7av2.bam",
                "phase_11/models/lawbotHQ/LB_Zone08a.bam",
                "phase_11/models/lawbotHQ/LB_Zone13a.bam",
                "phase_10/models/cashbotHQ/ZONE17a.bam",
                "phase_10/models/cashbotHQ/ZONE18a.bam",
                "phase_11/models/lawbotHQ/LB_Zone22a.bam"
            ],
            'parents': [
                render,
                "EXIT",
                "EXIT",
                "EXIT",
                "ENTRANCE",
                "ENTRANCE",
                "ENTRANCE",
                "EXIT"
            ],
            'model_positions': [
                Point3(0.00, 0.00, 0.00),
                Point3(-1.02, 59.73, 0.00),
                Point3(0.00, 74.77, 0.00),
                Point3(0.00, 89.37, -13.50),
                Point3(16.33, -136.53, 0.00),
                Point3(-1.01, -104.40, 0.00),
                Point3(0.65, -23.86, 0.00),
                Point3(-55.66, -29.01, 0.00)
            ],
            'model_orientations': [
                Vec3(0.00, 0.00, 0.00),
                Vec3(0.00, 0.00, 0.00),
                Vec3(90.00, 0.00, 0.00),
                Vec3(180.00, 0.00, 0.00),
                Vec3(97.00, 0.00, 0.00),
                Vec3(359.95, 0.00, 0.00),
                Vec3(90.00, 0.00, 0.00),
                Vec3(270.00, 0.00, 0.00)
            ],
            'spawn_points': [
                (Point3(0, 0, 0), Vec3(0, 0, 0)),
                (Point3(-20, 50, 0), Vec3(0, 0, 0)),
                (Point3(20, 50, 0), Vec3(0, 0, 0)),
                (Point3(0, 120, 0), Vec3(0, 0, 0)),
                (Point3(0, 100, 0), Vec3(180, 0, 0)),
                (Point3(-90, 0, 0), Vec3(0, 0, 0)),
                (Point3(-170, 0, 0), Vec3(0, 0, 0)),
                (Point3(-90, 50, 0), Vec3(0, 0, 0)),
                (Point3(-170, 50, 0), Vec3(0, 0, 0)),
                (Point3(35, 250, 0), Vec3(-90, 0, 0)),
                (Point3(0, 285, 0), Vec3(180, 0, 0)),
                (Point3(-185, 250, 0), Vec3(90, 0, 0))
            ]
        },

        'dg': {
            'name': ZoneUtil.DaisyGardens,
            'camera': (Point3(-33.13, -3.20, 48.62), Vec3(326.31, 332.68, 0.00)),
            'dna': [
                'phase_8/dna/storage_DG.pdna',
                'phase_8/dna/storage_DG_sz.pdna',
                'phase_8/dna/daisys_garden_sz.pdna'
            ],
            'sky': 'TT',
            'spawn_points': hoodMgr.dropPoints[ZoneUtil.DaisyGardens]
        },

        'mml': {
            'name': ZoneUtil.MinniesMelodyland,
            'camera': (Point3(-54.42, -91.05, 34.89), Vec3(315.29, 336.80, 0.00)),
            'dna': [
                'phase_6/dna/storage_MM.pdna',
                'phase_6/dna/storage_MM_sz.pdna',
                'phase_6/dna/minnies_melody_land_sz.pdna'
            ],
            'sky': 'MM',
            'spawn_points': hoodMgr.dropPoints[ZoneUtil.MinniesMelodyland]
        },

        'oz': {
            'name': ZoneUtil.OutdoorZone,
            'camera': (Point3(-54.42, -91.05, 34.89), Vec3(315.29, 336.80, 0.00)),
            'dna': [
                'phase_6/dna/storage_OZ.pdna',
                'phase_6/dna/storage_OZ_sz.pdna',
                'phase_6/dna/outdoor_zone_sz.pdna'
            ],
            'sky': 'TT',
            'spawn_points': hoodMgr.dropPoints[ZoneUtil.OutdoorZone]
        },

        'cbhq': {
            'name': ZoneUtil.CashbotHQ,
            'camera': (Point3(302.64, 5.00, 15.20), Vec3(135.00, 341.57, 0.00)),
            'model': 'phase_10/models/cogHQ/CashBotShippingStation.bam',
            'sky': None,
            'spawn_points': hoodMgr.dropPoints[ZoneUtil.CashbotHQ]
        },

        'sbf': {
            'name': ZoneUtil.SellbotFactory,
            'camera': (Point3(0, 0, 0), Vec3(0, 0, 0)),
            'model': "phase_9/models/cogHQ/SelbotLegFactory.bam",
            'sky': 'cog',
            'sky_scale': 10.0,
            'occluders': 'phase_9/models/cogHQ/factory_sneak_occluders.egg',
            'spawn_points': {GGG.Teams.BLUE: [
                    (Point3(13, 30, 3.73), Point3(0, 0, 0)), (Point3(21, 30, 3.73), Point3(0, 0, 0)), (Point3(29, 30, 3.73), Point3(0, 0, 0)),
                    (Point3(13, 20, 3.73), Point3(0, 0, 0)), (Point3(21, 20, 3.73), Point3(0, 0, 0)), (Point3(29, 30, 3.73), Point3(0, 0, 0))],
                GGG.Teams.RED: [
                    (Point3(-644.43, 378.12, 8.73), Point3(270, 0, 0)), (Point3(-644.43, 370.75, 8.73), Point3(270, 0, 0)), (Point3(-644.43, 363.22, 8.73), Point3(270, 0, 0)),
                    (Point3(-659.05, 378.12, 8.73), Point3(270, 0, 0)), (Point3(-659.05, 370.75, 8.73), Point3(270, 0, 0)), (Point3(-659.05, 363.22, 8.73), Point3(270, 0, 0))]
            },
            'flag_points': {GGG.Teams.BLUE: [Point3(213.23, 340.59, 19.73), Point3(90, 0, 0)],
                GGG.Teams.RED: [Point3(-543.60, 595.79, 9.73), Point3(270, 0, 0)]},
            'flagpoint_points': {GGG.Teams.BLUE: [Point3(-543.60, 595.79, 9.73), Point3(270, 0, 0)],
                GGG.Teams.RED: [Point3(213.23, 340.59, 19.73), Point3(0, 0, 0)]}
        },
        
        'ttc' : {
            'name' : ZoneUtil.ToontownCentral,
            'dna' : [
                'phase_4/dna/storage_TT.pdna',
                'phase_4/dna/storage_TT_sz.pdna',
                'phase_4/dna/new_ttc_sz.pdna',
            ],
            'sky' : 'TT',
            'spawn_points' : [
                (9.90324401855, 91.9139556885, 8.0364112854, -545.909545898, 0.0, 0.0),
                (77.9181442261, 50.953086853, 7.52815723419, -598.509460449, 0.0, 0.0),
                (93.7379760742, 6.37303066254, 7.99749088287, -626.209533691, 0.0, 0.0),
                (39.0383415222, -81.5989837646, 8.01874637604, -694.309265137, 0.0, 0.0),
                (-19.2093048096, -95.1359481812, 8.07303524017,  -731.409240723, 0.0, 0.0),
                (-84.4093933105, -45.4780502319, 8.06541728973, -781.809143066, 0.0, 0.0),
                (-92.2512283325, 2.41426730156, 8.03108692169, -811.70916748, 0.0, 0.0),
                (46.8868179321, 81.3593673706, 8.04793071747, -955.309509277, 0.0, 0.0),
                (32.3203735352, 90.0017929077, 8.06353855133, -884.409301758, 0.0, 0.0)
            ],
            'cap_point' : Point3(-1.5, 0, 0)
        }
    }

    SkyData = {
        'TT': 'phase_3.5/models/props',
        'MM': 'phase_6/models/props',
        'cog': 'phase_9/models/cogHQ',

        'MovingSkies': ['TT']
    }

    def __init__(self, mg):
        self.mg = mg
        self.levelName = None
        self.dnaStore = DNAStorage()
        self.loadingText = None

        # for not momada only:
        self.levelGeom = None
        self.olc = None
        self.occluders = None

        # for momada only:
        self.momadaAreas = []
        self.momadaAreaName2areaModel = {}

    def getFlagPoint_Point(self, team):
        return self.LevelData[self.levelName]['flagpoint_points'][team]

    def getFlagPoint(self, team):
        return self.LevelData[self.levelName]['flag_points'][team]
    
    def getCapturePoint(self):
        return self.LevelData[self.levelName]['cap_point']

    def setLevel(self, level):
        self.levelName = level

    def getLevel(self):
        return self.levelName

    def getCameraOfCurrentLevel(self):
        return self.LevelData[self.getLevel()]['camera']

    def getSpawnPoints(self):
        # Return the spawn points for this level.
        pointData = self.LevelData[self.levelName]['spawn_points']
        if self.levelName == "momada":
            return pointData
        else:
            if self.mg.gameMode in [GGG.GameModes.CASUAL, GGG.GameModes.KOTH]:
                # These points come from src.coginvasion.distributed.HoodMgr,
                # which is a tuple of a bunch of arrays with pos as first
                # 3, and hpr as last 3 list elements.
                #
                # Disect the arrays and return a tuple holding a Point3 pos, and a Vec3 hpr.
                array = []
                for posAndHpr in pointData:
                    array.append(
                        (
                            Point3(
                                posAndHpr[0],
                                posAndHpr[1],
                                posAndHpr[2]
                            ),

                            Vec3(
                                posAndHpr[3],
                                posAndHpr[4],
                                posAndHpr[5]
                            )
                        )
                    )
            elif self.mg.gameMode == GGG.GameModes.CTF:
                array = pointData[self.mg.team]
            return array

    def getNameOfCurrentLevel(self):
        return self.LevelData[self.getLevel()]['name']

    def load(self):
        self.unload()
        if self.loadingText:
            self.loadingText.destroy()
            self.loadingText = None
        self.loadingText = OnscreenText(text = "",
            font = CIGlobals.getMinnieFont(), fg = (1, 1, 1, 1))
        self.loadingText.setBin('gui-popup', 0)
        base.graphicsEngine.renderFrame()
        base.graphicsEngine.renderFrame()
        if self.levelName == "momada":
            # momada is completely different from the other levels,
            # so it has it's own separate method for loading.
            self.__momadaLoad()
        elif self.levelName in ['cbhq', 'sbf']:
            # Cog hqs are just one model with everything in it. no dna loading needed.
            modelPath = self.LevelData[self.levelName]['model']
            self.levelGeom = loader.loadModel(modelPath)
            self.levelGeom.flattenMedium()
            self.levelGeom.reparentTo(render)
            if self.LevelData[self.levelName].get('occluders'):
                self.occluders = loader.loadModel(self.LevelData[self.levelName]['occluders'])
                for occluderNode in self.occluders.findAllMatches('**/+OccluderNode'):
                    base.render.setOccluder(occluderNode)
                    occluderNode.node().setDoubleSided(True)
            if self.levelName == 'sbf':
                base.camLens.setFar(250)
        else:
            # It's a playground with dna and stuff. Just do the
            # normal loading procedure.
            dnaFiles = self.LevelData[self.levelName]['dna']
            loadDNAFile(self.dnaStore, 'phase_4/dna/storage.pdna')
            for index in range(len(dnaFiles)):
                if index == len(dnaFiles) - 1:
                    node = loadDNAFile(self.dnaStore, dnaFiles[index])
                    if node.getNumParents() == 1:
                        self.levelGeom = NodePath(node.getParent(0))
                        self.levelGeom.reparentTo(hidden)
                    else:
                        self.levelGeom = hidden.attachNewNode(node)
                    if self.levelName == 'ttc' and dnaFiles[index] == 'phase_4/dna/new_ttc_sz.pdna':
                        self.levelGeom.find('**/prop_gazebo_DNARoot').removeNode()
                    else:
                        self.levelGeom.flattenMedium()
                    gsg = base.win.getGsg()
                    if gsg:
                        self.levelGeom.prepareScene(gsg)
                    self.levelGeom.reparentTo(render)
                else:
                    loadDNAFile(self.dnaStore, dnaFiles[index])
            children = self.levelGeom.findAllMatches('**/*doorFrameHole*')
            
            for child in children:
                child.hide()

        self.olc = ZoneUtil.getOutdoorLightingConfig(self.LevelData[self.levelName].get('name'))
        self.olc.setupAndApply()

        if self.loadingText:
            self.loadingText.destroy()
            self.loadingText = None

    def __momadaLoad(self):

        def attachArea(itemNum):
            name = 'MomadaArea-%s' % itemNum
            area = self.momadaAreaName2areaModel.get(name)
            parents = self.LevelData['momada']['parents']
            parent = parents[itemNum]
            if type(parent) == type(""):
                parent = self.momadaAreas[itemNum - 1].find('**/' + parent)
            pos = self.LevelData['momada']['model_positions'][itemNum]
            hpr = self.LevelData['momada']['model_orientations'][itemNum]
            area.reparentTo(parent)
            area.setPos(pos)
            area.setHpr(hpr)

        _numItems = 0
        name = None
        for item in self.LevelData['momada']['models']:
            name = 'MomadaArea-%s' % _numItems
            area = loader.loadModel(item)
            self.momadaAreas.append(area)
            self.momadaAreaName2areaModel[name] = area
            attachArea(_numItems)
            _numItems += 1
            self.notify.info("Loaded and attached %s momada areas." % _numItems)

    def unload(self):
        render.clearOccluder()
        if self.olc:
            self.olc.cleanup()
            self.olc = None
        if self.levelName == "sbf":
            base.camLens.setFar(CIGlobals.DefaultCameraFar)
        if self.levelName == "momada":
            for area in self.momadaAreas:
                self.momadaAreas.remove(area)
                area.removeNode()
                del area
            self.momadaAreas = []
            self.momadaAreaName2areaModel = {}
        else:
            if self.occluders:
                self.occluders.removeNode()
                self.occluders = None
            if self.levelGeom:
                self.levelGeom.removeNode()
                self.levelGeom = None

    def cleanup(self):
        self.momadaAreas = None
        self.momadaAreaName2areaModel = None
        if self.dnaStore:
            self.dnaStore.reset_nodes()
            self.dnaStore.reset_hood_nodes()
            self.dnaStore.reset_place_nodes()
            self.dnaStore.reset_hood()
            self.dnaStore.reset_fonts()
            self.dnaStore.reset_DNA_vis_groups()
            self.dnaStore.reset_materials()
            self.dnaStore.reset_block_numbers()
            self.dnaStore.reset_block_zones()
            self.dnaStore.reset_suit_points()
        self.dnaStore = None