Ejemplo n.º 1
0
Archivo: ui.py Proyecto: tgbugs/desc
    def __create_item__(self, text, command = None, args = tuple()): 
        args = list(args)

        #if not len(self.items):
            #parent = self.frame
        if len(self.items) <= 1:
            parent = self.itemsParent  #everyone else parents off 2nd text
        else:
            parent = list(self.items.values())[-1]

        if command != None:
            def cmd(*args):
                """ any item should raise
                """
                self.raise_()
                command(*args)
        else:
            cmd = self.raise_


        b = DirectButton(
            parent=parent,
            frameColor=(1,1,1,.0),  # a = 0 => no border overlap
            frameSize=(0, self.width, 0, self.text_h),
            text=' '+text,  # hack to keep spacing from border
            text_font=self.text_font,
            text_fg=self.text_color,
            text_scale=self.text_s,
            text_pos=(0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s),
            command=cmd,
            relief=DGG.FLAT,
            text_align=TextNode.ALeft,
        )

        b.setPos(LVecBase3f(0, 0, -self.text_h))
        b.setName('DirectButton-'+text)
        if not len(self.items):
            self.items['title'] = b
            b.setBin(*self.DRAW_ORDER['title'])
        else:
            b['extraArgs'] = args+[self, id(b)]
            b.node().setPythonTag('id', id(b))
            b.setBin(*self.DRAW_ORDER['items'])
            if len(self.items) is 1:  # the first item that is not the title
                b.setPos(LVecBase3f(0, 0, -(self.text_h * 2)))
                self.__first_item__ = id(b)

            self.items[id(b)] = b

        if text == ' blank':
            if self.__add_head__ is None:
                self.__add_head__ = 1

        return b
Ejemplo n.º 2
0
    def __create_item__(self, text, command=None, args=tuple()):
        args = list(args)

        #if not len(self.items):
        #parent = self.frame
        if len(self.items) <= 1:
            parent = self.itemsParent  #everyone else parents off 2nd text
        else:
            parent = list(self.items.values())[-1]

        if command != None:

            def cmd(*args):
                """ any item should raise
                """
                self.raise_()
                command(*args)
        else:
            cmd = self.raise_

        b = DirectButton(
            parent=parent,
            frameColor=(1, 1, 1, .0),  # a = 0 => no border overlap
            frameSize=(0, self.width, 0, self.text_h),
            text=' ' + text,  # hack to keep spacing from border
            text_font=self.text_font,
            text_fg=self.text_color,
            text_scale=self.text_s,
            text_pos=(0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s),
            command=cmd,
            relief=DGG.FLAT,
            text_align=TextNode.ALeft,
        )

        b.setPos(LVecBase3f(0, 0, -self.text_h))
        b.setName('DirectButton-' + text)
        if not len(self.items):
            self.items['title'] = b
            b.setBin(*self.DRAW_ORDER['title'])
        else:
            b['extraArgs'] = args + [self, id(b)]
            b.node().setPythonTag('id', id(b))
            b.setBin(*self.DRAW_ORDER['items'])
            if len(self.items) is 1:  # the first item that is not the title
                b.setPos(LVecBase3f(0, 0, -(self.text_h * 2)))
                self.__first_item__ = id(b)

            self.items[id(b)] = b

        if text == ' blank':
            if self.__add_head__ is None:
                self.__add_head__ = 1

        return b
Ejemplo n.º 3
0
class InventoryView:
    """
    Renders the inventory screen.
    """

    ButtonStateNormal = 1
    ButtonStatePressed = 2
    ButtonStateHover = 3

    POINTER_NAME = "inventory_pointer"
    INVENTORY_SCENE_NODE = "inventory_sceneNode"
    ICONS_NODE = "inventory_icons_node"
    BACKDROP_NODE = "backdrop"
    TEXT_NODE = "item_text"

    def __init__(self, game):
        self.log = logging.getLogger('pano.inventoryView')
        self.game = game
        self.msn = Messenger(
            self
        )  # the messenger is used to broadcast user events related to the interface
        self.inventory = None  # the inventory to render

        self.node = None  # the root scenegraph node for inventory rendering nodes
        self.iconsNode = None  # the parent node for all OnscreenImages that render items' icons
        self.pos = (0.0, 0.0)  # position in absolute screen coordinates
        self.size = (1.0, 1.0)  # size in absolute screen coordinates
        self.textPos = (0.0, 0.0)  # position of the item's description text
        self.textScale = 0.07  # the text scale
        self.opacity = 1.0  # controls the opacity of all rendering elements included in the inventory

        self.backdropImage = None  # the name of the image to use as a backdrop
        self.backdropImageObject = None  # the OnscreenImage object used to render the backdrop
        self.backdropNode = None  # the scenegraph node that parents the backdrop

        self.updateIcons = False  # if True then we need to update the rendering of the items' icons
        self.itemText = None  # the TextNode used to render the text
        self.itemTextNode = None  # nodepath that acts as a parent to the TextNode
        self.fontName = None  # the name of the font to use when rendering items' descriptions
        self.font = None  # the Panda3D font resource
        self.fontColor = (1.0, 1.0, 1.0, 1.0
                          )  # colour of the text for an item's description
        self.fontBgColor = (0.0, 0.0, 0.0, 1.0
                            )  # background colour of the text

        # scrolling and paging buttons are DirectButton instances
        self.nextPageButton = None
        self.prevPageButton = None
        self.scrollNextButton = None
        self.scrollPrevButton = None

        # specifies the range of items to be rendered in the next frame as a list [start_item_index, end_item_index]
        # used for scrolling and paging
        self.itemsRange = None

        # number of items displayed per page
        self.pageSize = 0

        # provides the layout of the slots
        self.slotsLayout = None

        # stores image objects for each item's icon
        self.itemIcons = []

        self.mousePointer = InventoryView.POINTER_NAME

        self.debugLayout = False

    def initialize(self, inventory):
        """
        Initialises the inventory, call this method only once otherwise resources could be leaked
        and rendering artifacts created.
        """
        if self.node is not None:
            self.node.removeNode()
#            self.node.detachNode()

        self.node = aspect2d.attachNewNode(InventoryView.INVENTORY_SCENE_NODE)
        self.iconsNode = self.node.attachNewNode(InventoryView.ICONS_NODE)

        # from here on we just initialize the member fields according to the cvars...
        cfg = self.game.getConfig()
        if not self._validateConfig(cfg):
            self.log.error('Missing or invalid inventory configuration')
            return

        view = self.game.getView()

        if self.backdropImageObject is not None:
            self.backdropImageObject.destroy()
            self.backdropImageObject = None

        self.pos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_POS)
        if self.pos is None:
            self.pos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_REL_POS)
            self.pos = view.relativeToAbsolute(self.pos)

        self.textPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_TEXT_POS)
        if self.textPos is None:
            self.textPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_REL_POS)
            self.textPos = view.relativeToAbsolute(self.textPos)

        self.pos, self.textPos = PandaUtil.convertScreenToAspectCoords(
            [self.pos, self.textPos])

        self.size = cfg.getVec2(PanoConstants.CVAR_INVENTORY_SIZE, (1.0, 1.0))

        self.textScale = cfg.getFloat(PanoConstants.CVAR_INVENTORY_TEXT_SCALE,
                                      0.07)
        self.opacity = cfg.getFloat(PanoConstants.CVAR_INVENTORY_OPACITY)
        self.fontName = cfg.get(PanoConstants.CVAR_INVENTORY_FONT)
        self.fontColor = cfg.getVec4(PanoConstants.CVAR_INVENTORY_FONT_COLOR)
        if self.fontColor is None:
            self.fontColor = (1.0, 1.0, 1.0, 1.0)

        self.fontBgColor = cfg.getVec4(
            PanoConstants.CVAR_INVENTORY_FONT_BG_COLOR)
        if self.fontBgColor is None:
            self.fontBgColor = (0.0, 0.0, 0.0, 0.0)

        self.mousePointer = cfg.get(PanoConstants.CVAR_INVENTORY_POINTER)

        layout = cfg.get(PanoConstants.CVAR_INVENTORY_SLOTS)
        self._parseLayout(layout)

        slotsCount = self.slotsLayout.getNumSlots()
        self.log.debug('Setting slots count to %i' % slotsCount)

        # by default render all items, the controller state can later overridde this
        self.itemsRange = [0, slotsCount]

        if cfg.hasVar(PanoConstants.CVAR_INVENTORY_PAGESIZE):
            self.pageSize = cfg.getInt(PanoConstants.CVAR_INVENTORY_PAGESIZE)
        else:
            self.pageSize = slotsCount

        self.inventory = inventory
        self.inventory.setSlotsCount(slotsCount)

        self.backdropImage = cfg.get(PanoConstants.CVAR_INVENTORY_BACKDROP)
        if self.backdropImage is not None:
            self._createBackdrop(show=False)

        # create the scrolling and paging gui buttons
        self._createButtons(cfg)

        # force an initial rendering of the icons
        self.updateIcons = True

        # start as  hidden
        self.node.hide()

    def update(self, millis):
        """
        Re-renders anything that has updated.        
        """
        if self.isVisible() and self.updateIcons:
            self._renderItemsIcons()
            self.updateIcons = False

    def redraw(self):
        """
        Called to indicate that the underlying inventory has updated its state and now we
        should redraw it.
        """
        self.updateIcons = True

    def show(self):
        """
        Shows the inventory.
        """
        self.node.show()
        if self.nextPageButton:
            self.nextPageButton.show()

        if self.prevPageButton:
            self.prevPageButton.show()

        if self.scrollNextButton:
            self.scrollNextButton.show()

        if self.scrollPrevButton:
            self.scrollPrevButton.show()

        if self.debugLayout:
            self.enableDebugRendering()

    def hide(self):
        """
        Hides the inventory.
        """
        self.node.hide()
        if self.nextPageButton:
            self.nextPageButton.hide()

        if self.prevPageButton:
            self.prevPageButton.hide()

        if self.scrollNextButton:
            self.scrollNextButton.hide()

        if self.scrollPrevButton:
            self.scrollPrevButton.hide()

        if self.debugLayout:
            self.disableDebugRendering()

    def isVisible(self):
        """
        Returns True if the inventory is visible and False if otherwise.
        """
        return (self.node is not None) and (not self.node.isHidden())

    def getMousePointerName(self):
        return self.mousePointer

    def getSlotAtScreenPos(self, x, y):
        return self.slotsLayout.getSlotAtScreenPos(x, y)

    def getBackdropImage(self):
        return self.backdropImage

    def setBackdropImage(self, imageName):
        self.backdropImage = imageName
        self._createBackdrop()

    def getText(self):
        return self.text

    def setText(self, text):
        self.text = text
        self._updateText()

    def clearText(self):
        self.text = ""
        if self.itemTextNode is not None:
            self.itemTextNode.hide()

    def getNode(self):
        return self.node

    def enableDebugRendering(self):
        self.slotsLayout.enableDebugRendering(self.game)
        self.debugLayout = True

    def disableDebugRendering(self):
        self.slotsLayout.disableDebugRendering(self.game)
        self.debugLayout = False

    def _validateConfig(self, config):
        return (config.hasVar(PanoConstants.CVAR_INVENTORY_BACKDROP)
                and (config.hasVar(PanoConstants.CVAR_INVENTORY_POS)
                     or config.hasVar(PanoConstants.CVAR_INVENTORY_REL_POS))
                and (config.hasVar(PanoConstants.CVAR_INVENTORY_TEXT_POS)
                     or config.hasVar(PanoConstants.CVAR_INVENTORY_REL_POS))
                and config.hasVar(PanoConstants.CVAR_INVENTORY_SIZE)
                and config.hasVar(PanoConstants.CVAR_INVENTORY_FONT)
                and config.hasVar(PanoConstants.CVAR_INVENTORY_POINTER)
                and config.hasVar(PanoConstants.CVAR_INVENTORY_SLOTS))

    def _createBackdrop(self, show=True):
        """
        Setups rendering for the inventory's backdrop image.
        The backdrop image is rendered through a OnscreenImage object and is attached under the scenegraph node
        named Inventory.BACKDROP_NODE.
        If the parameter show is True then the backdrop image becomes visible as well, otherwise it is hidden.
        """
        if self.backdropImageObject is not None:
            self.backdropImageObject.destroy()
            self.backdropImageObject = None

        if self.backdropNode is not None:
            self.backdropNode.removeNode()

        imagePath = self.game.getResources().getResourceFullPath(
            PanoConstants.RES_TYPE_TEXTURES, self.backdropImage)

        self.backdropNode = self.node.attachNewNode(
            InventoryView.BACKDROP_NODE)
        self.backdropImageObject = OnscreenImage(parent=self.node,
                                                 image=imagePath,
                                                 pos=(self.pos[0], 0.0,
                                                      self.pos[1]),
                                                 sort=0)

        self.backdropImageObject.setTransparency(TransparencyAttrib.MAlpha)
        self.backdropImageObject.setBin("fixed",
                                        PanoConstants.RENDER_ORDER_INVENTORY)

        if not show:
            self.backdropNode.hide()

    def _updateText(self):
        if self.itemText is not None:
            self.itemText.destroy()
            self.itemText = None

        if self.itemTextNode is None:
            self.itemTextNode = self.node.attachNewNode(self.TEXT_NODE)
            self.itemTextNode.setPos(self.textPos[0], 0.0, self.textPos[1])
        self.itemTextNode.show()

        i18n = self.game.getI18n()
        translated = i18n.translate(self.text)

        localizedFont = i18n.getLocalizedFont(self.fontName)
        fontPath = self.game.getResources().getResourceFullPath(
            PanoConstants.RES_TYPE_FONTS, localizedFont)
        self.font = loader.loadFont(fontPath)

        self.itemText = DirectButton(
            parent=self.itemTextNode,
            text=translated,
            text_font=self.font,
            text_bg=(self.fontBgColor[0], self.fontBgColor[1],
                     self.fontBgColor[2], self.fontBgColor[3]),
            text_fg=(self.fontColor[0], self.fontColor[1], self.fontColor[2],
                     self.fontColor[3]),
            text_scale=self.textScale,
            frameColor=(0, 0, 0, 0),
            text_wordwrap=None,
            text_align=TextNode.ALeft,
            sortOrder=10,
            pressEffect=0)
        self.itemText.setBin("fixed",
                             PanoConstants.RENDER_ORDER_INVENTORY_ITEMS)

    def _parseLayout(self, layoutName):
        layoutName = layoutName.strip()
        if layoutName.startswith('grid'):
            # pos, res, size, offset
            grid_re = re.compile(
                r'grid\(\s*(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+(\d+)\D+'
            )
            m = grid_re.match(layoutName)
            self.slotsLayout = GridSlotsLayout(
                self.game,
                (int(m.group(1)) + self.pos[0],
                 int(m.group(2)) + self.pos[1]),  # position within inventory
                (int(m.group(3)), int(m.group(4))),  # grid resolution
                (int(m.group(5)), int(m.group(6))),  # slot size
                (int(m.group(7)), int(m.group(8))))  # slots offset
        elif layoutName.starts_with('image'):
            self.slotsLayout = ImageBasedSlotsProvider(layoutName)
        # a default to avoid None
        else:
            self.slotsLayout = GridSlotsLayout(self.game, 100, 100, 5, 5, 50,
                                               50)

    def _renderItemsIcons(self):

        self.iconsNode.node().removeAllChildren()
        for icon in self.itemIcons:
            icon.destroy()
        self.itemIcons = []

        startItem = 0
        endItem = self.inventory.getSlotsCount()
        if self.itemsRange is not None:
            startItem = self.itemsRange[0]
            endItem = self.itemsRange[1]

        for i in xrange(endItem - startItem):
            itemNum = startItem + i
            s = self.inventory.getSlotByNum(itemNum)
            if not s.isFree():
                # get slot position and size in aspect2d space
                p, sz = self.slotsLayout.getRelativeSlotPosSize(s.getNum())
                itemImage = s.getItem().getImage()
                imagePath = self.game.getResources().getResourceFullPath(
                    PanoConstants.RES_TYPE_TEXTURES, itemImage)
                iconNode = OnscreenImage(parent=self.iconsNode,
                                         image=imagePath,
                                         pos=(p[0] + sz[0] / 2.0, 0.0,
                                              p[1] + sz[1] / 2.0),
                                         scale=0.2)
                iconNode.setTransparency(TransparencyAttrib.MAlpha)
                iconNode.setBin("fixed",
                                PanoConstants.RENDER_ORDER_INVENTORY_ITEMS)
                self.itemIcons.append(iconNode)

    def _createButtons(self, cfg):
        '''
        Creates DirectGui elements for displaying the paging and scrolling buttons.
        The sprite names are read from the configuration.
        The create DirectButtons use sprites as images.
        @param cfg: a ConfigVars instance
        '''
        # button to display next page of items
        nxPgBtnSprite = cfg.get(PanoConstants.CVAR_INVENTORY_NEXTPAGE_SPRITE)
        nxPgBtnPressedSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_NEXTPAGE_PRESSED_SPRITE)
        nxPgBtnHoverSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_NEXTPAGE_HOVER_SPRITE)
        nxPgBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_NEXTPAGE_POS)

        # button to display previous page of items
        pvPgBtnSprite = cfg.get(PanoConstants.CVAR_INVENTORY_PREVPAGE_SPRITE)
        pvPgBtnPressedSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_PREVPAGE_PRESSED_SPRITE)
        pvPgBtnHoverSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_PREVPAGE_HOVER_SPRITE)
        pvPgBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_PREVPAGE_POS)

        # button to scroll to next items
        scrNxBtnSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_SCROLLNEXT_SPRITE)
        scrNxBtnPressedSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_SCROLLNEXT_PRESSED_SPRITE)
        scrNxBtnHoverSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_SCROLLNEXT_HOVER_SPRITE)
        scrNxBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_SCROLLNEXT_POS)

        # button to scroll to previous items
        scrPvBtnSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_SCROLLPREV_SPRITE)
        scrPvBtnPressedSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_SCROLLPREV_PRESSED_SPRITE)
        scrPvBtnHoverSprite = cfg.get(
            PanoConstants.CVAR_INVENTORY_SCROLLPREV_HOVER_SPRITE)
        scrPvBtnPos = cfg.getVec2(PanoConstants.CVAR_INVENTORY_SCROLLPREV_POS)

        sprites = self.game.getView().getSpritesFactory()
        origin = aspect2d.getRelativePoint(screen2d, VBase3(0, 0, 0))

        # for every button define property name, position, callback, list of sprites for normal, pressed and hover state
        pagingButtons = [
            ('nextPageButton', nxPgBtnPos, self._nextPageCallback,
             [(nxPgBtnSprite, 'next_page_sprite'),
              (nxPgBtnPressedSprite, 'next_page_pressed_sprite'),
              (nxPgBtnHoverSprite, 'next_page_hover_sprite')]),
            ('prevPageButton', pvPgBtnPos, self._previousPageCallback,
             [(pvPgBtnSprite, 'previous_page_sprite'),
              (pvPgBtnPressedSprite, 'previous_page_pressed_sprite'),
              (pvPgBtnHoverSprite, 'previous_page_hover_sprite')]),
            ('scrollNextButton', scrNxBtnPos, self._scrollNextCallback,
             [(scrNxBtnSprite, 'scroll_next_sprite'),
              (scrNxBtnPressedSprite, 'scroll_next_pressed_sprite'),
              (scrNxBtnHoverSprite, 'scroll_next_hover_sprite')]),
            ('scrollPrevButton', scrPvBtnPos, self._scrollPreviousCallback,
             [(scrPvBtnSprite, 'scroll_previous_sprite'),
              (scrPvBtnPressedSprite, 'scroll_previous_pressed_sprite'),
              (scrPvBtnHoverSprite, 'scroll_previous_hover_sprite')]),
        ]

        for buttonName, buttonPos, buttonCallback, spritesList in pagingButtons:
            buttonGeoms = [None, None, None, None]
            btnScrBounds = [0, 0, 0]
            i = 0
            for spriteFile, spriteName in spritesList:
                print 'adding sprite %s' % spriteName
                if spriteFile is not None:
                    spr = None
                    if spriteFile.rindex('.') >= 0:
                        ext = spriteFile[spriteFile.rindex('.'):]
                        print ext
                        if ResourcesTypes.isExtensionOfType(
                                ext, PanoConstants.RES_TYPE_IMAGES):
                            spr = Sprite(spriteName)
                            spr.image = spriteFile
                    else:
                        spr = self.game.getResources().loadSprite(spriteFile)

                    if spr:
                        buttonGeoms[i] = sprites.createSprite(spr).nodepath
                        buttonGeoms[i].setScale(1.0)
                        btnScrBounds = aspect2d.getRelativePoint(
                            screen2d, VBase3(spr.width, 1.0,
                                             spr.height)) - origin
                        btnScrBounds[2] *= -1

                i += 1

            if buttonGeoms[0] is not None:
                b = DirectButton(
                    geom=(buttonGeoms[0],
                          buttonGeoms[1] if buttonGeoms[1] else buttonGeoms[0],
                          buttonGeoms[2] if buttonGeoms[2] else buttonGeoms[0],
                          buttonGeoms[3]
                          if buttonGeoms[3] else buttonGeoms[0]),
                    relief=None)
                b['geom_pos'] = (0, 0, 0)
                b.setTransparency(1)

                # if position is omitted from the configuration, put the button on the upper left corner
                if buttonPos is not None:
                    b.setPos(
                        aspect2d.getRelativePoint(
                            screen2d, VBase3(buttonPos[0], 1.0, buttonPos[1])))
                else:
                    b.setPos(origin[0], 1.0, origin[2])

                b.setScale(btnScrBounds[0], 1.0, btnScrBounds[2])
                b.setFrameSize((0, btnScrBounds[0], 1.0, btnScrBounds[2]))
                b['command'] = buttonCallback
                b['extraArgs'] = (self.msn, )
                b.hide()
            else:
                b = None

            setattr(self, buttonName, b)

    def _nextPageCallback(self, messenger):
        '''
        Callback for next page button which only sends the appropriate message.
        '''
        messenger.sendMessage(PanoConstants.EVENT_ITEMS_NEXT_PAGE)

    def _previousPageCallback(self, messenger):
        messenger.sendMessage(PanoConstants.EVENT_ITEMS_PREV_PAGE)

    def _scrollNextCallback(self, messenger):
        messenger.sendMessage(PanoConstants.EVENT_ITEMS_SCROLL_NEXT)

    def _scrollPreviousCallback(self, messenger):
        messenger.sendMessage(PanoConstants.EVENT_ITEMS_SCROLL_PREV)
Ejemplo n.º 4
0
    def makePickableQuests(self, questList):
        self.doCameraNPCInteraction(True)

        quests = []

        for questId in questList:
            quest = Quest(questId, base.localAvatar.questManager)
            quest.setupCurrentObjectiveFromData(-1, 0, None)
            quests.append(quest)

        positions = [(0, 0, 0.65), (0, 0, 0.1), (0, 0, -0.45)]

        self.questFrame = DirectFrame(relief=None,
                                      pos=(-0.8, 0, 0),
                                      geom=DGG.getDefaultDialogGeom(),
                                      geom_color=Vec4(0.8, 0.6, 0.4, 1),
                                      geom_scale=(1.85, 1, 0.9),
                                      geom_hpr=(0, 0, -90))

        self.cancelBtn = DirectButton(text="Cancel",
                                      geom=CIGlobals.getDefaultBtnGeom(),
                                      geom_scale=(0.6, 0.75, 0.75),
                                      relief=None,
                                      parent=self.questFrame,
                                      pos=(0.2, 0, -0.8),
                                      text_scale=0.045,
                                      text_pos=(0, -0.015),
                                      scale=1.1,
                                      command=self.__cancelQuestPicker,
                                      extraArgs=[False])

        self.timer = Timer()
        self.timer.load()
        self.timer.setScale(0.3)
        self.timer.reparentTo(self.questFrame)
        self.timer.setPos(-0.1, 0, -0.8)
        self.timer.setInitialTime(20)
        self.timer.setZeroCommand(self.__cancelQuestPicker)
        self.timer.startTiming()

        self.questPosters = []
        self.questBtns = []

        for i in xrange(len(quests)):
            poster = None
            quest = quests[i]
            poster = QuestGlobals.generatePoster(quest, parent=aspect2d)
            poster.setScale(0.85)
            poster.setPos(0, 0, 0)
            poster.progressBar.hide()
            self.questPosters.append(poster)

            # Let's setup the choose button.
            btn = DirectButton(geom=CIGlobals.getDefaultBtnGeom(),
                               parent=poster,
                               pos=(0.35, 0, 0.215),
                               text='Choose',
                               text_scale=0.08,
                               text_pos=(0, -0.025),
                               relief=None,
                               command=self.d_pickedQuest,
                               extraArgs=[quests[i]])
            btn.setScale(0.4)
            btn.setBin('gui-popup', 60)
            btn.initialiseoptions(DirectButton)

            poster.reparentTo(self.questFrame.stateNodePath[0], 20)
            poster.setPos(positions[i])
            poster.show()

            self.questBtns.append(btn)
Ejemplo n.º 5
0
class LocalToon(DistributedPlayerToon, BaseLocalAvatar):
    neverDisable = 1

    GTAControls = ConfigVariableBool('want-gta-controls', False)

    def __init__(self, cr):
        try:
            self.LocalToon_initialized
            return
        except:
            self.LocalToon_initialized = 1
        DistributedPlayerToon.__init__(self, cr)
        BaseLocalAvatar.__init__(self)
        self.chatInputState = False
        self.avatarChoice = cr.localAvChoice
        self.chatInput = ChatInput()
        self.positionExaminer = PositionExaminer()
        self.friendRequestManager = FriendRequestManager()
        self.friendsList = FriendsList()
        self.questManager = QuestManager(self)
        self.questUpdateGUI = QuestUpdateGUI()
        self.panel = ToonPanel()
        self.firstTimeGenerating = True
        friendsgui = loader.loadModel(
            'phase_3.5/models/gui/friendslist_gui.bam')
        self.friendButton = DirectButton(
            geom=(friendsgui.find('**/FriendsBox_Closed'),
                  friendsgui.find('**/FriendsBox_Rollover'),
                  friendsgui.find('**/FriendsBox_Rollover')),
            text=("", "Friends", "Friends", ""),
            text_fg=(1, 1, 1, 1),
            text_shadow=(0, 0, 0, 1),
            text_scale=0.09,
            text_pos=(0, -0.18),
            relief=None,
            parent=base.a2dTopRight,
            pos=(-0.141, 0, -0.125),
            command=self.friendsButtonClicked,
            scale=0.8)
        friendsgui.removeNode()
        del friendsgui
        self.hideFriendButton()
        self.runSfx = base.loadSfx(
            "phase_3.5/audio/sfx/AV_footstep_runloop.ogg")
        self.runSfx.setLoop(True)
        self.walkSfx = base.loadSfx(
            "phase_3.5/audio/sfx/AV_footstep_walkloop.ogg")
        self.walkSfx.setLoop(True)
        self.offset = 3.2375
        self.firstPersonCamPos = None
        self.movementKeymap = {
            "forward": 0,
            "backward": 0,
            "left": 0,
            "right": 0,
            "jump": 0
        }
        self.avatarMovementEnabled = False
        self.isMoving_forward = False
        self.isMoving_side = False
        self.isMoving_back = False
        self.isMoving_jump = False
        self.gagThrowBtn = None

        self.pickerTrav = None
        self.pickerRay = None
        self.pickerRayNode = None
        self.pickerHandler = None
        self.rolledOverTag = None

        self.clickToonCallback = None

        self.inTutorial = False
        self.hasDoneJump = False
        self.lastState = None
        self.lastAction = None

        self.jumpHardLandIval = None

        # This is used by CutsceneGUI
        self.allowA2dToggle = True

        # This is used by the animation traverser.
        self.__traverseGUI = None

    def primaryFirePress(self):
        if not self.canUseGag():
            return

        DistributedPlayerToon.primaryFirePress(self)

    def primaryFireRelease(self):
        if not self.canUseGag():
            return

        DistributedPlayerToon.primaryFireRelease(self)

    def secondaryFirePress(self):
        if not self.canUseGag():
            return

        DistributedPlayerToon.secondaryFirePress(self)

    def secondaryFireRelease(self):
        if not self.canUseGag():
            return

        DistributedPlayerToon.secondaryFireRelease(self)

    def stopPlay(self):
        if not self.playState:
            self.notify.warning("Redundant call to stopPlay()")
            return

        self.hideBookButton()
        self.hideFriendButton()

        BaseLocalAvatar.stopPlay(self)

        self.stopTrackAnimToSpeed()

    def startPlay(self,
                  gags=False,
                  book=False,
                  friends=False,
                  laff=False,
                  chat=False,
                  wantMouse=1):
        if self.playState:
            self.notify.warning("Redundant call to startPlay()")
            return

        if book:
            self.showBookButton()
        if friends:
            self.showFriendButton()
        if chat:
            self.createChatInput()

        self.startTrackAnimToSpeed()

        BaseLocalAvatar.startPlay(self, gags, laff, wantMouse)

    def handleSuitAttack(self, attack):
        if self.isFirstPerson():
            self.getFPSCam().handleSuitAttack(attack)

    def areGagsAllowed(self):
        return (BaseLocalAvatar.areGagsAllowed(self) and
                (self.chatInput is not None
                 and self.chatInput.fsm.getCurrentState().getName() == 'idle'))

    def setEquippedAttack(self, gagId):
        DistributedPlayerToon.setEquippedAttack(self, gagId)
        BaseLocalAvatar.setEquippedAttack(self, gagId)

    def updateAttackAmmo(self, attackId, ammo, maxAmmo, ammo2, maxAmmo2, clip,
                         maxClip):
        DistributedPlayerToon.updateAttackAmmo(self, attackId, ammo, maxAmmo,
                                               ammo2, maxAmmo2, clip, maxClip)
        BaseLocalAvatar.updateAttackAmmo(self, attackId, ammo, maxAmmo, ammo2,
                                         maxAmmo2, clip, maxClip)

    def setupAttacks(self):
        DistributedPlayerToon.setupAttacks(self)
        BaseLocalAvatar.setupAttacks(self)

    def _handleWentInTunnel(self, requestStatus):
        self.cr.playGame.getPlace().doneStatus = requestStatus
        messenger.send(self.cr.playGame.getPlace().doneEvent)

    def _handleCameOutTunnel(self):
        self.wrtReparentTo(render)

        self.cr.playGame.getPlace().fsm.request(
            self.cr.playGame.getPlace().nextState)

    def handleClickedWhisper(self,
                             senderName,
                             fromId,
                             isPlayer,
                             openPanel=False):
        place = self.cr.playGame.getPlace()
        if place is None or not hasattr(place, 'fsm') or place.fsm is None:
            return

        if openPanel and place.fsm.getCurrentState().getName() in [
                'walk', 'shtickerBook'
        ]:
            self.panel.makePanel(fromId)

        self.chatInput.disableKeyboardShortcuts()
        self.chatInput.fsm.request('input', ["", fromId])

    def handleClickedSentWhisper(self, senderName, fromId, isPlayer):
        self.handleClickedWhisper(senderName, fromId, isPlayer, True)

    def hasDiscoveredHood(self, zoneId):
        return zoneId in self.hoodsDiscovered

    def hasTeleportAccess(self, zoneId):
        return zoneId in self.teleportAccess

    def tutorialCreated(self, zoneId):
        self.cr.tutorialCreated(zoneId)

    def friendsButtonClicked(self):
        self.hideFriendButton()
        self.friendsList.fsm.request('onlineFriendsList')

    def destroyFriendButton(self):
        if CIGlobals.isNodePathOk(self.friendButton):
            self.friendButton.destroy()
            self.friendButton = None

    def hideFriendButton(self):
        self.friendButton.hide()

    def showFriendButton(self):
        self.friendButton.show()

    def gotoNode(self, node, eyeHeight=3):
        possiblePoints = (Point3(0, 0, 0), Point3(3, 6, 0), Point3(-3, 6, 0),
                          Point3(6, 6, 0), Point3(-6, 6, 0), Point3(3, 9, 0),
                          Point3(-3, 9, 0), Point3(6, 9, 0), Point3(-6, 9, 0),
                          Point3(9, 9, 0), Point3(-9, 9, 0), Point3(6, 0, 0),
                          Point3(-6, 0, 0), Point3(6, 3, 0), Point3(-6, 3, 0),
                          Point3(9, 9, 0), Point3(-9, 9, 0), Point3(0, 12, 0),
                          Point3(3, 12, 0), Point3(-3, 12,
                                                   0), Point3(6, 12, 0),
                          Point3(-6, 12, 0), Point3(9, 12,
                                                    0), Point3(-9, 12, 0),
                          Point3(0, -6,
                                 0), Point3(-3, -6,
                                            0), Point3(0, -9,
                                                       0), Point3(-6, -9, 0))
        for point in possiblePoints:
            pos = self.positionExaminer.consider(node, point, eyeHeight)
            if pos:
                self.setPos(node, pos)
                self.lookAt(node)
                self.setHpr(self.getH() + random.choice((-10, 10)), 0, 0)
                return

        self.setPos(node, 0, 0, 0)

    def setFriendsList(self, friends):
        DistributedPlayerToon.setFriendsList(self, friends)
        self.cr.friendsManager.d_requestFriendsList()
        self.panel.maybeUpdateFriendButton()

    def d_requestAddFriend(self, avId):
        self.sendUpdate('requestAddFriend', [avId])

    def enablePicking(self):
        self.accept('toonClicked', self.toonClicked)

    def disablePicking(self):
        self.ignore('toonClicked')

    def toonClicked(self, avId):
        if not self.clickToonCallback:
            self.panel.makePanel(avId)
        else:
            self.clickToonCallback(avId)
            self.clickToonCallback = None

    def prepareToSwitchControlType(self):
        # Hack fix for getting stuck moving in one direction without pressing the movement keys.
        inputs = [
            "run", "forward", "reverse", "turnLeft", "turnRight", "slideLeft",
            "slideRight", "jump"
        ]
        for inputName in inputs:
            try:
                inputState.releaseInputs(inputName)
            except:
                pass

    def getBackpack(self):
        return DistributedPlayerToon.getBackpack(self)

    def enterReadBook(self, ts=0, callback=None, extraArgs=[]):
        self.stopLookAround()
        self.b_lookAtObject(0, -45, 0)
        DistributedPlayerToon.enterReadBook(self, ts, callback, extraArgs)

    def exitReadBook(self):
        DistributedPlayerToon.exitReadBook(self)
        self.startLookAround()

    def getAirborneHeight(self):
        return self.offset + 0.025000000000000001

    def setupControls(self):
        self.walkControls = CILocalControls()
        self.walkControls.setupControls()
        self.walkControls.setMode(
            CIGlobals.getSettingsMgr().getSetting("bpov").getValue())

    def setWalkSpeedNormal(self):
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed,
                                       CIGlobals.ToonJumpForce,
                                       CIGlobals.ToonReverseSpeed,
                                       CIGlobals.ToonRotateSpeed)

    def setWalkSpeedNormalNoJump(self):
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSpeed, 0.0,
                                       CIGlobals.ToonForwardSpeed,
                                       CIGlobals.ToonRotateSpeed)

    def setWalkSpeedSlow(self):
        self.walkControls.setWalkSpeed(CIGlobals.ToonForwardSlowSpeed,
                                       CIGlobals.ToonJumpSlowForce,
                                       CIGlobals.ToonReverseSlowSpeed,
                                       CIGlobals.ToonRotateSlowSpeed)

    def setDNAStrand(self, dnaStrand):
        DistributedPlayerToon.setDNAStrand(self, dnaStrand)
        if self.firstTimeGenerating:
            self.setupCamera()
            self.firstTimeGenerating = False

    def setMoney(self, money):
        DistributedPlayerToon.setMoney(self, money)

    def setupNameTag(self, tempName=None):
        DistributedPlayerToon.setupNameTag(self, tempName)
        self.nametag.setNametagColor(
            NametagGlobals.NametagColors[NametagGlobals.CCLocal])
        self.nametag.unmanage(base.marginManager)
        self.nametag.setActive(0)
        self.nametag.updateAll()

    def b_setAnimState(self, anim, callback=None, extraArgs=[]):
        if self.anim != anim:
            self.d_setAnimState(anim)
            DistributedPlayerToon.setAnimState(self,
                                               anim,
                                               callback=callback,
                                               extraArgs=extraArgs)

            camTransitionStates = ['teleportIn', 'teleportOut', 'died']
            if anim in camTransitionStates and not NO_TRANSITION in extraArgs:
                self.doFirstPersonCameraTransition()

    def enableAvatarControls(self, wantMouse=0):
        BaseLocalAvatar.enableAvatarControls(self, wantMouse)
        self.accept('jumpStart', self.__jump)

    def handleJumpLand(self):
        if self.jumpHardLandIval:
            self.jumpHardLandIval.finish()
            self.jumpHardLandIval = None
        if self.getHealth() > 0:
            self.b_setAnimState('Happy')

    def handleJumpHardLand(self):
        if self.jumpHardLandIval:
            self.jumpHardLandIval.finish()
            self.jumpHardLandIval = None
        self.jumpHardLandIval = ActorInterval(self, 'zend')
        self.jumpHardLandIval.setDoneEvent('LT::zend-done')
        self.acceptOnce('LT::zend-done', self.handleJumpLand)
        self.jumpHardLandIval.start()

    def disableAvatarControls(self, chat=False):
        BaseLocalAvatar.disableAvatarControls(self, chat)
        self.ignore('jumpStart')
        for k, _ in self.movementKeymap.items():
            self.updateMovementKeymap(k, 0)
        self.resetTorsoRotation()
        self.resetHeadHpr()

    def updateMovementKeymap(self, key, value):
        self.movementKeymap[key] = value

    def getMovementKeyValue(self, key):
        return self.movementKeymap[key]

    def playMovementSfx(self, movement):
        """ This previously was the main method of playing movement sfxs, but now this is only used for tunnels """

        if movement == 'run':
            self.walkSfx.stop()
            self.runSfx.play()
        elif movement == 'walk':
            self.runSfx.stop()
            self.walkSfx.play()
        else:
            self.runSfx.stop()
            self.walkSfx.stop()

    def __forward(self):
        self.resetHeadHpr()
        self.stopLookAround()
        if self.getHealth() < 1:
            self.setPlayRate(1.2, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.setAnimState('run')
        self.isMoving_side = False
        self.isMoving_back = False
        self.isMoving_forward = True
        self.isMoving_jump = False

    def __turn(self):
        self.resetHeadHpr()
        self.stopLookAround()
        if self.getHealth() < 1:
            self.setPlayRate(1.2, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.setPlayRate(1.0, "walk")
            self.setAnimState("walk")
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_side = True
        self.isMoving_jump = False

    def __reverse(self):
        self.resetHeadHpr()
        self.stopLookAround()
        if self.getHealth() < 1:
            self.setPlayRate(-1.0, 'dwalk')
            self.setAnimState('deadWalk')
        else:
            self.setAnimState("walkBack")
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = True
        self.isMoving_jump = False

    def __jump(self):
        if self.getHealth() > 0:
            if self.playingAnim in ['run', 'walk']:
                self.b_setAnimState("leap")
            else:
                self.b_setAnimState("jump")
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_jump = True

    def __neutral(self):
        self.resetHeadHpr()
        self.startLookAround()
        if self.getHealth() > 0:
            self.setAnimState("neutral")
        else:
            self.setPlayRate(1.0, 'dneutral')
            self.setAnimState("deadNeutral")
        self.isMoving_side = False
        self.isMoving_forward = False
        self.isMoving_back = False
        self.isMoving_jump = False

    def movementTask(self, task):
        if self.getMovementKeyValue("jump") == 1:
            if not self.walkControls.isAirborne:
                if self.walkControls.mayJump:
                    self.__jump()
                    self.hasDoneJump = True
                else:
                    if self.hasDoneJump:
                        if self.getHealth() > 0:
                            self.b_setAnimState('Happy')
                        self.hasDoneJump = False
        else:
            if not self.walkControls.isAirborne:
                if self.hasDoneJump:
                    if self.getHealth() > 0:
                        self.b_setAnimState('Happy')
                    self.hasDoneJump = False
        return task.cont

    def startTrackAnimToSpeed(self):
        if not base.taskMgr.hasTaskNamed(self.uniqueName('trackAnimToSpeed')):
            base.taskMgr.add(self.trackAnimToSpeed,
                             self.uniqueName('trackAnimToSpeed'))

    def stopTrackAnimToSpeed(self):
        base.taskMgr.remove(self.uniqueName('trackAnimToSpeed'))

    def trackAnimToSpeed(self, task):
        slideSpeed, speed, rotSpeed = self.walkControls.getSpeeds()
        state = None
        if self.isSwimming:
            state = 'swim'
        else:
            if self.getHealth() > 0:
                state = 'Happy'
            else:
                state = 'Sad'
        if state != self.lastState:
            self.lastState = state
            self.b_setAnimState(state)
            if base.minigame is None and not self.battleControls:
                if state == 'Sad' and not self.isSwimming:
                    self.setWalkSpeedSlow()
                else:
                    self.setWalkSpeedNormal()
        action = self.setSpeed(speed, rotSpeed, slideSpeed)
        if action != self.lastAction:
            self.lastAction = action
            if action == CIGlobals.WALK_INDEX:
                self.resetHeadHpr()
                self.stopLookAround()
            elif action == CIGlobals.RUN_INDEX or action in [
                    CIGlobals.STRAFE_LEFT_INDEX, CIGlobals.STRAFE_RIGHT_INDEX
            ] or action == CIGlobals.REVERSE_INDEX:
                self.resetHeadHpr()
                self.stopLookAround()
            else:
                self.resetHeadHpr()
                self.stopLookAround()
                if self.walkControls.mode == self.walkControls.MThirdPerson:
                    if state == 'Happy':
                        self.startLookAround()
        return task.cont

    def setLoadout(self, gagIds):
        DistributedPlayerToon.setLoadout(self, gagIds)
        place = base.cr.playGame.getPlace()
        if place and place.fsm.getCurrentState().getName() == 'shtickerBook':
            if hasattr(place, 'shtickerBookStateData'):
                stateData = place.shtickerBookStateData
                if stateData.getCurrentPage() is not None:
                    if stateData.getCurrentPage().title == 'Gags':
                        stateData.getCurrentPage().gui.fsm.request('idle')

    def resetHeadHpr(self, override=False):
        if self.lookMode == self.LMOff or not self.walkControls.controlsEnabled or override:
            self.b_lookAtObject(0, 0, 0, blink=0)

    def checkSuitHealth(self, suit):
        pass

    def handleLookSpot(self, hpr):
        h, p, r = hpr
        self.d_lookAtObject(h, p, r, blink=1)

    def showBookButton(self, inBook=0):
        self.book_gui = loader.loadModel(
            "phase_3.5/models/gui/stickerbook_gui.bam")
        self.book_btn = DirectButton(
            image=(self.book_gui.find('**/BookIcon_CLSD'),
                   self.book_gui.find('**/BookIcon_OPEN'),
                   self.book_gui.find('**/BookIcon_RLVR')),
            relief=None,
            pos=(-0.158, 0, 0.17),
            command=self.bookButtonClicked,
            scale=0.305,
            parent=base.a2dBottomRight)
        self.book_btn.setBin('gui-popup', 60)
        if inBook:
            self.book_btn["image"] = (self.book_gui.find('**/BookIcon_OPEN'),
                                      self.book_gui.find('**/BookIcon_CLSD'),
                                      self.book_gui.find('**/BookIcon_RLVR2'))
            self.book_btn["command"] = self.bookButtonClicked
            self.book_btn["extraArgs"] = [0]

    def hideBookButton(self):
        if hasattr(self, 'book_gui'):
            self.book_gui.removeNode()
            del self.book_gui
        if hasattr(self, 'book_btn'):
            self.book_btn.destroy()
            del self.book_btn

    def bookButtonClicked(self, openIt=1):
        if openIt:
            base.cr.playGame.getPlace().fsm.request('shtickerBook')
        else:
            base.cr.playGame.getPlace().shtickerBookStateData.finishedResume()

    def handleHealthChange(self, hp, oldHp):
        if hp > 0 and oldHp < 1:
            if self.cr.playGame and self.cr.playGame.getPlace():
                if self.cr.playGame.getPlace().fsm.getCurrentState().getName(
                ) == 'walk':
                    if self.cr.playGame.getPlace(
                    ).walkStateData.fsm.getCurrentState().getName(
                    ) == 'deadWalking':
                        self.cr.playGame.getPlace().walkStateData.fsm.request(
                            'walking')
            if self.animFSM.getCurrentState().getName() == 'deadNeutral':
                self.b_setAnimState("neutral")
            elif self.animFSM.getCurrentState().getName() == 'deadWalk':
                self.b_setAnimState("run")

        BaseLocalAvatar.handleHealthChange(self, hp, oldHp)

        DistributedPlayerToon.handleHealthChange(self, hp, oldHp)

    def setSessionHealth(self, hp):
        currHp = self.getSessionHealth()

        self.handleHealthChange(hp, currHp)

        DistributedPlayerToon.setSessionHealth(self, hp)

    def reparentTo(self, parent):
        self.notify.debug("Local toon reparent to {0}".format(
            parent.node().getName()))
        DistributedPlayerToon.reparentTo(self, parent)

    def wrtReparentTo(self, parent):
        self.notify.debug("Local toon wrtReparent to {0}".format(
            parent.node().getName()))
        DistributedPlayerToon.wrtReparentTo(self, parent)

    def loadAvatar(self):
        DistributedPlayerToon.loadAvatar(self)
        base.avatars.remove(self)

    def diedStateDone(self, requestStatus):
        hood = self.cr.playGame.hood.id
        if hood == ZoneUtil.BattleTTC:
            hood = ZoneUtil.ToontownCentral
        toZone = ZoneUtil.getZoneId(hood)
        if self.zoneId != toZone:
            requestStatus = {
                'zoneId': toZone,
                'hoodId': hood,
                'where': ZoneUtil.getWhereName(toZone),
                'avId': self.doId,
                'loader': ZoneUtil.getLoaderName(toZone),
                'shardId': None,
                'wantLaffMeter': 1,
                'how': 'teleportIn'
            }
            self.cr.playGame.getPlace().doneStatus = requestStatus
            messenger.send(self.cr.playGame.getPlace().doneEvent)
        else:
            return

    def teleportToCT(self):
        toZone = ZoneUtil.CogTropolisId
        hood = ZoneUtil.CogTropolis
        requestStatus = {
            'zoneId': toZone,
            'hoodId': hood,
            'where': ZoneUtil.getWhereName(toZone),
            'avId': self.doId,
            'loader': ZoneUtil.getLoaderName(toZone),
            'shardId': None,
            'wantLaffMeter': 1,
            'how': 'teleportIn'
        }
        self.cr.playGame.getPlace().fsm.request('teleportOut', [requestStatus])

    def setQuests(self, dataStr):
        oldDataStr = self.quests
        DistributedPlayerToon.setQuests(self, dataStr)
        self.questManager.makeQuestsFromData()

        # Let's send our quest data update event.
        messenger.send(QUEST_DATA_UPDATE_EVENT, [oldDataStr, dataStr])

    def createChatInput(self):
        if not self.chatInputState:
            self.chatInput.load()
            self.chatInput.enter()
            self.chatInputState = True

    def disableChatInput(self):
        if self.chatInputState:
            self.chatInput.exit()
            self.chatInput.unload()
            self.chatInputState = False

    def toggleAspect2d(self):
        if self.allowA2dToggle:
            if base.aspect2d.isHidden():
                base.aspect2d.show()
            else:
                base.aspect2d.hide()

    def startTraverseAnimationControls(self, animName):
        if not self.__traverseGUI:
            if not self.getNumFrames(animName) is None:
                frame = self.getCurrentFrame(animName)

                if frame is None:
                    frame = 0
                    self.pose(animName, 0)

                self.accept('h',
                            self.__traverseAnimation,
                            extraArgs=[animName, -1])
                self.accept('j',
                            self.__traverseAnimation,
                            extraArgs=[animName, 1])

                self.__traverseGUI = OnscreenText(
                    text=
                    'Current Frame: {0}\n\'H\' Decrease Frame, \'J\' Increase Frame'
                    .format(str(frame)),
                    pos=(0, -0.75),
                    font=CIGlobals.getToonFont(),
                    fg=(1, 1, 1, 1),
                    shadow=(0, 0, 0, 1))
            else:
                self.notify.info(
                    'Tried to traverse unknown animation: {0}'.format(
                        animName))

    def __traverseAnimation(self, animName, delta):
        frame = self.getCurrentFrame(animName)
        if frame is None:
            frame = 0

        if (frame + delta) < 0:
            frame = self.getNumFrames(animName) - 1
        elif (frame + delta) > (self.getNumFrames(animName) - 1):
            frame = self.getNumFrames(animName) - 1
        else:
            frame += delta
        self.pose(animName, frame)
        self.__traverseGUI.setText(
            'Current Frame: {0}\n\'H\' Decrease Frame, \'J\' Increase Frame'.
            format(str(frame)))

    def endTraverseAnimationControls(self):
        self.ignore('h')
        self.ignore('j')

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

    def generate(self):
        DistributedPlayerToon.generate(self)

    def delete(self):
        DistributedPlayerToon.delete(self)
        self.deleteLaffMeter()
        return

    def disable(self):
        DistributedPlayerToon.disable(self)

        self.stopTrackAnimToSpeed()
        base.camLens.setMinFov(CIGlobals.OriginalCameraFov / (4. / 3.))
        if self.jumpHardLandIval:
            self.ignore('LT::zend-done')
            self.jumpHardLandIval.finish()
            self.jumpHardLandIval = None
        if self.friendsList:
            self.friendsList.destroy()
            self.friendsList = None
        if self.panel:
            self.panel.cleanup()
            self.panel = None
        if self.positionExaminer:
            self.positionExaminer.delete()
            self.positionExaminer = None
        self.disablePicking()
        self.destroyFriendButton()
        self.stopLookAround()
        self.disableAvatarControls()
        self.destroyControls()
        if self.smartCamera:
            self.smartCamera.stopUpdateSmartCamera()
            self.smartCamera.deleteSmartCameraCollisions()
            self.smartCamera = None
        if self.questManager:
            self.questManager.cleanup()
            self.questManager = None
        if self.questUpdateGUI:
            self.questUpdateGUI.cleanup()
            self.questUpdateGUI = None
        if self.friendRequestManager:
            self.friendRequestManager.cleanup()
            self.friendRequestManager = None
        self.destroyInvGui()
        if self.crosshair:
            self.crosshair.destroy()
            self.crosshair = None
        self.disableLaffMeter()
        self.disableGags()
        self.disableChatInput()
        self.hideBookButton()
        self.weaponType = None
        self.runSfx = None
        self.walkSfx = None
        self.offset = None
        self.movementKeymap = None
        self.minigame = None
        self.inTutorial = None
        self.avatarChoice = None
        self.chatInputState = None
        self.playState = None
        self.endTraverseAnimationControls()
        self.ignore("gotLookSpot")
        self.ignore("clickedWhisper")
        self.ignore('/')
        self.ignore(base.inputStore.ToggleAspect2D)
        return

    def delete(self):
        DistributedPlayerToon.delete(self)
        del base.localAvatar
        del __builtins__['localAvatar']
        print "Local avatar finally deleted"

    def sewerHeadOff(self, zoneId):
        # TEMPORARY
        requestStatus = {
            'zoneId': zoneId,
            'hoodId': 0,
            'where': 'sewer',
            'avId': self.doId,
            'loader': 'sewer',
            'shardId': None,
            'wantLaffMeter': 1
        }
        self.cr.playGame.getPlace().fsm.request('teleportOut', [requestStatus])

    def announceGenerate(self):
        DistributedPlayerToon.announceGenerate(self)
        self.setupControls()
        self.startLookAround()
        self.friendRequestManager.watch()
        self.accept("gotLookSpot", self.handleLookSpot)
        self.accept("clickedWhisper", self.handleClickedSentWhisper)
        self.accept(base.inputStore.ToggleAspect2D, self.toggleAspect2d)

        if not metadata.IS_PRODUCTION:
            self.acceptOnce('m', self.sendUpdate, ['reqMakeSewer'])
            self.accept('l', render.ls)
            self.accept('/', self.printPos)
            self.accept('\\', self.printPos_cam)

        #self.accept('c', self.walkControls.setCollisionsActive, [0])

        self.createInvGui()

        # Unused developer methods.
        #self.accept('p', self.enterPictureMode)
        #self.accept('c', self.teleportToCT)
        #posBtn = DirectButton(text = "Get Pos", scale = 0.08, pos = (0.3, 0, 0), parent = base.a2dLeftCenter, command = self.printAvPos)

    def enterHiddenToonMode(self):
        self.laffMeter.stop()
        self.laffMeter.disable()
        self.laffMeter.destroy()
        self.getGeomNode().hide()
        self.deleteNameTag()
        self.invGui.disable()
        self.hideFriendButton()
        self.hideBookButton()
        self.removeAdminToken()