Esempio n. 1
0
class OptionsCategory(DirectObject):
    AppendOptions = True
    ApplyCancelButtons = True
    WantTitle = True

    def __init__(self, page):
        self.page = page
        self.page.header.setScale(0.1)
        if self.WantTitle:
            self.page.header.setText(
                self.Name + (" Options" if self.AppendOptions else ""))
        else:
            self.page.header.setText("")
        if self.ApplyCancelButtons:
            self.applyBtn = CIGlobals.makeOkayButton("Apply/Save",
                                                     parent=self.page.book,
                                                     command=self.applyChanges,
                                                     pos=(0.45, -0.62, -0.62))
            self.discardBtn = CIGlobals.makeCancelButton(
                "Discard",
                parent=self.page.book,
                command=self.discardChanges,
                pos=(0.65, -0.62, -0.62))

        self.applying = GlobalDialog("Saving settings...")
        self.applying.hide()

        self.settingsMgr = CIGlobals.getSettingsMgr()

        # This is a list of ChoiceWidgets under this options category.
        self.widgets = []

    def applyChanges(self):
        self._showApplying()
        if self.widgets:
            for widget in self.widgets:
                widget.saveSetting()
        self.settingsMgr.saveFile()
        self._hideApplying()

    def discardChanges(self):
        if self.widgets:
            for widget in self.widgets:
                widget.reset()

    def _showApplying(self):
        self.applying.show()
        base.cr.renderFrames()

    def _hideApplying(self):
        base.cr.renderFrames()
        self.applying.hide()

    def cleanup(self):
        self.page.header.setScale(0.12)
        if hasattr(self, 'title'):
            self.title.destroy()
            del self.title
        if hasattr(self, 'applyBtn'):
            self.applyBtn.destroy()
            del self.applyBtn
        if hasattr(self, 'discardBtn'):
            self.discardBtn.destroy()
            del self.discardBtn
        if hasattr(self, 'applying'):
            self.applying.cleanup()
            del self.applying
        self.widgets = None
        del self.widgets
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. 3
0
class Place(StateData):
    notify = directNotify.newCategory("Place")

    def __init__(self, loader, doneEvent):
        StateData.__init__(self, doneEvent)
        self.loader = loader
        self.zoneId = None
        self.track = None
        self.interior = False
        self.firstPerson = FirstPerson()
        self.snowEffect = SnowEffect(self)
        self.lastBookPage = 2
        self.useFirstPerson = config.GetBool('want-firstperson-battle')
        self.lampLights = []
        self.lampLightColor = VBase4(255 / 255.0, 255 / 255.0, 218 / 255.0,
                                     1.0)
        return

    def __handleChatInputOpened(self):
        if base.localAvatarReachable():
            currentState = self.fsm.getCurrentState()
            if currentState and currentState.getName() == 'walk':
                base.localAvatar.disableAvatarControls(True)

    def __handleChatInputClosed(self):
        if base.localAvatarReachable():
            currentState = self.fsm.getCurrentState()
            if currentState and currentState.getName() == 'walk':
                base.localAvatar.enableAvatarControls(True)

    def __acceptEvents(self):
        self.accept(CHAT_WINDOW_OPENED_EVENT, self.__handleChatInputOpened)
        self.accept(CHAT_WINDOW_CLOSED_EVENT, self.__handleChatInputClosed)

    def __ignoreEvents(self):
        self.ignore(CHAT_WINDOW_OPENED_EVENT)
        self.ignore(CHAT_WINDOW_CLOSED_EVENT)

    def maybeUpdateAdminPage(self):
        if self.fsm:
            currentState = self.fsm.getCurrentState()
            if currentState and currentState.getName() == 'shtickerBook':
                if hasattr(self, 'shtickerBookStateData'):
                    if self.shtickerBookStateData.getCurrentPage(
                    ) and self.shtickerBookStateData.getCurrentPage(
                    ).title == 'Admin Page':
                        if base.cr.playGame.suitManager:
                            text2Change2 = 'Turn Suit Spawner '
                            if base.cr.playGame.suitManager.getSpawner():
                                text2Change2 += 'Off'
                            else:
                                text2Change2 += 'On'
                            self.shtickerBookStateData.getCurrentPage(
                            ).suitSpawnerBtn['text'] = text2Change2

    # Used to disable all GUI interaction.
    def __disableInteraction(self):
        if base.localAvatar.invGui:
            base.localAvatar.invGui.disable()
        base.localAvatar.disableLaffMeter()

    def enterStart(self):
        pass

    def exitStart(self):
        pass

    def enterFinal(self):
        pass

    def exitFinal(self):
        pass

    def enter(self):
        StateData.enter(self)

        base.localAvatar.createChatInput()

    def exit(self):
        self.__disableInteraction()
        del self.lastBookPage

        base.localAvatar.disableChatInput()

        StateData.exit(self)

    def enterTrolleyOut(self, requestStatus):
        base.localAvatar.walkControls.setCollisionsActive(0)
        base.transitions.fadeScreen(1.0)

        prevZone = requestStatus['prevZoneId']
        slot = requestStatus['slot']
        for trolley in base.cr.doFindAll("DistributedBattleTrolley"):
            if trolley.toZone == prevZone:
                trolley.localAvOnTrolley = True
                CIGlobals.showWaitForOthers()
                trolley.sendUpdate('arrivedInTrolley', [slot])

    def exitTrolleyOut(self):
        pass

    def enterDoorIn(self, distDoor):
        requestStatus = {}
        requestStatus['zoneId'] = distDoor.getToZone()
        requestStatus['hoodId'] = base.cr.playGame.hood.id
        requestStatus['how'] = 'doorOut'
        requestStatus['shardId'] = None
        requestStatus['doorIndex'] = distDoor.getDoorIndex()
        foundBlock = False
        for interior in base.cr.doFindAll("DistributedToonInterior"):
            if interior.zoneId == base.localAvatar.zoneId:
                foundBlock = True
                requestStatus['block'] = interior.getBlock()
                break
        if not foundBlock:
            requestStatus['block'] = distDoor.getBlock()
        requestStatus['where'] = ZoneUtil.getWhereName(requestStatus['zoneId'])
        requestStatus['loader'] = base.cr.playGame.hood.fsm.getCurrentState(
        ).getName()
        requestStatus['avId'] = base.localAvatar.doId
        self.acceptOnce('DistributedDoor_localAvatarWentInDoor',
                        self.handleDoorInDone, [requestStatus])
        self.acceptOnce('DistributedDoor_localAvatarGoingInDoor',
                        base.transitions.irisOut)

        base.localAvatar.doFirstPersonCameraTransition()

    def exitDoorIn(self):
        self.ignore('DistributedDoor_localAvatarWentInDoor')
        self.ignore('DistributedDoor_localAvatarGoingInDoor')

    def handleDoorInDone(self, requestStatus):
        self.doneStatus = requestStatus
        messenger.send(self.doneEvent)

    def __waitOnDoor(self, door, task):
        if door.ready:
            self.__doorReady(door)
            return task.done
        return task.cont

    def enterDoorOut(self, requestStatus):
        base.localAvatar.d_clearSmoothing()
        base.localAvatar.stopPosHprBroadcast()
        base.localAvatar.walkControls.setCollisionsActive(0)
        block = requestStatus['block']
        zoneId = requestStatus['zoneId']
        doorIndex = requestStatus['doorIndex']
        doorToExitFrom = None
        for door in base.cr.doFindAll("DistributedDoor"):
            if door.zoneId == zoneId:
                if door.getBlock() == block:
                    if door.getDoorIndex() == doorIndex:
                        doorToExitFrom = door
                        break
        if not doorToExitFrom:
            self.notify.error('Could not find a DistributedDoor to exit from!')
        elif not doorToExitFrom.ready:
            base.taskMgr.add(self.__waitOnDoor,
                             "Place.waitOnDoor",
                             extraArgs=[doorToExitFrom],
                             appendTask=True)
            return
        self.__doorReady(doorToExitFrom)

    def __doorReady(self, door):
        door.sendUpdate('requestExit', [])
        self.nextState = 'walk'
        self.acceptOnce('DistributedDoor_localAvatarCameOutOfDoor',
                        self.handleDoorOutDone)

    def exitDoorOut(self):
        base.taskMgr.remove("Place.waitOnDoor")
        self.ignore('DistributedDoor_localAvatarCameOutOfDoor')

    def handleDoorOutDone(self):
        base.transitions.irisIn()
        base.localAvatar.walkControls.setCollisionsActive(1)
        self.fsm.request(self.nextState)

    def enterShtickerBook(self):
        base.localAvatar.createLaffMeter()
        base.localAvatar.startSmartCamera()
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.d_broadcastPositionNow()
        if base.localAvatar.isFirstPerson():
            # Don't wait for an animation we can't see, open the book now.
            self.enterShtickerBookGui()
        else:
            base.localAvatar.b_setAnimState('openBook',
                                            self.enterShtickerBookGui)

    def enterShtickerBookGui(self):
        doneEvent = 'shtickerBookDone'
        self.shtickerBookStateData = ShtickerBook(doneEvent)
        self.acceptOnce(doneEvent, self.__shtickerBookDone)
        self.shtickerBookStateData.load()
        self.shtickerBookStateData.enter(self.lastBookPage)
        base.localAvatar.showBookButton(1)
        base.localAvatar.b_setAnimState('readBook')
        base.localAvatar.showFriendButton()
        NametagGlobals.setWantActiveNametags(True)
        NametagGlobals.makeTagsReady()
        self.acceptOnce('escape-up', base.localAvatar.bookButtonClicked, [0])

    def __shtickerBookDone(self):
        self.hideFriendsStuff()
        NametagGlobals.setWantActiveNametags(False)
        NametagGlobals.makeTagsInactive()
        self.ignore('escape-up')
        doneStatus = self.shtickerBookStateData.getDoneStatus()
        base.localAvatar.hideBookButton()
        self.shtickerBookStateData.exit()

        data = []
        if doneStatus['mode'] == 'exit':
            data = [self.__handleBookCloseExit, []]
        elif doneStatus['mode'] == 'teleport':
            data = [self.__handleBookCloseTeleport, [doneStatus]]
        elif doneStatus['mode'] == 'resume':
            data = [self.__handleBookCloseResume, [doneStatus]]
        elif doneStatus['mode'] == 'switchShard':
            data = [self.__handleBookCloseSwitchShard, [doneStatus]]

        if base.localAvatar.isFirstPerson():
            # Don't wait for an animation we can't see.
            data[0](*data[1])
        else:
            base.localAvatar.b_setAnimState('closeBook', data[0], data[1])

    def __handleBookCloseSwitchShard(self, requestStatus):
        base.localAvatar.b_setAnimState('teleportOut',
                                        self.__handleBookSwitchShard,
                                        [requestStatus])

    def __handleBookSwitchShard(self, requestStatus):
        params = []
        params.append(requestStatus['shardId'])
        params.append(base.cr.playGame.hood.id)
        params.append(ZoneUtil.getZoneId(base.cr.playGame.hood.id))
        params.append(base.localAvatar.doId)
        base.cr.gameFSM.request('switchShards', params)

    def __handleBookCloseResume(self, doneStatus):
        if doneStatus.get('callback'):
            doneStatus['callback'](*doneStatus.get("extraArgs", []))

        if base.localAvatar.isFirstPerson():
            base.localAvatar.getGeomNode().hide()
        self.fsm.request('walk', [0, 0])

    def __handleBookCloseTeleport(self, requestStatus):
        self.fsm.request('teleportOut', [requestStatus])

    def __teleportOutDone(self, requestStatus):
        self.doneStatus = requestStatus
        messenger.send(self.doneEvent)

    def __handleBookCloseExit(self):
        base.localAvatar.b_setAnimState('teleportOut',
                                        self.__handleBookExitTeleport)

    def __handleBookExitTeleport(self):
        base.transitions.fadeOut(0.0)
        base.cr.gameFSM.request('closeShard')

    def exitShtickerBook(self):
        base.localAvatar.stopPosHprBroadcast()
        base.localAvatar.disableLaffMeter()
        self.ignore(self.shtickerBookStateData.doneEvent)
        self.shtickerBookStateData.exit()
        self.shtickerBookStateData.unload()
        del self.shtickerBookStateData
        base.localAvatar.hideBookButton()
        self.hideFriendsStuff()
        NametagGlobals.setWantActiveNametags(False)
        NametagGlobals.makeTagsInactive()
        self.ignore('escape-up')

    def enterStop(self, doNeutral=1):
        if doNeutral:
            base.localAvatar.b_setAnimState('neutral')
        base.localAvatar.createLaffMeter()
        if base.localAvatar.getBattleZone():
            base.localAvatar.enableGags(andKeys=0)

    def exitStop(self):
        self.__disableInteraction()
        if base.localAvatar.getBattleZone():
            base.localAvatar.disableGags()

    def load(self):
        StateData.load(self)
        self.walkDoneEvent = "walkDone"
        self.walkStateData = PublicWalk(self.fsm, self.walkDoneEvent)
        self.walkStateData.load()
        if not self.interior and (
                base.cr.holidayManager.getHoliday() == HolidayType.CHRISTMAS
                or base.cr.playGame.getCurrentWorldName() == 'BRHood'):
            self.snowEffect.load()
        self.__acceptEvents()

    def unload(self):
        StateData.unload(self)
        if not self.interior and (
                base.cr.holidayManager.getHoliday() == HolidayType.CHRISTMAS
                or base.cr.playGame.getCurrentWorldName() == 'BRHood'):
            self.snowEffect.unload()
        del self.walkDoneEvent
        self.walkStateData.unload()
        del self.walkStateData
        del self.loader
        del self.snowEffect

        base.waterReflectionMgr.clearWaterNodes()

        self.__ignoreEvents()

    def enterTeleportIn(self, requestStatus):
        self.nextState = requestStatus.get('nextState', 'walk')
        if requestStatus['avId'] != base.localAvatar.doId:
            av = base.cr.doId2do.get(requestStatus['avId'])
            if av:
                base.localAvatar.gotoNode(av)
                base.localAvatar.b_setChat(
                    ChatGlobals.getGreeting(av.getName()))

        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.b_setAnimState('teleportIn',
                                        callback=self.teleportInDone)
        base.localAvatar.d_broadcastPositionNow()
        base.localAvatar.b_setParent(CIGlobals.SPRender)

        base.transitions.irisIn()

    def exitTeleportIn(self):
        base.localAvatar.stopPosHprBroadcast()
        return

    def teleportInDone(self):
        if hasattr(self, 'fsm'):
            self.fsm.request(self.nextState, [1])

    def enterAcknowledgeDeath(self, foo=0):
        message = "You were defeated by the Cogs! Collect treasures in the Playground to refill your Laff meter."
        self.dialog = GlobalDialog(message=message,
                                   style=3,
                                   doneEvent='ackDeathDone')
        self.dialog.show()
        self.acceptOnce('ackDeathDone', self.handleAckDeathDone)

    def handleAckDeathDone(self):
        self.fsm.request('walk', [1])

    def exitAcknowledgeDeath(self):
        self.ignore('ackDeathDone')
        self.dialog.cleanup()
        del self.dialog

    def enterDied(self, requestStatus, callback=None):
        if callback is None:
            callback = self.__diedDone
        base.localAvatar.createLaffMeter()
        base.localAvatar.b_setAnimState('died', callback, [requestStatus])

    def __diedDone(self, requestStatus):
        self.doneStatus = requestStatus
        messenger.send(self.doneEvent)

    def exitDied(self):
        base.localAvatar.disableLaffMeter()

    def enterWalk(self, teleportIn=0, wantMouse=1):
        self.walkStateData.enter(wantMouse)
        if teleportIn == 0:
            self.walkStateData.fsm.request('walking')
        self.acceptOnce(self.walkDoneEvent, self.handleWalkDone)
        self.walkStateData.fsm.request('walking')
        self.watchTunnelSeq = Sequence(Wait(1.0),
                                       Func(LinkTunnel.globalAcceptCollisions))
        self.watchTunnelSeq.start()
        NametagGlobals.setWantActiveNametags(True)
        NametagGlobals.makeTagsReady()

        if base.localAvatar.getBattleZone():
            if self.useFirstPerson:
                base.localAvatar.stopSmartCamera()
                camera.setPos(base.localAvatar.smartCamera.firstPersonCamPos)
                self.firstPerson.start()
                self.firstPerson.reallyStart()
                self.firstPerson.disableMouse()
                base.localAvatar.getGeomNode().show()
                base.localAvatar.getShadow().hide()
                base.localAvatar.find('**/torso-top').hide()
                base.localAvatar.find('**/torso-bot').hide()
                base.localAvatar.getPart('head').hide()
            base.localAvatar.setBusy(1)
        else:
            base.localAvatar.setBusy(0)
            base.localAvatar.enablePicking()
            base.localAvatar.showFriendButton()
            base.localAvatar.questManager.enableShowQuestsHotkey()
        messenger.send(CIGlobals.ENTER_WALK_EVENT, [])

    def hideFriendsStuff(self):
        base.localAvatar.hideFriendButton()
        if base.localAvatar.friendsList:
            base.localAvatar.friendsList.fsm.requestFinalState()
        if base.localAvatar.panel:
            base.localAvatar.panel.fsm.requestFinalState()

    def exitWalk(self):
        self.walkStateData.exit()
        self.ignore(self.walkDoneEvent)
        if base.cr.playGame.hood.titleText != None:
            base.cr.playGame.hood.hideTitleText()
        if hasattr(self, 'watchTunnelSeq'):
            self.watchTunnelSeq.pause()
            del self.watchTunnelSeq
        NametagGlobals.setWantActiveNametags(False)
        NametagGlobals.makeTagsInactive()

        if base.localAvatar.getBattleZone():
            base.localAvatar.setBusy(1)

        base.localAvatar.disablePicking()
        self.hideFriendsStuff()
        if base.localAvatar.invGui:
            base.localAvatar.invGui.disable()
        if base.localAvatar.questManager:
            base.localAvatar.questManager.disableShowQuestsHotkey()
        if self.useFirstPerson:
            if base.localAvatar.getBattleZone():
                self.firstPerson.enableMouse()
                self.firstPerson.end()
                self.firstPerson.reallyEnd()
                base.localAvatar.getShadow().show()
                base.localAvatar.find('**/torso-top').show()
                base.localAvatar.find('**/torso-bot').show()
                base.localAvatar.getPart('head').show()
        return

    def handleWalkDone(self, doneStatus):
        pass

    def enterTeleportOut(self, requestStatus, callback=None):
        if not callback:
            callback = self.__teleportOutDone
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.d_broadcastPositionNow()
        base.localAvatar.b_setAnimState('teleportOut', callback,
                                        [requestStatus])

    def exitTeleportOut(self):
        base.localAvatar.disableLaffMeter()
        base.localAvatar.stopPosHprBroadcast()

    def enterTunnelIn(self, linkTunnel):
        zoneId = linkTunnel.data['zoneId']
        base.localAvatar.sendUpdate('goThroughTunnel', [zoneId, 0])
        base.localAvatar.playMovementSfx('run')

        requestStatus = {}
        requestStatus['zoneId'] = linkTunnel.data['zoneId']

        # Goes from safe zone to street.
        if linkTunnel.__class__.__name__ == "SafeZoneLinkTunnel":
            requestStatus['where'] = 'street'
            requestStatus['loader'] = 'townLoader'
            requestStatus['hoodId'] = base.cr.playGame.hood.id
            requestStatus['shardId'] = None
            requestStatus['avId'] = base.localAvatar.doId
            requestStatus['how'] = 'tunnelOut'
            requestStatus['fromZone'] = base.localAvatar.zoneId
        # Goes from street to safe zone.
        elif linkTunnel.__class__.__name__ == "StreetLinkTunnel":
            requestStatus['where'] = 'playground'
            requestStatus['loader'] = 'safeZoneLoader'
            requestStatus['hoodId'] = base.cr.playGame.hood.id
            requestStatus['shardId'] = None
            requestStatus['avId'] = base.localAvatar.doId
            requestStatus['how'] = 'tunnelOut'
            requestStatus['fromZone'] = base.localAvatar.zoneId
        # Goes from street to street.
        elif linkTunnel.__class__.__name__ == "NeighborhoodLinkTunnel":
            requestStatus['where'] = 'street'
            requestStatus['loader'] = 'townLoader'
            hoodId = ZoneUtil.getHoodId(linkTunnel.data['zoneId'], 1)
            requestStatus['hoodId'] = hoodId
            requestStatus['shardId'] = None
            requestStatus['avId'] = base.localAvatar.doId
            requestStatus['how'] = 'tunnelOut'
            requestStatus['fromZone'] = base.localAvatar.zoneId

        base.localAvatar.goThroughTunnel(zoneId, 0, requestStatus)

    def exitTunnelIn(self):
        base.localAvatar.playMovementSfx(None)
        base.localAvatar.reparentTo(hidden)
        #base.localAvatar.walkControls.setCollisionsActive(1)

    def enterTunnelOut(self, requestStatus):
        zone = requestStatus['fromZone']
        base.localAvatar.sendUpdate('goThroughTunnel', [zone, 1])
        base.localAvatar.playMovementSfx('run')

        self.nextState = requestStatus.get('nextState', 'walk')
        base.localAvatar.goThroughTunnel(zone, 1)

    def exitTunnelOut(self):
        base.localAvatar.playMovementSfx(None)
        del self.nextState

    def enterNoAccessFA(self):
        base.localAvatar.startSmartCamera()
        base.localAvatar.createLaffMeter()

        noAccess = "Watch out!\n\nThis neighborhood is too dangerous for your Toon. Complete Quests to unlock this neighborhood."
        self.dialog = GlobalDialog(noAccess, 'noAccessAck', Ok)
        self.acceptOnce('noAccessAck', self.__handleNoAccessAck)
        self.dialog.show()

    def __handleNoAccessAck(self):
        self.fsm.request('walk')

    def exitNoAccessFA(self):
        base.localAvatar.disableLaffMeter()

        if hasattr(self, 'dialog'):
            self.dialog.cleanup()
            del self.dialog
class DistributedMinigame(DistributedObject.DistributedObject, Timer.Timer):
    """Abstract class for any minigame (client side)"""
    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.ogg"
        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.round = 0
        self.numPlayers = 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 setNumPlayers(self, num):
        self.numPlayers = num

    def getNumPlayers(self):
        return self.numPlayers

    def roundOver(self):
        pass

    def setRound(self, round):
        self.round = round

    def getRound(self):
        return self.round

    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

    def enterFinalScores(self):
        # Not defined as a state in DistributedMinigame, but you
        # can define it in a minigame that might need to show scores.

        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)
        self.descDialog.show()

    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):
        CIGlobals.showWaitForOthers()

    def exitWaitForOthers(self):
        CIGlobals.hideWaitForOthers()

    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()
        elif scenario == "loser":
            msg = self.loserMsg % self.loserPrize
            self.prizeLow.play()
        elif 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(ZoneUtil.MinigameAreaId)
        loaderName = ZoneUtil.getLoaderName(ZoneUtil.MinigameAreaId)
        requestStatus = {
            'zoneId': ZoneUtil.MinigameAreaId,
            'hoodId': ZoneUtil.MinigameArea,
            'where': whereName,
            'how': 'teleportIn',
            'avId': base.localAvatar.doId,
            'shardId': None,
            'loader': loaderName
        }
        self.cr.playGame.hood.fsm.request('quietZone', [requestStatus])

    def abort(self):
        self.headBackToMinigameArea()

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

    def d_leaving(self):
        """ Tell the AI that we are leaving. """
        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.play()

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

    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)
        if not base.localAvatar.walkControls.getCollisionsActive():
            base.localAvatar.walkControls.setCollisionsActive(1)

    def disable(self):
        self.deleteTimer()
        base.localAvatar.getGeomNode().setColorScale(VBase4(1, 1, 1, 1))
        if hasattr(self, 'gameOverLbl') and self.gameOverLbl is not None:
            self.gameOverLbl.destroy()
            self.gameOverLbl = None
        NametagGlobals.setWant2dNametags(True)
        base.localAvatar.setPosHpr(0, 0, 0, 0, 0, 0)
        if hasattr(self, 'fsm'):
            self.fsm.requestFinalState()
            del self.fsm
        self.winSfx = None
        self.loseSfx = None
        self.prizeHigh = None
        self.prizeLow = None
        if self.headPanels is not None:
            self.headPanels.delete()
            self.headPanels = None
        if self.finalScoreUI is not None:
            self.finalScoreUI.unload()
            self.finalScoreUI = None
        self.numPlayers = None
        base.minigame = None
        DistributedObject.DistributedObject.disable(self)
class AboutCategory(OptionsCategory, DirectObject):
    Name = "About"
    AppendOptions = False
    ApplyCancelButtons = False
    WantTitle = False

    def __init__(self, page):
        OptionsCategory.__init__(self, page)
        DirectObject.__init__(self)

        self.logoNode, self.logoImg = CIGlobals.getLogoImage(
            self.page.book, 0.75, (0, 0, 0.48))

        self.creditsScreen = None

        self.exitConfirmDlg = None

        font = CIGlobals.getToonLogoFont()

        self.gVersionText = OnscreenText(metadata.getBuildInformation(),
                                         parent=self.page.book,
                                         pos=(0, 0.15, 0.15),
                                         font=font,
                                         fg=(1, 1, 1, 1))
        self.gBuildDate = OnscreenText(text=metadata.BUILD_DATE,
                                       parent=self.page.book,
                                       pos=(0, 0.085, 0.085),
                                       scale=0.06,
                                       font=font,
                                       fg=(1, 1, 1, 1))

        self.eVersionText = OnscreenText(text="Engine Version {0}".format(
            PandaSystem.getVersionString()),
                                         parent=self.page.book,
                                         pos=(0, -0.05),
                                         font=font,
                                         fg=(1, 1, 1, 1))
        self.eBuildDate = OnscreenText(text=PandaSystem.getBuildDate(),
                                       parent=self.page.book,
                                       pos=(0, -0.115),
                                       scale=0.06,
                                       font=font,
                                       fg=(1, 1, 1, 1))

        self.exitToontown = CIGlobals.makeDefaultBtn(
            "Exit Toontown",
            pos=(-0.62, -0.62, -0.62),
            parent=self.page.book,
            scale=1.2,
            command=self.showConfirmDlg,
            geom_scale=(0.8, 0.8, 0.8))

        self.credits = CIGlobals.makeDefaultBtn("Credits",
                                                pos=(0.0, 0.5, -0.62),
                                                parent=self.page.book,
                                                scale=1.2,
                                                command=self.rollCredits,
                                                geom_scale=(0.8, 0.8, 0.8))

    def showConfirmDlg(self):
        self.hideConfirmDlg()
        self.acceptOnce('exitToontownChoice', self.__handleExitToontownChoice)
        self.exitConfirmDlg = GlobalDialog('Exit Toontown?',
                                           doneEvent='exitToontownChoice',
                                           style=YesCancel)
        self.exitConfirmDlg.show()

    def hideConfirmDlg(self):
        self.ignore('exitToontownChoice')
        if self.exitConfirmDlg:
            self.exitConfirmDlg.cleanup()
            self.exitConfirmDlg = None

    def __handleExitToontownChoice(self):
        if self.exitConfirmDlg.getValue():
            self.page.book.finished("exit")
        self.hideConfirmDlg()

    def rollCredits(self):
        base.muteMusic()
        base.muteSfx()
        base.transitions.fadeOut(1.0)
        base.taskMgr.doMethodLater(1.1, self.__rollCreditsTask,
                                   "doRollCredits")

    def __rollCreditsTask(self, task):
        self.creditsScreen = Credits()
        self.creditsScreen.setup()
        base.localAvatar.toggleAspect2d()
        self.page.book.hide()
        self.acceptOnce('credits-Complete', self.showBook)
        base.transitions.fadeIn(1.0)
        return task.done

    def showBook(self):
        self.page.book.show()
        base.localAvatar.toggleAspect2d()

    def cleanup(self):
        self.hideConfirmDlg()
        if hasattr(self, 'gVersionText'):
            self.gVersionText.destroy()
            del self.gVersionText
        if hasattr(self, 'gBuildDate'):
            self.gBuildDate.destroy()
            del self.gBuildDate
        if hasattr(self, 'eVersionText'):
            self.eVersionText.destroy()
            del self.eVersionText
        if hasattr(self, 'eBuildDate'):
            self.eBuildDate.destroy()
            del self.eBuildDate
        if hasattr(self, 'logoImg'):
            self.logoImg.destroy()
            del self.logoImg
        if hasattr(self, 'logoNode'):
            self.logoNode.removeNode()
            del self.logoNode
        if hasattr(self, 'exitToontown'):
            self.exitToontown.destroy()
            del self.exitToontown
        if hasattr(self, 'credits'):
            self.credits.destroy()
            del self.credits
        if hasattr(self, 'creditsScreen'):
            self.creditsScreen = None
            del self.creditsScreen
class InitialLoad(LoadUtility):

    def __init__(self, callback):
        LoadUtility.__init__(self, callback)
        phasesToScan = ["phase_3/models"]
        self.models = FileUtility.findAllModelFilesInVFS(phasesToScan)
        self.version_lbl = None
        self.clouds = None
        self.barShadow = None

    def createGui(self):
        self.version_lbl = OnscreenText(text="Version {0} (Build {1} : {2})".format(metadata.VERSION, metadata.BUILD_NUMBER, metadata.BUILD_TYPE),
                                        scale=0.06, pos=(-1.32, -0.97, -0.97), align=TextNode.ALeft,
                                        fg = (1, 1, 1, 1), shadow = (0, 0, 0, 0),
                                        font = CIGlobals.getToonLogoFont())
        gui = loader.loadModel('phase_3/models/gui/loading-background.bam')
        gui.find('**/fg').removeNode()
        self.clouds = OnscreenImage(image = gui.find("**/bg"), parent = render2d)
        gui.removeNode()

    def load(self):
        loader.progressScreen.bg_img.hide()
        loader.progressScreen.bgm.hide()
        loader.progressScreen.bg.hide()
        loader.progressScreen.toontipFrame.hide()
        loader.progressScreen.logoNode.setPos(0, 0, 0)
        loader.progressScreen.logoNode.setScale(1.8)
        self.createGui()
        loader.beginBulkLoad('init', 'init', len(self.models), 0, False)
        if base.config.GetBool('precache-assets', True):
            base.precacheStuff()
        self.done()
       # LoadUtility.load(self)

    def done(self):
        # Load C++ tournament music stuff.
        #ccoginvasion.CTMusicData.initialize_chunk_data()
        #ccoginvasion.CTMusicManager.spawn_load_tournament_music_task()
        taskMgr.add(self.__pollTournyMusic, "pollTournyMusic")
        self.dialog = GlobalDialog("Please wait...")
        self.dialog.show()

    def __pollTournyMusic(self, task):
        # Wait for the asynchronous load of tournament music to finish.
        #if ccoginvasion.CTMusicManager.is_loaded():
        if True:
            self.dialog.cleanup()
            del self.dialog
            LoadUtility.done(self)
            loader.endBulkLoad('init')
            return task.done
        return task.cont

    def destroy(self):
        self.version_lbl.destroy()
        self.version_lbl = None
        self.clouds.destroy()
        self.clouds = None
        loader.progressScreen.bg_img.show()
        loader.progressScreen.bgm.show()
        loader.progressScreen.bg.show()
        loader.progressScreen.toontipFrame.show()
        loader.progressScreen.logoNode.setZ(loader.progressScreen.defaultLogoZ)
        loader.progressScreen.logoNode.setScale(loader.progressScreen.defaultLogoScale)
        LoadUtility.destroy(self)
class AdminPage(BookPage):
    def __init__(self, book):
        BookPage.__init__(self, book, 'Admin Panel')
        self.fsm = ClassicFSM(
            'AdminPage',
            [
                State('off', self.enterOff, self.exitOff),
                State('basePage', self.enterBasePage, self.exitBasePage),
                State('kickSection', self.enterKickSection,
                      self.exitKickSection),
                #State('clickOnToon', self.enterClickOnToon, self.exitClickOnToon),
                State('sysMsgSection', self.enterSysMsgSection,
                      self.exitSysMsgSection)
            ],
            'off',
            'off')
        self.fsm.enterInitialState()

    def load(self):
        BookPage.load(self)
        icons = loader.loadModel('phase_4/models/gui/tfa_images.bam')
        self.icon = icons.find('**/hq-dialog-image')
        icons.detachNode()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enter(self):
        BookPage.enter(self)
        self.fsm.request('basePage')

    def exit(self):
        self.fsm.requestFinalState()
        BookPage.exit(self)

    def unload(self):
        del self.book
        del self.fsm
        BookPage.unload(self)

    def enterSysMsgSection(self):
        geom = CIGlobals.getDefaultBtnGeom()
        self.infoLbl = OnscreenText(
            text="Inform all online players about something.", pos=(0, 0.45))
        self.msgEntry = DirectEntry(
            initialText="System Message...",
            scale=0.055,
            width=15,
            numLines=4,
            command=self.sendSystemMessageCommand,
            focusInCommand=base.localAvatar.chatInput.disableKeyboardShortcuts,
            focusOutCommand=base.localAvatar.chatInput.enableKeyboardShortcuts,
            pos=(-0.4, 0, 0))
        self.sendBtn = DirectButton(
            geom=geom,
            text_scale=0.04,
            relief=None,
            scale=1.0,
            text="Send",
            pos=(0, 0, -0.35),
            text_pos=(0, -0.01),
            command=self.sendSystemMessageCommand,
        )
        self.cancelBtn = DirectButton(geom=geom,
                                      text_scale=0.04,
                                      relief=None,
                                      scale=1.0,
                                      text="Cancel",
                                      pos=(-0.45, 0.15, -0.55),
                                      text_pos=(0, -0.01),
                                      command=self.fsm.request,
                                      extraArgs=['basePage'])

    # Occasionally, extra arguments are sent and this extra variable must be here to capture them.
    def sendSystemMessageCommand(self, _=None):
        msg = self.msgEntry.get()
        DISTRICT_WIDE_MSG(msg)
        self.fsm.request('basePage')

    def exitSysMsgSection(self):
        self.infoLbl.destroy()
        del self.infoLbl
        self.msgEntry.destroy()
        del self.msgEntry
        self.sendBtn.destroy()
        del self.sendBtn
        self.cancelBtn.destroy()
        del self.cancelBtn

    def enterKickSection(self):
        geom = CIGlobals.getDefaultBtnGeom()
        self.infoLbl = OnscreenText(text="Kick or Ban?", pos=(0, 0.45))
        self.kickBtn = DirectButton(geom=geom,
                                    text_scale=0.04,
                                    relief=None,
                                    scale=1.0,
                                    text="Kick",
                                    pos=(0, 0, 0.1),
                                    text_pos=(0, -0.01),
                                    command=self.book.finishedResume,
                                    extraArgs=[KickBanDialog, [0]])
        self.banBtn = DirectButton(geom=geom,
                                   text_scale=0.04,
                                   relief=None,
                                   scale=1.0,
                                   text="Ban",
                                   pos=(0, 0, 0.0),
                                   text_pos=(0, -0.01),
                                   command=self.book.finishedResume,
                                   extraArgs=[KickBanDialog, [1]])
        self.cancelBtn = DirectButton(geom=geom,
                                      text_scale=0.04,
                                      relief=None,
                                      scale=1.0,
                                      text="Cancel",
                                      pos=(-0.45, 0.15, -0.45),
                                      text_pos=(0, -0.01),
                                      command=self.fsm.request,
                                      extraArgs=['basePage'])

    def exitKickSection(self):
        self.banBtn.destroy()
        del self.banBtn
        self.infoLbl.destroy()
        del self.infoLbl
        self.cancelBtn.destroy()
        del self.cancelBtn
        self.kickBtn.destroy()
        del self.kickBtn

    def enterBasePage(self):
        geom = CIGlobals.getDefaultBtnGeom()
        self.ghostBtn = DirectButton(geom=geom,
                                     text_scale=0.04,
                                     relief=None,
                                     scale=1.0,
                                     text="Toggle Ghost",
                                     pos=(-0.45, 0.15, 0.5),
                                     text_pos=(0, -0.01),
                                     command=TOGGLE_GHOST)
        self.bgBtn = DirectButton(geom=geom,
                                  text_scale=0.04,
                                  relief=None,
                                  scale=1.0,
                                  text="Toggle Background",
                                  pos=(-0.45, 0.15, 0.40),
                                  text_pos=(0, -0.01),
                                  command=self.toggleBackground)
        self.idBtn = DirectButton(geom=geom,
                                  text_scale=0.04,
                                  relief=None,
                                  scale=1.0,
                                  text="Toggle Player Ids",
                                  pos=(-0.45, 0.15, 0.3),
                                  text_pos=(0, -0.01),
                                  command=TOGGLE_PLAYER_IDS)
        self.kickBtn = DirectButton(geom=geom,
                                    text_scale=0.04,
                                    relief=None,
                                    scale=1.0,
                                    text="Kick/Ban Player",
                                    pos=(0.45, 0.15, 0.5),
                                    text_pos=(0, -0.01),
                                    command=self.openKickPage)
        self.systemMsgBtn = DirectButton(geom=geom,
                                         text_scale=0.04,
                                         relief=None,
                                         scale=1.0,
                                         text="System Message",
                                         pos=(-0.45, 0.15, 0.1),
                                         text_pos=(0, -0.01),
                                         command=self.openSysMsgPage)
        self.oobeBtn = DirectButton(geom=geom,
                                    text_scale=0.04,
                                    relief=None,
                                    scale=1.0,
                                    text="Toggle OOBE",
                                    pos=(-0.45, 0.15, 0.2),
                                    text_pos=(0, -0.01),
                                    command=base.oobe)
        self.directBtn = DirectButton(geom=geom,
                                      text_scale=0.04,
                                      relief=None,
                                      scale=1.0,
                                      text="Start DIRECT",
                                      pos=(-0.45, 0.15, 0.1),
                                      text_pos=(0, -0.01),
                                      command=self.doStartDirect)
        self.pstatsBtn = DirectButton(geom=geom,
                                      text_scale=0.04,
                                      relief=None,
                                      scale=1.0,
                                      text="Toggle PStats",
                                      pos=(-0.45, 0.15, 0.0),
                                      text_pos=(0, -0.01),
                                      command=self.togglePStats)
        self.pingBtn = DirectButton(geom=geom,
                                    text_scale=0.04,
                                    relief=None,
                                    scale=1.0,
                                    text="Toggle Ping",
                                    pos=(-0.45, 0.15, -0.1),
                                    text_pos=(0, -0.01),
                                    command=base.cr.togglePing)
        self.tokenBtn = DirectButton(geom=geom,
                                     text_scale=0.04,
                                     relief=None,
                                     scale=1.0,
                                     text="Modify Access Level",
                                     pos=(0.45, 0.15, 0.4),
                                     text_pos=(0, -0.01),
                                     command=self.book.finishedResume,
                                     extraArgs=[AdminTokenDialog, []])
        self.worldBtn = DirectButton(geom=geom,
                                     text_scale=0.04,
                                     relief=None,
                                     scale=1.0,
                                     text="Give World Access",
                                     pos=(0.45, 0.15, 0.3),
                                     text_pos=(0, -0.01),
                                     command=self.book.finishedResume,
                                     extraArgs=[WorldAccessDialog, []])
        self.allGagsBtn = DirectButton(geom=geom,
                                       text_scale=0.04,
                                       relief=None,
                                       scale=1.0,
                                       text="Restock All Gags",
                                       pos=(0.45, 0.15, 0.2),
                                       text_pos=(0, -0.01),
                                       command=SEND_REQ_UNLOCK_GAGS)

        self.allLaffBtn = DirectButton(geom=geom,
                                       text_scale=0.04,
                                       relief=None,
                                       scale=1.0,
                                       text="Refill Laff",
                                       pos=(0.45, 0.15, 0.1),
                                       text_pos=(0, -0.01),
                                       command=SEND_REQ_REFILL_LAFF)

        self.physDbgBtn = DirectButton(geom=geom,
                                       text_scale=0.039,
                                       relief=None,
                                       scale=1.0,
                                       text="Toggle Physics Debug",
                                       pos=(0.45, 0.15, 0.0),
                                       text_pos=(0, -0.01),
                                       command=self.togglePhysDbg)
        self.analyzeBtn = DirectButton(geom=geom,
                                       text_scale=0.04,
                                       relief=None,
                                       scale=1.0,
                                       text="Analyze Scene",
                                       pos=(0.45, 0.15, -0.1),
                                       text_pos=(0, -0.01),
                                       command=self.doAnalyzeScene)
        self.listBtn = DirectButton(geom=geom,
                                    text_scale=0.04,
                                    relief=None,
                                    scale=1.0,
                                    text="List Scene",
                                    pos=(0.45, 0.15, -0.2),
                                    text_pos=(0, -0.01),
                                    command=render.ls)
        self.noClipBtn = DirectButton(geom=geom,
                                      text_scale=0.04,
                                      relief=None,
                                      scale=1.0,
                                      text="Toggle No Clip",
                                      pos=(0.45, 0.15, -0.3),
                                      text_pos=(0, -0.01),
                                      command=self.toggleNoClip)
        base.cr.playGame.getPlace().maybeUpdateAdminPage()
        del geom

    def doStartDirect(self):
        base.startTk()
        base.startDirect()

    def doAnalyzeScene(self):
        render.analyze()

        ls = LineStream()
        sga = SceneGraphAnalyzer()
        sga.addNode(render.node())
        sga.write(ls)
        text = ""
        while ls.isTextAvailable():
            text += ls.getLine() + "\n"
        self.acceptOnce('analyzedone', self.__handleAnalyzeDone)
        self.analyzeDlg = GlobalDialog(message=text,
                                       style=Ok,
                                       doneEvent='analyzedone',
                                       text_scale=0.05)
        self.analyzeDlg.show()

    def __handleAnalyzeDone(self):
        self.analyzeDlg.cleanup()
        del self.analyzeDlg

    def toggleNoClip(self):
        ncl = not base.localAvatar.walkControls.controller.noClip
        base.localAvatar.walkControls.controller.noClip = ncl

        if ncl:
            base.cr.myDistrict.systemMessage("No Clip Enabled")
        else:
            base.cr.myDistrict.systemMessage("No Clip Disabled")

    def togglePhysDbg(self):
        base.setPhysicsDebug(not base.physicsDbgFlag)

    def togglePStats(self):
        if PStatClient.isConnected():
            PStatClient.disconnect()
        else:
            # in production, show stats viewer on the server
            if base.config.GetBool("pstats-view-on-server", False):
                PStatClient.connect("127.0.0.1" if not metadata.IS_PRODUCTION
                                    else "gameserver.coginvasion.online")
            else:
                PStatClient.connect("127.0.0.1")

    def toggleBackground(self):
        if render.isHidden():
            render.show()
        else:
            render.hide()
        if self.book.isBackgroundHidden():
            self.book.show()
            self.book.setBackgroundHidden(False)
        else:
            self.book.hide()
            self.book.setBackgroundHidden(True)

    def openKickPage(self):
        self.fsm.request('kickSection')

    def openSysMsgPage(self):
        self.fsm.request('sysMsgSection')

    def exitBasePage(self):
        self.noClipBtn.destroy()
        del self.noClipBtn
        self.systemMsgBtn.destroy()
        del self.systemMsgBtn
        self.idBtn.destroy()
        del self.idBtn
        self.kickBtn.destroy()
        del self.kickBtn
        self.bgBtn.destroy()
        del self.bgBtn
        self.ghostBtn.destroy()
        del self.ghostBtn
        self.oobeBtn.destroy()
        del self.oobeBtn
        self.tokenBtn.destroy()
        del self.tokenBtn
        self.worldBtn.destroy()
        del self.worldBtn
        self.allGagsBtn.destroy()
        del self.allGagsBtn
        self.allLaffBtn.destroy()
        del self.allLaffBtn
        self.physDbgBtn.destroy()
        del self.physDbgBtn
        self.analyzeBtn.destroy()
        del self.analyzeBtn
        if hasattr(self, 'analyzeDlg'):
            self.ignore('analyzedone')
            self.analyzeDlg.cleanup()
            del self.analyzeDlg
        self.directBtn.destroy()
        del self.directBtn
        self.listBtn.destroy()
        del self.listBtn
        self.pstatsBtn.destroy()
        del self.pstatsBtn
        self.pingBtn.destroy()
        del self.pingBtn