Example #1
0
 def __makeHeadMeter(self):
     self.headMeter = LaffOMeter(forRender=True)
     r, g, b, _ = self.getHeadColor()
     animal = self.getAnimal()
     maxHp = self.getMaxHealth()
     hp = self.getHealth()
     self.headMeter.generate(r, g, b, animal, maxHP=maxHp, initialHP=hp)
     self.headMeter.reparentTo(self)
     self.headMeter.setZ(self.getHeight() + 2)
     self.headMeter.setScale(0.4)
     self.headMeter.setBillboardAxis()
     self.__updateHeadMeter()
Example #2
0
 def makeBattleMeter(self):
     if self.getHealth() < self.getMaxHealth():
         if not self.battleMeter:
             self.battleMeter = LaffOMeter()
             r, g, b, _ = self.getHeadColor()
             animal = self.getAnimal()
             maxHp = self.getMaxHealth()
             hp = self.getHealth()
             self.battleMeter.generate(r,
                                       g,
                                       b,
                                       animal,
                                       maxHP=maxHp,
                                       initialHP=hp)
             self.battleMeter.reparentTo(self)
             self.battleMeter.setZ(self.getHeight() + 5)
             self.battleMeter.setScale(0.5)
             self.battleMeter.start()
 def __init__(self):
     self.walkControls = None
     self.laffMeter = LaffOMeter()
     self.smartCamera = SmartCamera()
     self.crosshair = Crosshair()
     self.crosshair.hide()
     self.doId = 0
     self.defaultShard = 0
     self.avatarMovementEnabled = False
     self.isSwimming = False
     self.touchingWater = False
     self.invGui = None
     self.playState = False
     self.battleControls = False
     self.selectedGag = -1
     self.lastSelectedGag = -1
     self.needsToSwitchToGag = None
     self.gagsEnabled = False
     self.gagsTimedOut = False
    def setup(self):
        if self.reward.rewardType == 1:
            # This is a jellybeans reward.
            self.setPos(QuestGlobals.LEFT_JB_JAR_POS)
            self.info['text'] = str(self.reward.rewardValue)
        elif self.reward.rewardType == 2:
            # This is a teleport access reward.
            self['image'] = QuestGlobals.getTPAccessIcon()
            self['image_scale'] = QuestGlobals.TP_ACCESS_SCALE
            self.setPos(QuestGlobals.LEFT_TP_ACCESS_POS)
            self.info['text'] = ZoneUtil.ZoneId2HoodAbbr[
                self.reward.rewardValue]
            self.info.setPos(-0.0025, 0, -0.04)
        elif self.reward.rewardType == 3:
            # This is a laff boost reward.
            r, g, b, _ = base.localAvatar.getHeadColor()
            hp = base.localAvatar.getMaxHealth() + self.reward.rewardValue
            laffMeter = LaffOMeter()
            laffMeter.generate(r,
                               g,
                               b,
                               base.localAvatar.getAnimal(),
                               maxHP=hp,
                               initialHP=hp)
            self['image'] = laffMeter
            self['image_scale'] = QuestGlobals.LAFF_METER_SCALE
            self.setPos(QuestGlobals.LEFT_LAFF_METER_POS)
            self.info['text'] = '+%d' % self.reward.rewardValue
            self.info.setPos(0, 0, -0.05)
            laffMeter.destroy()
        elif self.reward.rewardType == 5:
            # This is a gag slot reward.
            icon = QuestGlobals.getGagSlotIcon(self.reward.rewardValue)
            self['image'] = icon
            self['image_scale'] = QuestGlobals.GAG_SLOT_ICON_SCALE
            self.setTransparency(TransparencyAttrib.MAlpha)
            self.setPos(QuestGlobals.LEFT_GAG_SLOT_POS)
            self.info.hide()

        self.show()
    def update(self):
        objective = self.quest.getCurrentObjective()
        objective.updateInfo()

        # Let's setup the quest info.
        self.questInfo.setPos(self.quest.getInfoPos())
        self.questInfo['text'] = self.quest.getInfoText()
        self.questInfo02.setPos(self.quest.getInfo02Pos())
        self.questInfo02['text'] = self.quest.getInfo02Text()
        
        # Let's move the picture frames to the positions we want them in.
        self.lPictureFrame.setPos(self.quest.getLeftPicturePos())
        self.rPictureFrame.setPos(self.quest.getRightPicturePos())
        
        editLeftAtr = isinstance(objective, VisitNPCObjective) or isinstance(objective, CogObjective)
        if editLeftAtr and objective.getDidEditLeft() or not editLeftAtr:
            geom = self.quest.getLeftIconGeom()
            scale = self.quest.getLeftIconScale()
            icon = self.lQuestIcon
            self.handleIcon(objective, geom, scale, icon)
            self.handleIcon(objective, self.quest.getRightIconGeom(), self.quest.getRightIconScale(), self.rQuestIcon)
        else:
            geom = self.quest.getRightIconGeom()
            scale = self.quest.getRightIconScale()
            icon = self.rQuestIcon
            self.handleIcon(objective, geom, scale, icon)
            self.handleIcon(objective, self.quest.getLeftIconGeom(), self.quest.getLeftIconScale(), self.lQuestIcon)

        if self.questInfo02['text'] == '':
            self.rPictureFrame.hide()
            self.questInfo02.hide()
        else:
            self.rPictureFrame.show()
            self.questInfo02.show()

        self.middleText['text'] = self.quest.getMiddleText()
        if not self.middleText['text'] == '':
            self.middleText.show()

        self.questInfo.show()
        self.lPictureFrame.show()

        # Let's set the location text.
        self.locationInfo['text'] = self.quest.getLocationText()
        self.locationInfo['text_pos'] = (0, self.quest.getLocationY())
        self.locationInfo.show()

        # Let's set the progress bar up.
        self.questProgress['text'] = self.quest.getProgressText()
        if len(self.questProgress['text']) > 0 and not objective.finished():
            self.questProgress.show()
            self.questProgress['range'] = objective.getNeededAmount()
            self.questProgress['value'] = objective.getProgress() & pow(2, 16) - 1
        else:
            self.questProgress.hide()

        # Let's setup the aux text.
        self.auxText.setPos(self.quest.getAuxPos())
        self.auxText['text'] = self.quest.getAuxText()
        self.auxText.show()

        maxHP = base.localAvatar.getMaxHealth()
        
        # Let's setup the rewards.
        for i in xrange(0, len(self.quest.getRewards())):
            reward = self.quest.getRewards()[i]
            frame = self.lRewardFrame if (i == 0) else self.rRewardFrame
            info = self.lRewardAmt if (i == 0) else self.rRewardAmt
            rType = reward.getType()
            if(rType == RewardType.JELLYBEANS):
                frame['pos'] = QuestGlobals.LEFT_JB_JAR_POS if (i == 0) else QuestGlobals.RIGHT_JB_JAR_POS
                frame['geom'] = QuestGlobals.getJBIcon()
                frame['geom_scale'] = QuestGlobals.JB_JAR_SCALE
                info['text'] = str(reward.getModifier())
            elif(rType == RewardType.TELEPORT_ACCESS or rType == RewardType.GAG_FRAME):
                frame['pos'] = QuestGlobals.LEFT_TP_ACCESS_POS if(i == 0) else QuestGlobals.RIGHT_TP_ACCESS_POS
                frame['geom'] = QuestGlobals.getTPAccessIcon() if(rType == RewardType.TELEPORT_ACCESS) else QuestGlobals.getFilmIcon()
                frame['geom_scale'] = QuestGlobals.TP_ACCESS_SCALE
                info['text'] = 'N/A' if(rType == RewardType.TELEPORT_ACCESS) else '#%s' % (str(reward.getModifier()))
            elif(rType == RewardType.LAFF_POINTS):
                frame.initialiseoptions(DirectFrame)
                r, g, b, _ = base.localAvatar.getHeadColor()
                pos = QuestGlobals.LEFT_LAFF_METER_POS if(i == 0) else QuestGlobals.RIGHT_LAFF_METER_POS

                # Create the laff meter with the new health.
                hp = maxHP + reward.getModifier()
                laffMeter = LaffOMeter()
                laffMeter.generate(r, g, b, base.localAvatar.getAnimal(), maxHP = hp, initialHP = hp)

                # Let's position the laff meter.
                frame['geom'] = laffMeter
                frame['geom_scale'] = QuestGlobals.LAFF_METER_SCALE
                frame.setPos(pos)
                info['text'] = '+%s' % (str(reward.getModifier()))
                laffMeter.destroy()
                laffMeter = None

        # Hide or show the other reward depending on if there's 2 rewards.
        if(len(self.quest.getRewards()) == 1):
            self.rRewardFrame.hide()
            self.rRewardAmt.hide()
        else:
            self.rRewardFrame.show()
            self.rRewardAmt.show()

        if objective.finished():
            self.setColor(Vec4(*QuestGlobals.LIGHT_GREEN))
            self.sideInfo['text'] = 'Completed!'
            self.sideInfo.show()
            
        self.questInfo.initialiseoptions(DirectLabel)
        self.questInfo02.initialiseoptions(DirectLabel)
        self.locationInfo.initialiseoptions(DirectLabel)
        self.lPictureFrame.initialiseoptions(DirectFrame)
        self.rPictureFrame.initialiseoptions(DirectFrame)
        self.lQuestIcon.initialiseoptions(DirectFrame)
        self.rQuestIcon.initialiseoptions(DirectFrame)
        self.auxText.initialiseoptions(DirectLabel)
        self.middleText.initialiseoptions(DirectLabel)
        self.sideInfo.initialiseoptions(DirectLabel)
        self.lPictureFrame['image_color'] = self.quest.getPictureFrameColor()
        self.rPictureFrame['image_color'] = self.quest.getPictureFrameColor()
Example #6
0
    def update(self):
        objective = self.quest.getCurrentObjective()
        objective.setupQuestPoster()

        # Let's setup the picture frames and info.
        self.questInfo.setPos(self.quest.getInfoPos())
        self.questInfo['text'] = self.quest.getInfoText()
        self.questInfo02.setPos(self.quest.getInfo02Pos())
        self.questInfo02['text'] = self.quest.getInfo02Text()
        self.lPictureFrame.setPos(self.quest.getLeftPicturePos())
        self.rPictureFrame.setPos(self.quest.getRightPicturePos())
        self.lQuestIcon['geom'] = self.quest.getLeftIconGeom()
        if isinstance(objective, VisitNPCObjective) or isinstance(
                objective, DefeatObjective):
            if objective.getDidEditLeft():
                head = self.quest.getLeftIconGeom()
                icon = self.lQuestIcon
                scale = self.quest.getLeftIconScale()
            else:
                head = self.quest.getRightIconGeom()
                icon = self.rQuestIcon
                scale = self.quest.getRightIconScale()

            isHead = True if type(head) == ToonHead else head.getName() == (
                '%sHead' % CIGlobals.Suit)

            if isHead:
                head.setDepthWrite(1)
                head.setDepthTest(1)
                self.fitGeometry(head, fFlip=1)
            else:
                icon.setScale(scale)

            if isinstance(objective,
                          VisitNPCObjective) and icon == self.rQuestIcon:
                icon.setHpr(180, 0, 0)
                icon.setPos(icon.getX(), icon.getY(), icon.getZ() + 0.05)
            elif isinstance(objective, CogObjective):
                if icon == self.lQuestIcon:
                    if objective.cog != QuestGlobals.Any:
                        icon.setScale(QuestGlobals.IMAGE_SCALE_SMALL)
                        icon.setPos(icon.getX(), icon.getY(),
                                    icon.getZ() - 0.04)
                    else:
                        head.setScale(self.quest.getLeftIconScale())
                else:
                    if objective.cog != QuestGlobals.Any:
                        head.setScale(1.2)
                    else:
                        icon.setScale(self.quest.getRightIconScale())

            icon['geom'] = head
            icon['geom_scale'] = QuestGlobals.IMAGE_SCALE_SMALL

            #self.lQuestIcon['geom_hpr'] = (180, 0, 0)
            #self.lQuestIcon['geom_pos'] = (0, 10, -0.04)
        else:
            self.lQuestIcon['geom'] = self.quest.getLeftIconGeom()
            self.lQuestIcon['geom_scale'] = self.quest.getLeftIconScale()
        #self.rQuestIcon['geom'] = self.quest.getRightIconGeom()
        #self.rQuestIcon['geom_scale'] = self.quest.getRightIconScale()

        if self.questInfo02['text'] == '':
            self.rPictureFrame.hide()
            self.questInfo02.hide()
        else:
            self.rPictureFrame.show()
            self.questInfo02.show()

        self.middleText['text'] = self.quest.getMiddleText()
        if not self.middleText['text'] == '':
            self.middleText.show()

        self.questInfo.show()
        self.lPictureFrame.show()

        # Let's set the location text.
        self.locationInfo['text'] = self.quest.getLocationText()
        self.locationInfo['text_pos'] = (0, self.quest.getLocationY())
        self.locationInfo.show()

        # Let's set the progress bar up.
        if self.quest.currentObjective.HasProgress:
            self.questProgress['text'] = self.quest.getProgressText()
            if len(self.questProgress['text']
                   ) > 0 and not objective.isComplete():
                self.questProgress.show()
                self.questProgress['range'] = objective.goal
                self.questProgress['value'] = objective.getProgress() & pow(
                    2, 16) - 1
            else:
                self.questProgress.hide()

        # Let's setup the aux text.
        self.auxText.setPos(self.quest.getAuxPos())
        self.auxText['text'] = self.quest.getAuxText()
        self.auxText.show()

        maxHP = base.localAvatar.getMaxHealth()

        # Let's setup the rewards.
        for i in xrange(0, len(self.quest.getRewards())):
            reward = self.quest.getRewards()[i]
            frame = self.lRewardFrame if (i == 0) else self.rRewardFrame
            info = self.lRewardInfo if (i == 0) else self.rRewardInfo
            rType = reward.getType()
            if (rType == RewardType.JELLYBEANS):
                frame['pos'] = QuestGlobals.LEFT_JB_JAR_POS if (
                    i == 0) else QuestGlobals.RIGHT_JB_JAR_POS
                frame['geom'] = QuestGlobals.getJBIcon()
                frame['geom_scale'] = QuestGlobals.JB_JAR_SCALE
                info['text'] = str(reward.getModifier())
            elif (rType == RewardType.TELEPORT_ACCESS
                  or rType == RewardType.GAG_FRAME):
                frame['pos'] = QuestGlobals.LEFT_TP_ACCESS_POS if (
                    i == 0) else QuestGlobals.RIGHT_TP_ACCESS_POS
                frame['geom'] = QuestGlobals.getTPAccessIcon() if (
                    rType == RewardType.TELEPORT_ACCESS
                ) else QuestGlobals.getFilmIcon()
                frame['geom_scale'] = QuestGlobals.TP_ACCESS_SCALE
                info['text'] = 'N/A' if (
                    rType == RewardType.TELEPORT_ACCESS
                ) else '#%s' % (str(reward.getModifier()))
            elif (rType == RewardType.LAFF_POINTS):
                frame.initialiseoptions(DirectFrame)
                r, g, b, _ = base.localAvatar.getHeadColor()
                pos = QuestGlobals.LEFT_LAFF_METER_POS if (
                    i == 0) else QuestGlobals.RIGHT_LAFF_METER_POS

                # Create the laff meter with the new health.
                hp = maxHP + reward.getModifier()
                laffMeter = LaffOMeter()
                laffMeter.generate(r,
                                   g,
                                   b,
                                   base.localAvatar.getAnimal(),
                                   maxHP=hp,
                                   initialHP=hp)

                # Let's position the laff meter.
                frame['geom'] = laffMeter
                frame['geom_scale'] = QuestGlobals.LAFF_METER_SCALE
                frame.setPos(pos)
                info['text'] = '+%s' % (str(reward.getModifier()))
                laffMeter.destroy()
                laffMeter = None

        # Hide or show the other reward depending on if there's 2 rewards.
        if (len(self.quest.getRewards()) == 1):
            self.rRewardFrame.hide()
            self.rRewardInfo.hide()
        else:
            self.rRewardFrame.show()
            self.rRewardInfo.show()

        if objective.finished():
            self.setColor(Vec4(*QuestGlobals.LIGHT_GREEN))
            self.sideInfo['text'] = 'Completed!'
            self.sideInfo.show()

        self.questInfo.initialiseoptions(DirectLabel)
        self.questInfo02.initialiseoptions(DirectLabel)
        self.locationInfo.initialiseoptions(DirectLabel)
        self.lPictureFrame.initialiseoptions(DirectFrame)
        self.rPictureFrame.initialiseoptions(DirectFrame)
        self.lQuestIcon.initialiseoptions(DirectFrame)
        self.rQuestIcon.initialiseoptions(DirectFrame)
        self.auxText.initialiseoptions(DirectLabel)
        self.middleText.initialiseoptions(DirectLabel)
        #self.lRewardFrame.initialiseoptions(DirectFrame)
        #self.rRewardFrame.initialiseoptions(DirectFrame)
        self.sideInfo.initialiseoptions(DirectLabel)
        self.lPictureFrame['image_color'] = self.quest.getPictureFrameColor()
        self.rPictureFrame['image_color'] = self.quest.getPictureFrameColor()
Example #7
0
class DistributedPlayerToon(DistributedToon, DistributedPlayerToonShared):
    notify = directNotify.newCategory('DistributedPlayerToon')

    def __init__(self, cr):
        try:
            self.DistributedPlayerToon_initialized
            return
        except:
            self.DistributedPlayerToon_initialized = 1
        DistributedToon.__init__(self, cr)
        DistributedPlayerToonShared.__init__(self)
        self.role = None
        self.ghost = 0
        self.puInventory = []
        self.equippedPU = -1
        self.backpack = Backpack(self)
        self.battleMeter = None
        self.headMeter = None
        self.firstTimeChangingHP = True

        # Quest-related variables.
        self.quests = ""
        self.tier = None
        self.questHistory = None

        self.busy = 1
        self.friends = None
        self.tutDone = 0
        self.hoodsDiscovered = []
        self.teleportAccess = []
        self.lastHood = 0
        self.defaultShard = 0
        self.tunnelTrack = None
        self.trackExperience = dict(GagGlobals.DefaultTrackExperiences)

        self.takeDmgSfx = base.audio3d.loadSfx(
            'phase_5/audio/sfx/tt_s_ara_cfg_toonHit.ogg')
        base.audio3d.attachSoundToObject(self.takeDmgSfx, self)
        return

    def getHealth(self):
        return DistributedPlayerToonShared.getHealth(self)

    def getMaxHealth(self):
        return DistributedPlayerToonShared.getMaxHealth(self)

    def stopSmooth(self):
        DistributedToon.stopSmooth(self)
        localAvatarReachable = (hasattr(base, 'localAvatar')
                                and base.localAvatar)
        if localAvatarReachable and self.doId != base.localAvatar.doId:
            self.resetTorsoRotation()

    def handleHealthChange(self, hp, oldHp):
        if hp < oldHp and not self.firstTimeChangingHP:
            # We took damage, make oof sound.
            self.takeDmgSfx.play()

    def setHealth(self, health):
        self.handleHealthChange(health, self.getHealth())
        DistributedToon.setHealth(self, health)
        if self.doId != base.localAvatar.doId:
            if not self.firstTimeChangingHP:
                if health < self.getMaxHealth():
                    if not self.headMeter:
                        self.__makeHeadMeter()
                    else:
                        self.__updateHeadMeter()
                else:
                    self.__removeHeadMeter()
        self.firstTimeChangingHP = False

    def announceHealthAndPlaySound(self, level, hp, extraId=-1):
        DistributedToon.announceHealth(self, level, hp, extraId)
        hpSfx = base.audio3d.loadSfx('phase_11/audio/sfx/LB_toonup.ogg')
        base.audio3d.attachSoundToObject(hpSfx, self)
        SoundInterval(hpSfx, node=self).start()
        del hpSfx

    def setChat(self, chat):
        chat = ChatGlobals.filterChat(chat, self.animal)
        DistributedToon.setChat(self, chat)

    def goThroughTunnel(self, toZone, inOrOut, requestStatus=None):
        # inOrOut: 0 = in; 1 = out

        if self.tunnelTrack:
            self.ignore(self.tunnelTrack.getDoneEvent())
            self.tunnelTrack.finish()
            self.tunnelTrack = None

        linkTunnel = LinkTunnel.getTunnelThatGoesToZone(toZone)
        if not linkTunnel:
            return
        self.tunnelTrack = Parallel(
            name=self.uniqueName('Place.goThroughTunnel'))

        if inOrOut == 0:
            # Going in a tunnel!
            pivotPoint = linkTunnel.inPivotPoint
            pivotPointNode = linkTunnel.tunnel.attachNewNode(
                'tunnelPivotPoint')
            pivotPointNode.setPos(pivotPoint)
            pivotPointNode.setHpr(linkTunnel.inPivotStartHpr)

            x, y, z = self.getPos(render)
            surfZ = PhysicsUtils.getNearestGroundSurfaceZ(
                self,
                self.getHeight() + self.getHeight() / 2.0)

            if not surfZ == -1:
                # Let's use the ray-tested surface z-point instead so we don't come out of the tunnel hovering.
                # This is just in case the user jumped into the tunnel, which in that case would mean that they are
                # airborne and we can't depend on their current Z value.
                z = surfZ

            if base.localAvatar.doId == self.doId:
                doneMethod = self._handleWentInTunnel
                extraArgs = [requestStatus]
                base.localAvatar.walkControls.setCollisionsActive(
                    0, andPlaceOnGround=1)
                self.resetHeadHpr(override=True)
                camera.wrtReparentTo(linkTunnel.tunnel)
                currCamPos = camera.getPos()
                currCamHpr = camera.getHpr()
                tunnelCamPos = linkTunnel.camPos
                tunnelCamHpr = linkTunnel.camHpr
                camera.setPos(tunnelCamPos)
                camera.setHpr(tunnelCamHpr)
                self.tunnelTrack.append(
                    LerpPosInterval(camera,
                                    duration=0.7,
                                    pos=tunnelCamPos,
                                    startPos=currCamPos,
                                    blendType='easeOut'))
                self.tunnelTrack.append(
                    LerpQuatInterval(camera,
                                     duration=0.7,
                                     quat=tunnelCamHpr,
                                     startHpr=currCamHpr,
                                     blendType='easeOut'))

            self.wrtReparentTo(pivotPointNode)
            self.setPos(x, y, z)
            self.resetTorsoRotation()
            self.stopLookAround()

            if linkTunnel.__class__.__name__ == "SafeZoneLinkTunnel":
                self.setHpr(180, 0, 0)
            else:
                self.setHpr(0, 0, 0)

            exitSeq = Sequence(Func(self.loop, 'run'))
            if base.localAvatar.doId == self.doId:
                exitSeq.append(Wait(2.0))
                exitSeq.append(Func(base.transitions.irisOut))
            self.tunnelTrack.append(exitSeq)
            self.tunnelTrack.append(
                Sequence(
                    LerpHprInterval(
                        pivotPointNode,
                        duration=2.0,
                        hpr=linkTunnel.inPivotEndHpr,
                        startHpr=linkTunnel.inPivotStartHpr,
                    ),
                    LerpPosInterval(pivotPointNode,
                                    duration=1.0,
                                    pos=(linkTunnel.inPivotEndX,
                                         pivotPointNode.getY(),
                                         pivotPointNode.getZ()),
                                    startPos=(linkTunnel.inPivotStartX,
                                              pivotPointNode.getY(),
                                              pivotPointNode.getZ())),
                    Func(self.reparentTo, hidden)))
        elif inOrOut == 1:

            # Going out!
            pivotPoint = linkTunnel.outPivotPoint
            pivotPointNode = linkTunnel.tunnel.attachNewNode(
                'tunnelPivotPoint')
            pivotPointNode.setPos(pivotPoint)
            pivotPointNode.setHpr(linkTunnel.outPivotStartHpr)

            exitSeq = Sequence()

            if base.localAvatar.doId == self.doId:
                base.localAvatar.walkControls.setCollisionsActive(
                    0, andPlaceOnGround=1)
                base.localAvatar.detachCamera()
                camera.reparentTo(linkTunnel.tunnel)
                tunnelCamPos = linkTunnel.camPos
                tunnelCamHpr = linkTunnel.camHpr
                camera.setPos(tunnelCamPos)
                camera.setHpr(tunnelCamHpr)
                doneMethod = self._handleCameOutTunnel
                extraArgs = []

                exitSeq.append(Func(base.transitions.irisIn))
            else:
                self.stopSmooth()

            self.reparentTo(pivotPointNode)
            self.setHpr(linkTunnel.toonOutHpr)
            self.setPos(linkTunnel.toonOutPos)

            seq = Sequence(
                Func(self.loop, 'run'),
                LerpPosInterval(pivotPointNode,
                                duration=1.0,
                                pos=(linkTunnel.outPivotEndX,
                                     pivotPointNode.getY(),
                                     pivotPointNode.getZ()),
                                startPos=(linkTunnel.outPivotStartX,
                                          pivotPointNode.getY(),
                                          pivotPointNode.getZ())),
                LerpHprInterval(
                    pivotPointNode,
                    duration=2.0,
                    hpr=linkTunnel.outPivotEndHpr,
                    startHpr=linkTunnel.outPivotStartHpr,
                ))
            if base.localAvatar.doId != self.doId:
                seq.append(Func(self.startSmooth))
            seq.append(Func(self.wrtReparentTo, render))
            exitSeq.append(seq)
            self.tunnelTrack.append(exitSeq)

        if base.localAvatar.doId == self.doId:
            self.tunnelTrack.setDoneEvent(self.tunnelTrack.getName())
            self.acceptOnce(self.tunnelTrack.getDoneEvent(), doneMethod,
                            extraArgs)

        self.tunnelTrack.start()

    def setDefaultShard(self, shardId):
        self.defaultShard = shardId

    def getDefaultShard(self):
        return self.defaultShard

    def setLastHood(self, zoneId):
        self.lastHood = zoneId

    def b_setLastHood(self, zoneId):
        self.sendUpdate('setLastHood', [zoneId])
        self.setLastHood(zoneId)

    def getLastHood(self):
        return self.lastHood

    def setTeleportAccess(self, array):
        self.teleportAccess = array

    def getTeleportAccess(self):
        return self.teleportAccess

    def setHoodsDiscovered(self, array):
        self.hoodsDiscovered = array

    def b_setHoodsDiscovered(self, array):
        self.sendUpdate('setHoodsDiscovered', [array])
        self.setHoodsDiscovered(array)

    def getHoodsDiscovered(self):
        return self.hoodsDiscovered

    def setTutorialCompleted(self, value):
        self.tutDone = value

    def getTutorialCompleted(self):
        return self.tutDone

    def setFriendsList(self, friends):
        self.friends = friends

    def getFriendsList(self):
        return self.friends

    def setBusy(self, busy):
        self.busy = busy

    def getBusy(self):
        return self.busy

    def setTier(self, tier):
        self.tier = tier

    def getTier(self):
        return self.tier

    def setQuestHistory(self, array):
        self.questHistory = array

    def getQuestHistory(self):
        return self.questHistory

    def setQuests(self, dataStr):
        self.quests = dataStr

    def getQuests(self):
        return self.quests

    def maybeMakeHeadMeter(self):
        if base.localAvatar.doId != self.doId:
            if self.getHealth() < self.getMaxHealth():
                if not self.headMeter:
                    self.__makeHeadMeter()

    def __makeHeadMeter(self):
        self.headMeter = LaffOMeter(forRender=True)
        r, g, b, _ = self.getHeadColor()
        animal = self.getAnimal()
        maxHp = self.getMaxHealth()
        hp = self.getHealth()
        self.headMeter.generate(r, g, b, animal, maxHP=maxHp, initialHP=hp)
        self.headMeter.reparentTo(self)
        self.headMeter.setZ(self.getHeight() + 2)
        self.headMeter.setScale(0.4)
        self.headMeter.setBillboardAxis()
        self.__updateHeadMeter()

    def __removeHeadMeter(self):
        if self.headMeter:
            self.headMeter.disable()
            self.headMeter.delete()
            self.headMeter = None

    def __updateHeadMeter(self):
        if self.headMeter:
            self.headMeter.updateMeter(self.getHealth())

    def d_createBattleMeter(self):
        self.sendUpdate('makeBattleMeter', [])

    def b_createBattleMeter(self):
        self.makeBattleMeter()
        self.d_createBattleMeter()

    def d_cleanupBattleMeter(self):
        self.sendUpdate('destroyBattleMeter', [])

    def b_cleanupBattleMeter(self):
        self.destroyBattleMeter()
        self.d_cleanupBattleMeter()

    def makeBattleMeter(self):
        if self.getHealth() < self.getMaxHealth():
            if not self.battleMeter:
                self.battleMeter = LaffOMeter()
                r, g, b, _ = self.getHeadColor()
                animal = self.getAnimal()
                maxHp = self.getMaxHealth()
                hp = self.getHealth()
                self.battleMeter.generate(r,
                                          g,
                                          b,
                                          animal,
                                          maxHP=maxHp,
                                          initialHP=hp)
                self.battleMeter.reparentTo(self)
                self.battleMeter.setZ(self.getHeight() + 5)
                self.battleMeter.setScale(0.5)
                self.battleMeter.start()

    def destroyBattleMeter(self):
        if self.battleMeter:
            self.battleMeter.stop()
            self.battleMeter.disable()
            self.battleMeter.delete()
            self.battleMeter = None

    def setEquippedPU(self, index):
        self.equippedPU = index

    def getEquippedPU(self):
        return self.equippedPU

    def setPUInventory(self, array):
        self.puInventory = array

    def getPUInventory(self):
        return self.puInventory

    def setGhost(self, value):
        self.ghost = value
        self.handleGhost(value)

    def d_setGhost(self, value):
        self.sendUpdate("setGhost", [value])

    def b_setGhost(self, value):
        self.d_setGhost(value)
        self.setGhost(value)

    def getGhost(self):
        return self.ghost

    def getBackpack(self):
        return self.backpack

    def setEquippedAttack(self, attackID):
        try:
            self.backpack.setCurrentGag(attackID)
        except:
            # If we couldn't do this, it means that the avatar was most likely disabled.
            pass
        DistributedToon.setEquippedAttack(self, attackID)

    def getCurrentGag(self):
        return self.getEquippedAttack()

    def setLoadout(self, gagIds):
        if self.backpack:
            loadout = []
            for i in range(len(gagIds)):
                gagId = gagIds[i]
                gag = self.backpack.getGagByID(gagId)
                if gag:
                    loadout.append(gag)
            self.backpack.setLoadout(loadout)

    def setBackpackAmmo(self, netString):
        if len(self.attackIds) != 0 or len(self.attacks) != 0:
            self.cleanupAttacks()
            self.clearAttackIds()
        return self.backpack.updateSuppliesFromNetString(netString)

    def getBackpackAmmo(self):
        if self.backpack:
            return self.backpack.netString
        return GagGlobals.getDefaultBackpack().toNetString()

    def setTrackExperience(self, netString):
        self.trackExperience = GagGlobals.getTrackExperienceFromNetString(
            netString)
        if GagGlobals.processTrackData(
                self.trackExperience,
                self.backpack) and self == base.localAvatar:
            if base.localAvatar.invGui:
                base.localAvatar.reloadInvGui()

    def getTrackExperience(self):
        return GagGlobals.trackExperienceToNetString(self.trackExperience)

    def updateAttackAmmo(self, gagId, ammo, maxAmmo, ammo2, maxAmmo2, clip,
                         maxClip):
        if self.useBackpack():
            self.backpack.setSupply(gagId, ammo)
        else:
            DistributedToon.updateAttackAmmo(self, gagId, ammo, maxAmmo, ammo2,
                                             maxAmmo2, clip, maxClip)

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

    def getMoney(self):
        return self.money

    def setAccessLevel(self, value):
        prevLevel = self.getAccessLevel()
        self.role = AdminCommands.Roles.get(value, None)

        if prevLevel != AdminCommands.NoAccess:
            # Let's remove any tokens that already are showing up.
            DistributedToon.removeAdminToken(self)

        if self.role:
            # Let's put a new token above our head.
            DistributedToon.setAdminToken(self, self.role.token)

    def getAccessLevel(self):
        return AdminCommands.NoAccess if not self.role else self.role.accessLevel

    def disable(self):
        base.audio3d.detachSound(self.takeDmgSfx)
        self.takeDmgSfx = None
        if self.tunnelTrack:
            self.ignore(self.tunnelTrack.getDoneEvent())
            self.tunnelTrack.finish()
            self.tunnelTrack = None
        self.role = None
        self.ghost = None
        self.puInventory = None
        self.equippedPU = None
        if self.backpack:
            self.backpack.cleanup()
            self.backpack = None
        self.firstTimeChangingHP = None
        self.quests = None
        self.tier = None
        self.questHistory = None
        self.busy = None
        self.friends = None
        self.tutDone = None
        self.hoodsDiscovered = None
        self.teleportAccess = None
        self.lastHood = None
        self.defaultShard = None
        self.trackExperience = None
        self.__removeHeadMeter()
        self.destroyBattleMeter()
        DistributedToon.disable(self)

    def delete(self):
        try:
            self.DistributedPlayerToon_deleted
        except:
            self.DistributedPlayerToon_deleted = 1
            DistributedPlayerToonShared.delete(self)
            del self.takeDmgSfx
            del self.tunnelTrack
            del self.role
            del self.ghost
            del self.puInventory
            del self.equippedPU
            del self.backpack
            del self.firstTimeChangingHP
            del self.quests
            del self.tier
            del self.questHistory
            del self.busy
            del self.friends
            del self.tutDone
            del self.hoodsDiscovered
            del self.teleportAccess
            del self.lastHood
            del self.defaultShard
            del self.trackExperience
            del self.battleMeter
            del self.headMeter
            DistributedToon.delete(self)
        return
    def enterPanel(self):
        accessLevel = self.avatarInfo[8]
        text_color = AdminCommands.Roles.get(
            accessLevel
        ).token.color if accessLevel > AdminCommands.NoAccess else (0, 0, 0, 1)
        self.nameText = OnscreenText(text=self.avatarInfo[1],
                                     parent=self,
                                     pos=(0, 0.2),
                                     scale=0.035,
                                     wordwrap=8,
                                     fg=text_color)
        self.nameText.setBin('gui-popup', 60)

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

        self.head = ToonGlobals.generateGuiHead(dna)
        self.head.reparentTo(self)
        self.head.setScale(self.animal2HeadData[dna.animal][0])
        self.head.setZ(self.animal2HeadData[dna.animal][1])

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

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

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

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

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

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

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

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

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

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

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

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

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

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterUnableToTP(self):
        pass

    def exitUnableToTP(self):
        pass

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.cleanup()

        base.localAvatar.hideFriendButton()
        base.localAvatar.friendsList.hide()

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

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

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

    def enterPanel(self):
        accessLevel = self.avatarInfo[8]
        text_color = AdminCommands.Roles.get(
            accessLevel
        ).token.color if accessLevel > AdminCommands.NoAccess else (0, 0, 0, 1)
        self.nameText = OnscreenText(text=self.avatarInfo[1],
                                     parent=self,
                                     pos=(0, 0.2),
                                     scale=0.035,
                                     wordwrap=8,
                                     fg=text_color)
        self.nameText.setBin('gui-popup', 60)

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

        self.head = ToonGlobals.generateGuiHead(dna)
        self.head.reparentTo(self)
        self.head.setScale(self.animal2HeadData[dna.animal][0])
        self.head.setZ(self.animal2HeadData[dna.animal][1])

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

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

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

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

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

    def exitPanel(self):
        if self.actionFSM.getCurrentState().getName(
        ) == 'waitOnAvatarFriendListResponse':
            if self.avatarInfo:
                base.cr.friendsManager.d_iCancelledFriendRequest(
                    self.avatarInfo[0])
        self.actionFSM.requestFinalState()
        self.action = None
        self.avatarInfo = None
        self.removeActionPanel()
        self.removeMoreDetailsPanel()
        self.hide()
        if self.nameText:
            self.nameText.destroy()
            self.nameText = None
        if self.head:
            self.head.removeNode()
            self.head.delete()
            self.head = None
        if self.laffMeter:
            self.laffMeter.disable()
            self.laffMeter.delete()
            self.laffMeter = None
        if self.friendButton:
            self.friendButton.destroy()
            self.friendButton = None
        if self.teleportButton:
            self.teleportButton.destroy()
            self.teleportButton = None
        if self.whisperButton:
            self.whisperButton.destroy()
            self.whisperButton = None
        if self.exitButton:
            self.exitButton.destroy()
            self.exitButton = None
        if self.moreDetailsBtn:
            self.moreDetailsBtn.destroy()
            self.moreDetailsBtn = None
Example #10
0
class DistributedToon(Toon.Toon, DistributedAvatar, DelayDeletable):
    notify = directNotify.newCategory('DistributedToon')

    LMHead = 0
    LMCage = 1
    LMOff = 2

    def __init__(self, cr):
        try:
            self.DistributedToon_initialized
            return
        except:
            self.DistributedToon_initialized = 1
        Toon.Toon.__init__(self, cr)
        DistributedAvatar.__init__(self, cr)

        self.lookMode = self.LMOff
        self.cageBone = None
        self.lookTask = None
        self.anim = ""

        self.headMeter = None
        self.firstTimeChangingHP = True

        self.addSound('oof', 'phase_5/audio/sfx/tt_s_ara_cfg_toonHit.ogg')

        return

    def handleHealthChange(self, hp, oldHp):
        if hp < oldHp and not self.firstTimeChangingHP:
            # We took damage, make oof sound.
            self.playSound('oof')

    def setHealth(self, health):
        oldHp = self.getHealth()
        self.handleHealthChange(health, self.getHealth())
        DistributedAvatar.setHealth(self, health)
        if self.doId != base.localAvatar.doId:
            if not self.firstTimeChangingHP:
                if health < self.getMaxHealth():
                    if not self.headMeter:
                        self.__makeHeadMeter()
                    else:
                        self.__updateHeadMeter(oldHp)
                else:
                    self.__removeHeadMeter()
        self.firstTimeChangingHP = False

    def maybeMakeHeadMeter(self):
        if base.localAvatar.doId != self.doId:
            if self.getHealth() < self.getMaxHealth():
                if not self.headMeter:
                    self.__makeHeadMeter()

    def __makeHeadMeter(self):
        self.headMeter = LaffOMeter(forRender=True)
        r, g, b, _ = self.getHeadColor()
        animal = self.getAnimal()
        maxHp = self.getMaxHealth()
        hp = self.getHealth()
        self.headMeter.generate(r, g, b, animal, maxHP=maxHp, initialHP=hp)
        self.headMeter.reparentTo(self)
        self.headMeter.setZ(self.getHeight() + 2)
        self.headMeter.setScale(0.4)
        self.headMeter.setBillboardAxis()
        self.__updateHeadMeter(self.getHealth())

    def __removeHeadMeter(self):
        if self.headMeter:
            self.headMeter.disable()
            self.headMeter.delete()
        self.headMeter = None

    def __updateHeadMeter(self, oldHp):
        if self.headMeter:
            self.headMeter.updateMeter(self.getHealth(), oldHp)

    def getEyeState(self):
        return 0

    def handleHitByToon(self, player, gagId, distance):
        # I was hit by another toon.
        # This is a little strange because this function is called on the toon that got hit
        # but we send an update on the toon that did the hitting.
        #player.sendUpdate('toonHitByGag', [self.doId, gagId])
        pass

    def setupNameTag(self, tempName=None):
        Toon.Toon.setupNameTag(self, tempName)
        self.nametag.getNametag3d().setClickEvent('toonClicked', [self.doId])
        self.nametag.getNametag2d().setClickEvent('toonClicked', [self.doId])

    def stopLookTask(self):
        if self.lookTask:
            self.lookTask.remove()
            self.lookTask = None

    def startLookTask(self):
        self.stopLookTask()
        self.lookTask = taskMgr.add(self.updateLookPitch,
                                    self.uniqueName('updateLookPitch'))

    def setLookMode(self, mode):
        self.lookMode = mode

        if self.lookMode == self.LMCage:
            head = self.getPart('head')
            if head and not head.isEmpty():
                oldPitch = head.getP(self)
                head.setP(self, 0)
            cage = self.getCageBone()
            if cage and not cage.isEmpty():
                cage.setP(self, oldPitch)
        elif self.lookMode == self.LMHead:
            # transfer from cage to head
            cage = self.getCageBone()
            if cage and not cage.isEmpty():
                oldPitch = self.getCageBone().getP(self)
                self.resetCageBone()
            head = self.getPart('head')
            if head and not head.isEmpty():
                head.setP(self, oldPitch)

        if self.lookMode != self.LMOff:
            self.startLookTask()
        else:
            self.stopLookTask()

    def getLookMode(self):
        return self.lookMode

    def getCageBone(self, makeIfEmpty=True):
        if self.isEmpty():
            return None

        cageBone = self.find("**/def_cageA")
        if cageBone.isEmpty() and makeIfEmpty:
            cageBone = self.controlJoint(None, "torso", "def_cageA")

        return cageBone

    def resetCageBone(self):
        if self.isEmpty():
            return

        cageBone = self.find("**/def_cageA")
        if not cageBone.isEmpty():
            self.releaseJoint("torso", "def_cageA")
            cageBone.detachNode()

    def __updateHead(self, cage):
        head = self.getPart('head')
        if head and not head.isEmpty():
            if cage:
                head.setHpr(self, 0, self.lookPitch, 0)
            else:
                head.setP(self.lookPitch)

    def updateLookPitch(self, task):
        if self.lookMode == self.LMHead:
            self.__updateHead(False)

        elif self.lookMode == self.LMCage:
            bone = self.getCageBone()
            if bone and not bone.isEmpty():
                bone.setHpr(self, 0, self.lookPitch, 0)
            self.__updateHead(True)

        return task.cont

    def lookAtObject(self, h, p, r, blink=1):
        head = self.getPart('head')

        if not head or (head and head.getHpr() == (h, p, r)):
            return

        Toon.Toon.lerpLookAt(self, head, tuple((h, p, r)))
        if blink:
            maxBlinks = random.randint(1, 2)
            numBlinks = 0
            delay = 0
            for blink in range(maxBlinks):
                if numBlinks == 0:
                    taskMgr.add(self.doBlink, self.uniqueName("blinkOnTurn"))
                else:
                    delay += 0.22
                    taskMgr.doMethodLater(delay, self.doBlink,
                                          self.doBlinkTaskName)
                numBlinks += 1

    def b_lookAtObject(self, h, p, r, blink=1):
        self.d_lookAtObject(h, p, r, blink)
        self.lookAtObject(h, p, r, blink)

    def d_lookAtObject(self, h, p, r, blink=1):
        self.sendUpdate('lookAtObject', [h, p, r, blink])

    def setAnimState(self, anim, timestamp=None, callback=None, extraArgs=[]):
        self.anim = anim
        if timestamp is None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)
        if self.animFSM.getStateNamed(anim):
            self.animFSM.request(anim, [ts, callback, extraArgs])

    def b_setAnimState(self, anim):
        self.d_setAnimState(anim)
        self.setAnimState(anim, None)

    def d_setAnimState(self, anim):
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate('setAnimState', [anim, timestamp])

    def getAnimState(self):
        return [self.anim, 0.0]

    def setName(self, name):
        Toon.Toon.setName(self, name)
        if self.cr.isShowingPlayerIds:
            self.showAvId()

    def d_setName(self, name):
        self.sendUpdate('setName', [name])

    def b_setName(self, name):
        self.d_setName(name)
        self.setName(name)

    def showAvId(self):
        self.setDisplayName(self.getName() + "\n" + str(self.doId))

    def showName(self):
        self.setDisplayName(self.getName())

    def setDisplayName(self, name):
        self.setupNameTag(tempName=name)

    def wrtReparentTo(self, parent):
        DistributedSmoothNode.wrtReparentTo(self, parent)

    def announceGenerate(self):
        DistributedAvatar.announceGenerate(self)
        if self.animFSM.getCurrentState().getName() == 'off':
            self.setAnimState('Happy')

    def generate(self):
        DistributedAvatar.generate(self)
        self.startSmooth()

    def disable(self):
        self.stopLookTask()

        taskMgr.remove(self.uniqueName('blinkOnTurn'))
        if self.track != None:
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        self.ignore('showAvId')
        self.ignore('showName')
        self.stopSmooth()

        self.__removeHeadMeter()
        self.firstTimeChangingHP = None

        Toon.Toon.disable(self)
        DistributedAvatar.disable(self)

    def delete(self):
        try:
            self.DistributedToon_deleted
        except:
            self.DistributedToon_deleted = 1
            del self.track
            Toon.Toon.delete(self)
            DistributedAvatar.delete(self)
        return
class DistributedToon(Toon.Toon, DistributedAvatar, DistributedSmoothNode,
                      DelayDeletable):
    def __init__(self, cr):
        try:
            self.DistributedToon_initialized
            return
        except:
            self.DistributedToon_initialized = 1
        Toon.Toon.__init__(self, cr)
        DistributedAvatar.__init__(self, cr)
        DistributedSmoothNode.__init__(self, cr)
        self.token = -1
        self.ghost = 0
        self.puInventory = []
        self.equippedPU = -1
        self.backpack = Backpack(self)
        self.animState2animId = {}
        self.battleMeter = None
        for index in range(len(self.animFSM.getStates())):
            self.animState2animId[self.animFSM.getStates()
                                  [index].getName()] = index
        self.animId2animState = {
            v: k
            for k, v in self.animState2animId.items()
        }
        self.headMeter = None
        self.firstTimeChangingHP = True
        self.quests = ""
        self.tier = None
        self.questHistory = None
        self.busy = 1
        self.friends = None
        self.tutDone = 0
        self.hoodsDiscovered = []
        self.teleportAccess = []
        self.lastHood = 0
        self.defaultShard = 0
        self.dmgFadeIval = None
        self.tunnelTrack = None
        self.numGagSlots = 0
        self.trackExperience = dict(GagGlobals.DefaultTrackExperiences)

        self.takeDmgSfx = base.audio3d.loadSfx(
            "phase_5/audio/sfx/tt_s_ara_cfg_toonHit.ogg")
        base.audio3d.attachSoundToObject(self.takeDmgSfx, self)

        return

    def stopSmooth(self):
        DistributedSmoothNode.stopSmooth(self)
        localAvatarReachable = (hasattr(base, 'localAvatar')
                                and base.localAvatar)
        if localAvatarReachable and self.doId != base.localAvatar.doId:
            self.resetTorsoRotation()

    def setNumGagSlots(self, num):
        self.numGagSlots = num

    def getNumGagSlots(self):
        return self.numGagSlots

    def goThroughTunnel(self, toZone, inOrOut, requestStatus=None):
        # inOrOut: 0 = in; 1 = out

        if self.tunnelTrack:
            self.ignore(self.tunnelTrack.getDoneEvent())
            self.tunnelTrack.finish()
            self.tunnelTrack = None

        linkTunnel = LinkTunnel.getTunnelThatGoesToZone(toZone)
        if not linkTunnel:
            return
        self.tunnelTrack = Parallel(
            name=self.uniqueName('Place.goThroughTunnel'))

        if inOrOut == 0:
            # Going in a tunnel!
            pivotPoint = linkTunnel.inPivotPoint
            pivotPointNode = linkTunnel.tunnel.attachNewNode(
                'tunnelPivotPoint')
            pivotPointNode.setPos(pivotPoint)
            self.stopSmooth()
            self.wrtReparentTo(pivotPointNode)
            if linkTunnel.__class__.__name__ == "SafeZoneLinkTunnel":
                self.setHpr(180, 0, 0)
            else:
                self.setHpr(0, 0, 0)
            if base.localAvatar.doId == self.doId:
                doneMethod = self._handleWentInTunnel
                extraArgs = [requestStatus]
                self.walkControls.setCollisionsActive(0)
                camera.wrtReparentTo(linkTunnel.tunnel)
                currCamPos = camera.getPos()
                currCamHpr = camera.getHpr()
                tunnelCamPos = linkTunnel.camPos
                tunnelCamHpr = linkTunnel.camHpr
                self.tunnelTrack.append(
                    LerpPosInterval(camera,
                                    duration=0.7,
                                    pos=tunnelCamPos,
                                    startPos=currCamPos,
                                    blendType='easeOut'))
                self.tunnelTrack.append(
                    LerpQuatInterval(camera,
                                     duration=0.7,
                                     quat=tunnelCamHpr,
                                     startHpr=currCamHpr,
                                     blendType='easeOut'))
            exitSeq = Sequence(Func(self.loop, 'run'))
            if base.localAvatar.doId == self.doId:
                exitSeq.append(Wait(2.0))
                exitSeq.append(Func(base.transitions.irisOut))
            self.tunnelTrack.append(exitSeq)
            self.tunnelTrack.append(
                Sequence(
                    LerpHprInterval(
                        pivotPointNode,
                        duration=2.0,
                        hpr=linkTunnel.inPivotEndHpr,
                        startHpr=linkTunnel.inPivotStartHpr,
                    ),
                    LerpPosInterval(pivotPointNode,
                                    duration=1.0,
                                    pos=(linkTunnel.inPivotEndX,
                                         pivotPointNode.getY(),
                                         pivotPointNode.getZ()),
                                    startPos=(linkTunnel.inPivotStartX,
                                              pivotPointNode.getY(),
                                              pivotPointNode.getZ()))))
        elif inOrOut == 1:
            # Going out!
            pivotPoint = linkTunnel.outPivotPoint
            pivotPointNode = linkTunnel.tunnel.attachNewNode(
                'tunnelPivotPoint')
            pivotPointNode.setPos(pivotPoint)
            pivotPointNode.setHpr(linkTunnel.outPivotStartHpr)
            if base.localAvatar.doId == self.doId:
                base.localAvatar.walkControls.setCollisionsActive(0)
                base.localAvatar.detachCamera()
                camera.reparentTo(linkTunnel.tunnel)
                tunnelCamPos = linkTunnel.camPos
                tunnelCamHpr = linkTunnel.camHpr
                camera.setPos(tunnelCamPos)
                camera.setHpr(tunnelCamHpr)
                doneMethod = self._handleCameOutTunnel
                extraArgs = []
            self.reparentTo(pivotPointNode)
            self.setHpr(linkTunnel.toonOutHpr)
            self.setPos(linkTunnel.toonOutPos)
            exitSeq = Sequence(
                Func(self.loop, 'run'),
                LerpPosInterval(pivotPointNode,
                                duration=1.0,
                                pos=(linkTunnel.outPivotEndX,
                                     pivotPointNode.getY(),
                                     pivotPointNode.getZ()),
                                startPos=(linkTunnel.outPivotStartX,
                                          pivotPointNode.getY(),
                                          pivotPointNode.getZ())),
                LerpHprInterval(
                    pivotPointNode,
                    duration=2.0,
                    hpr=linkTunnel.outPivotEndHpr,
                    startHpr=linkTunnel.outPivotStartHpr,
                ), Func(self.wrtReparentTo, render), Func(self.startSmooth))
            self.tunnelTrack.append(exitSeq)

        if base.localAvatar.doId == self.doId:
            self.tunnelTrack.setDoneEvent(self.tunnelTrack.getName())
            self.acceptOnce(self.tunnelTrack.getDoneEvent(), doneMethod,
                            extraArgs)

        self.tunnelTrack.start()

    def setupNameTag(self, tempName=None):
        Toon.Toon.setupNameTag(self, tempName)
        self.nametag.getNametag3d().setClickEvent('toonClicked', [self.doId])
        self.nametag.getNametag2d().setClickEvent('toonClicked', [self.doId])

    def setDefaultShard(self, shardId):
        self.defaultShard = shardId

    def getDefaultShard(self):
        return self.defaultShard

    def updateHeadPitch(self, pitch):
        head = self.getPart("head")
        if head and not head.isEmpty():
            head.setP(pitch)

    def doSmoothTask(self, task):
        self.smoother.computeAndApplySmoothPosHpr(self, self)
        if not hasattr(base, 'localAvatar'):
            return task.done
        else:
            if self.doId != base.localAvatar.doId:
                self.setSpeed(self.smoother.getSmoothForwardVelocity(),
                              self.smoother.getSmoothRotationalVelocity(),
                              self.smoother.getSmoothLateralVelocity())
        return task.cont

    def setLastHood(self, zoneId):
        self.lastHood = zoneId

    def b_setLastHood(self, zoneId):
        self.sendUpdate('setLastHood', [zoneId])
        self.setLastHood(zoneId)

    def getLastHood(self):
        return self.lastHood

    def setTeleportAccess(self, array):
        self.teleportAccess = array

    def getTeleportAccess(self):
        return self.teleportAccess

    def setHoodsDiscovered(self, array):
        self.hoodsDiscovered = array

    def b_setHoodsDiscovered(self, array):
        self.sendUpdate('setHoodsDiscovered', [array])
        self.setHoodsDiscovered(array)

    def getHoodsDiscovered(self):
        return self.hoodsDiscovered

    def setTutorialCompleted(self, value):
        self.tutDone = value

    def getTutorialCompleted(self):
        return self.tutDone

    def setFriendsList(self, friends):
        self.friends = friends

    def getFriendsList(self):
        return self.friends

    def setBusy(self, busy):
        self.busy = busy

    def getBusy(self):
        return self.busy

    def setTier(self, tier):
        self.tier = tier

    def getTier(self):
        return self.tier

    def setQuestHistory(self, array):
        self.questHistory = array

    def getQuestHistory(self):
        return self.questHistory

    def setQuests(self, dataStr):
        self.quests = dataStr
        base.localAvatar.questManager.makeQuestsFromData()

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

    def getQuests(self):
        return self.quests

    def maybeMakeHeadMeter(self):
        if base.localAvatar.doId != self.doId:
            if self.health < self.getMaxHealth():
                if not self.headMeter:
                    self.__makeHeadMeter()

    def __makeHeadMeter(self):
        self.headMeter = LaffOMeter(forRender=True)
        r, g, b, _ = self.getHeadColor()
        animal = self.getAnimal()
        maxHp = self.getMaxHealth()
        hp = self.getHealth()
        self.headMeter.generate(r, g, b, animal, maxHP=maxHp, initialHP=hp)
        self.headMeter.reparentTo(self)
        self.headMeter.setZ(self.getHeight() + 2)
        self.headMeter.setScale(0.4)
        self.headMeter.setBillboardAxis()
        self.__updateHeadMeter()

    def __removeHeadMeter(self):
        if self.headMeter:
            self.headMeter.disable()
            self.headMeter.delete()
            self.headMeter = None

    def __updateHeadMeter(self):
        if self.headMeter:
            self.headMeter.updateMeter(self.getHealth())

    def setHealth(self, health):
        if health < self.health:
            # We took damage, make oof sound.
            self.takeDmgSfx.play()

        self.health = health
        if self.doId != base.localAvatar.doId:
            if not self.firstTimeChangingHP:
                if health < self.getMaxHealth():
                    if not self.headMeter:
                        self.__makeHeadMeter()
                    else:
                        self.__updateHeadMeter()
                else:
                    self.__removeHeadMeter()

        self.firstTimeChangingHP = False

    def d_createBattleMeter(self):
        self.sendUpdate('makeBattleMeter', [])

    def b_createBattleMeter(self):
        self.makeBattleMeter()
        self.d_createBattleMeter()

    def d_cleanupBattleMeter(self):
        self.sendUpdate('destroyBattleMeter', [])

    def b_cleanupBattleMeter(self):
        self.destroyBattleMeter()
        self.d_cleanupBattleMeter()

    def makeBattleMeter(self):
        if self.getHealth() < self.getMaxHealth():
            if not self.battleMeter:
                self.battleMeter = LaffOMeter()
                r, g, b, _ = self.getHeadColor()
                animal = self.getAnimal()
                maxHp = self.getMaxHealth()
                hp = self.getHealth()
                self.battleMeter.generate(r,
                                          g,
                                          b,
                                          animal,
                                          maxHP=maxHp,
                                          initialHP=hp)
                self.battleMeter.reparentTo(self)
                self.battleMeter.setZ(self.getHeight() + 5)
                self.battleMeter.setScale(0.5)
                self.battleMeter.start()

    def destroyBattleMeter(self):
        if self.battleMeter:
            self.battleMeter.stop()
            self.battleMeter.disable()
            self.battleMeter.delete()
            self.battleMeter = None

    def setEquippedPU(self, index):
        self.equippedPU = index

    def getEquippedPU(self):
        return self.equippedPU

    def setPUInventory(self, array):
        self.puInventory = array

    def getPUInventory(self):
        return self.puInventory

    def setGhost(self, value):
        self.ghost = value
        self.handleGhost(value)

    def d_setGhost(self, value):
        self.sendUpdate("setGhost", [value])

    def b_setGhost(self, value):
        self.d_setGhost(value)
        self.setGhost(value)

    def getGhost(self):
        return self.ghost

    def setDNAStrand(self, dnaStrand):
        Toon.Toon.setDNAStrand(self, dnaStrand)
        self.maybeMakeHeadMeter()

    def d_setDNAStrand(self, dnaStrand):
        self.sendUpdate("setDNAStrand", [dnaStrand])

    def b_setDNAStrand(self, dnaStrand):
        self.setDNAStrand(dnaStrand)
        self.d_setDNAStrand(dnaStrand)

    def lookAtObject(self, h, p, r, blink=1):
        if self.getPart('head').getHpr() == (h, p, r):
            return
        Toon.Toon.lerpLookAt(self, self.getPart('head'), tuple((h, p, r)))
        if blink:
            self.stopBlink()
            maxBlinks = random.randint(1, 2)
            numBlinks = 0
            delay = 0
            for blink in range(maxBlinks):
                if numBlinks == 0:
                    taskMgr.add(self.doBlink, self.uniqueName("blinkOnTurn"))
                else:
                    delay += 0.22
                    taskMgr.doMethodLater(delay, self.doBlink,
                                          self.doBlinkTaskName)
                numBlinks += 1
            taskMgr.doMethodLater(delay, self.__startBlinkAfterLook,
                                  self.uniqueName("sBAL"))

    def __startBlinkAfterLook(self, task):
        self.startBlink()
        return task.done

    def toonUp(self):
        pass

    def b_lookAtObject(self, h, p, r, blink=1):
        self.d_lookAtObject(h, p, r, blink)
        self.lookAtObject(h, p, r, blink)

    def d_lookAtObject(self, h, p, r, blink=1):
        self.sendUpdate('lookAtObject', [h, p, r, blink])

    def setChat(self, chat):
        chat = ChatGlobals.filterChat(chat, self.animal)
        Toon.Toon.setChat(self, chat)

    def setTarget(self, gagId, targetId):
        gag = self.backpack.getGagByID(gagId)
        target = self.cr.doId2do.get(targetId, None)
        gag.setTarget(target)

    def trapActivate(self, gagId, avId, entityId, suitId):
        sender = self.cr.doId2do.get(avId, None)
        suit = self.cr.doId2do.get(suitId, None)
        if sender:
            backpack = sender.getBackpack()
            trapGag = backpack.getGagByID(gagId)
            if backpack and trapGag:
                entity = None
                if hasattr(trapGag, 'getEntities') and 0 <= entityId <= (
                        len(trapGag.getEntities()) - 1):
                    entity = trapGag.getEntities()[entityId]
                    trapGag.onActivate(entity, suit)

    def b_trapActivate(self, gagId, avId, entityId, suitId):
        self.trapActivate(gagId, avId, entityId, suitId)
        self.d_trapActivate(gagId, avId, entityId, suitId)

    def d_trapActivate(self, gagId, avId, entityId, suitId):
        self.sendUpdate('trapActivate', [gagId, avId, entityId, suitId])

    def gagCollision(self, gagId):
        gag = self.backpack.getGagByID(gagId)
        gag.doCollision()

    def b_gagCollision(self, gagId):
        self.sendUpdate("gagCollision", [gagId])
        self.gagCollision(gagId)

    def gagActivate(self, gagId):
        gag = self.backpack.getGagByID(gagId)
        if hasattr(gag, 'activate'):
            gag.activate()

    def b_gagActivate(self, gagId):
        self.sendUpdate("gagActivate", [gagId])
        self.gagActivate(gagId)

    def setDropLoc(self, gagId, x, y, z):
        gag = self.backpack.getGagByID(gagId)
        gag.setEndPos(x, y, z)

    def setGagPos(self, gagId, x, y, z):
        pos = Point3(x, y, z)
        gag = self.backpack.getGagByID(gagId)
        ent = gag.getGag()
        if ent:
            ent.setPos(pos)

    def setThrowPower(self, gagId, power):
        gag = self.backpack.getGagByID(gagId)
        if gag:
            gag.setPower(power)

    def gagStart(self, gagId):
        gag = self.backpack.getGagByID(gagId)
        if gag:
            gag.start()

    def b_gagStart(self, gagId):
        self.sendUpdate("gagStart", [gagId])
        self.gagStart(gagId)

    def gagThrow(self, gagId):
        gag = self.backpack.getGagByID(gagId)
        if gag:
            gag.throw()

    def b_gagThrow(self, gagId):
        self.sendUpdate("gagThrow", [gagId])
        self.gagThrow(gagId)

    def gagRelease(self, gagId):
        gag = self.backpack.getGagByID(gagId)
        print "gagRelease:", gag, hasattr(gag, 'name')
        if gag and hasattr(gag, 'name'):
            gag.release()

    def b_gagRelease(self, gagId):
        self.sendUpdate("gagRelease", [gagId])
        self.gagRelease(gagId)

    def setSplatPos(self, gagId, x, y, z):
        splatGag = self.backpack.getGagByID(gagId)
        if splatGag:
            splatGag.setSplatPos(x, y, z)

    def d_setSplatPos(self, gagId, x, y, z):
        self.sendUpdate('setSplatPos', [gagId, x, y, z])

    def gagBuild(self, gagId):
        gag = self.backpack.getGagByID(gagId)
        if gag:
            gag.build()

    def b_gagBuild(self, gagId):
        self.gagBuild(gagId)
        self.sendUpdate('gagBuild', [gagId])

    def handleSuitAttack(self, attack_id, suit_id):
        attack = SuitAttacks.SuitAttackLengths.keys()[attack_id]
        if attack == "canned":
            sfx = base.audio3d.loadSfx(
                "phase_5/audio/sfx/SA_canned_impact_only.ogg")
            base.audio3d.attachSoundToObject(sfx, self)
            SoundInterval(sfx, node=self).start()
        elif attack == "playhardball":
            sfx = base.audio3d.loadSfx(
                "phase_5/audio/sfx/SA_hardball_impact_only_alt.ogg")
            base.audio3d.attachSoundToObject(sfx, self)
            SoundInterval(sfx, node=self).start()
        elif attack == "clipontie":
            sfx = base.audio3d.loadSfx(
                "phase_5/audio/sfx/SA_powertie_impact.ogg")
            base.audio3d.attachSoundToObject(sfx, self)
            SoundInterval(sfx, node=self).start()
        if not self.isDead():
            if attack in ["fountainpen"]:
                self.getPart("head").setColorScale(0, 0, 0, 1)
                Sequence(Wait(3.0), Func(self.resetHeadColor)).start()

        self.doDamageFade()

    def resetHeadColor(self):
        head = self.getPart('head')
        if head:
            head.setColorScale(1, 1, 1, 1)

    def b_handleSuitAttack(self, attack_id, suit_id):
        self.handleSuitAttack(attack_id, suit_id)
        self.b_lookAtObject(0, 0, 0, blink=1)
        self.sendUpdate('handleSuitAttack', [attack_id, suit_id])

    def equip(self, gagId):
        if self.backpack:
            self.backpack.setCurrentGag(gagId)

    def unEquip(self):
        if self.backpack:
            self.backpack.setCurrentGag(None)

    def b_unEquip(self):
        self.unEquip()
        self.sendUpdate('unEquip', [])

    def b_equip(self, gag_id):
        self.equip(gag_id)
        self.sendUpdate('equip', [gag_id])

    def getBackpack(self):
        return self.backpack

    def setLoadout(self, gagIds):
        if self.backpack:
            loadout = []
            for i in range(len(gagIds)):
                gagId = gagIds[i]
                gag = self.backpack.getGagByID(gagId)
                if gag:
                    loadout.append(gag)
            self.backpack.setLoadout(loadout)

    def setBackpackAmmo(self, netString):
        self.backpack.updateSuppliesFromNetString(netString)

    def getBackpackAmmo(self):
        if self.backpack:
            return self.backpack.toNetString()
        return GagGlobals.getDefaultBackpack().toNetString()

    def setTrackExperience(self, netString):
        self.trackExperience = GagGlobals.getTrackExperienceFromNetString(
            netString)
        GagGlobals.processTrackData(self.trackExperience, self.backpack)

    def getTrackExperience(self):
        return GagGlobals.trackExperienceToNetString(self.trackExperience)

    def setGagAmmo(self, gagId, ammo):
        self.backpack.setSupply(gagId, ammo)

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

    def getMoney(self):
        return self.money

    def setAdminToken(self, value):
        self.token = value
        if value > -1:
            # Put an icon over my head.
            Toon.Toon.setAdminToken(self, value)
        else:
            Toon.Toon.removeAdminToken(self)

    def getAdminToken(self):
        return self.token

    def setAnimState(self, anim, timestamp=None, callback=None, extraArgs=[]):
        self.anim = anim
        if timestamp is None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)

        if type(anim) == types.IntType:
            anim = self.animId2animState[anim]
        if self.animFSM.getStateNamed(anim):
            self.animFSM.request(anim, [ts, callback, extraArgs])

    def b_setAnimState(self, anim):
        self.d_setAnimState(anim)
        self.setAnimState(anim, None)

    def d_setAnimState(self, anim):
        if type(anim) == types.StringType:
            anim = self.animState2animId[anim]
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate("setAnimState", [anim, timestamp])

    def getAnimState(self):
        return self.anim

    def setName(self, name):
        Toon.Toon.setName(self, name)
        if self.cr.isShowingPlayerIds:
            self.showAvId()

    def d_setName(self, name):
        self.sendUpdate('setName', [name])

    def b_setName(self, name):
        self.d_setName(name)
        self.setName(name)

    def showAvId(self):
        self.setDisplayName(self.getName() + "\n" + str(self.doId))

    def showName(self):
        self.setDisplayName(self.getName())

    def setDisplayName(self, name):
        self.setupNameTag(tempName=name)

    def wrtReparentTo(self, parent):
        DistributedSmoothNode.wrtReparentTo(self, parent)

    def announceHealthAndPlaySound(self, level, hp, extraId=-1):
        DistributedAvatar.announceHealth(self, level, hp, extraId)
        hpSfx = base.audio3d.loadSfx("phase_11/audio/sfx/LB_toonup.ogg")
        base.audio3d.attachSoundToObject(hpSfx, self)
        SoundInterval(hpSfx, node=self).start()
        del hpSfx

    def announceGenerate(self):
        DistributedAvatar.announceGenerate(self)
        if self.animFSM.getCurrentState().getName() == 'off':
            self.setAnimState('neutral')
        self.startBlink()

    def generate(self):
        DistributedAvatar.generate(self)
        DistributedSmoothNode.generate(self)
        self.startSmooth()

    def disable(self):
        if self.tunnelTrack:
            self.ignore(self.tunnelTrack.getDoneEvent())
            self.tunnelTrack.finish()
            self.tunnelTrack = None
        if self.dmgFadeIval:
            self.dmgFadeIval.finish()
            self.dmgFadeIval = None
        self.token = None
        self.ghost = None
        self.puInventory = None
        self.equippedPU = None
        if self.backpack:
            self.backpack.cleanup()
            self.backpack = None
        self.animState2animId = None
        self.animId2animState = None
        self.firstTimeChangingHP = None
        self.quests = None
        self.tier = None
        self.questHistory = None
        self.busy = None
        self.friends = None
        self.tutDone = None
        self.hoodsDiscovered = None
        self.teleportAccess = None
        self.lastHood = None
        self.defaultShard = None
        self.numGagSlots = None
        self.__removeHeadMeter()
        self.destroyBattleMeter()

        taskMgr.remove(self.uniqueName('sBAL'))
        taskMgr.remove(self.uniqueName('blinkOnTurn'))
        if self.track != None:
            self.track.finish()
            DelayDelete.cleanupDelayDeletes(self.track)
            self.track = None
        self.stopBlink()
        self.ignore('showAvId')
        self.ignore('showName')
        self.token = None
        self.stopSmooth()
        Toon.Toon.disable(self)
        DistributedAvatar.disable(self)
        DistributedSmoothNode.disable(self)

    def delete(self):
        try:
            self.DistributedToon_deleted
        except:
            self.DistributedToon_deleted = 1
            del self.tunnelTrack
            del self.dmgFadeIval
            del self.token
            del self.ghost
            del self.puInventory
            del self.equippedPU
            del self.backpack
            del self.animState2animId
            del self.animId2animState
            del self.firstTimeChangingHP
            del self.quests
            del self.tier
            del self.questHistory
            del self.busy
            del self.friends
            del self.tutDone
            del self.hoodsDiscovered
            del self.teleportAccess
            del self.lastHood
            del self.defaultShard
            del self.numGagSlots
            Toon.Toon.delete(self)
            DistributedAvatar.delete(self)
            DistributedSmoothNode.delete(self)
        return
Example #12
0
class BaseLocalAvatar:
    notify = directNotify.newCategory("BaseLocalAvatar")

    def __init__(self):
        self.walkControls = None
        self.laffMeter = LaffOMeter()
        self.smartCamera = SmartCamera()
        self.crosshair = Crosshair()
        self.crosshair.hide()
        self.doId = 0
        self.defaultShard = 0
        self.avatarMovementEnabled = False
        self.isSwimming = False
        self.touchingWater = False
        self.invGui = None
        self.playState = False
        self.battleControls = False
        self.selectedGag = -1
        self.lastSelectedGag = -1
        self.needsToSwitchToGag = None
        self.gagsEnabled = False
        self.gagsTimedOut = False
        self.lastState = None

    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 = 'Happy'
        if state != self.lastState:
            self.lastState = state
            self.b_setAnimState(state)
        self.setSpeed(speed, rotSpeed, slideSpeed)
        return task.cont

    def handleDamage(self, x, y, z):
        DirectionalDamageIndicator.make(Point3(x, y, z))

    def createLaffMeter(self):
        r, g, b, _ = self.getHeadColor()
        animal = self.getAnimal()
        maxHp = self.getMaxHealth()
        hp = self.getHealth()
        self.laffMeter.generate(r, g, b, animal, maxHP = maxHp, initialHP = hp)
        self.laffMeter.start()

    def disableLaffMeter(self):
        self.laffMeter.stop()
        self.laffMeter.disable()

    def deleteLaffMeter(self):
        self.laffMeter.delete()

    def updateAttackAmmo(self, attackId, ammo, maxAmmo, ammo2, maxAmmo2, clip, maxClip):
        if self.invGui:
            self.invGui.update()

    def setupAttacks(self):
        if self.getBattleZone() and (not self.getBattleZone().getGameRules().useBackpack()):
            self.reloadInvGui()

    def setEquippedAttack(self, gagId):
        if gagId != -1:
            if self.battleControls:
                self.crosshair.setCrosshair(self.getAttack(gagId).crosshair)
                self.crosshair.show()
                self.b_setLookMode(self.LMCage)
        else:
            # We've unequipped
            if not self.walkControls:
                return
            if self.battleControls:
                self.crosshair.hide()
                self.b_setLookMode(self.LMHead)
            else:
                self.b_setLookMode(self.LMOff)
        if self.invGui:
            self.invGui.update()

    def createInvGui(self):
        self.invGui = GagSelectionGui()
        self.invGui.load()
        self.invGui.hide()

    def reloadInvGui(self):
        self.destroyInvGui()
        self.createInvGui()
        if self.areGagsAllowed():
            self.enableGags(0)

    def destroyInvGui(self):
        if self.invGui:
            self.invGui.cleanup()
            self.invGui = None

    def doFirstPersonCameraTransition(self):
        if self.isFirstPerson():
            # Fancy little camera transition for first person
            camHeight = max(self.getHeight(), 3.0)
            heightScaleFactor = camHeight * 0.3333333333

            LerpPosHprInterval(nodePath = camera, other = self, duration = 1.0,
                               pos = (0, -9.0 * heightScaleFactor, camHeight), hpr = (0, 0, 0),
                               blendType = 'easeInOut').start()

    def handleHealthChange(self, hp, oldHp):
        if self.laffMeter:
            self.laffMeter.updateMeter(hp, oldHp)

        if self.walkControls:
            if hp < oldHp and self.isFirstPerson():
                self.getFPSCam().doDamageFade(1, 0, 0, (self.getHealth() - hp) / 30.0)

        if hp <= 0 and oldHp > 0:
            # Take appropriate action upon death.
            if self.getBattleZone():
                self.getBattleZone().getGameRules().onPlayerDied()

    def canUseGag(self):
        return (self.getEquippedAttack() != -1
                and self.getAttackAmmo(self.getEquippedAttack()) > 0
                and self.gagsEnabled)

    def enableGags(self, andKeys = 0):
        if self.avatarMovementEnabled and andKeys:
            self.enableGagKeys()
            self.selectGag(self.selectedGag, False)
        self.invGui.show()
        self.invGui.enableControls()

    def enableGagKeys(self):
        if not self.areGagsAllowed():
            return

        # Using attacks
        CIGlobals.acceptWithModifiers(self, base.inputStore.PrimaryFire,            self.primaryFirePress)
        CIGlobals.acceptWithModifiers(self, base.inputStore.PrimaryFire + '-up',    self.primaryFireRelease)
        CIGlobals.acceptWithModifiers(self, base.inputStore.SecondaryFire,          self.secondaryFirePress)
        CIGlobals.acceptWithModifiers(self, base.inputStore.SecondaryFire + '-up',  self.secondaryFireRelease)
        CIGlobals.acceptWithModifiers(self, base.inputStore.Reload,                 self.reloadPress)
        CIGlobals.acceptWithModifiers(self, base.inputStore.Reload + '-up',         self.reloadRelease)
        CIGlobals.acceptWithModifiers(self, base.inputStore.LastGag,                self.switchToLastSelectedGag)

        self.gagsEnabled = True

    def disableGagKeys(self):
        self.gagsEnabled = False

        CIGlobals.ignoreWithModifiers(self, base.inputStore.PrimaryFire)
        CIGlobals.ignoreWithModifiers(self, base.inputStore.PrimaryFire + '-up')
        CIGlobals.ignoreWithModifiers(self, base.inputStore.SecondaryFire)
        CIGlobals.ignoreWithModifiers(self, base.inputStore.SecondaryFire + '-up')
        CIGlobals.ignoreWithModifiers(self, base.inputStore.Reload)
        CIGlobals.ignoreWithModifiers(self, base.inputStore.Reload + '-up')
        CIGlobals.ignoreWithModifiers(self, base.inputStore.LastGag)

    def disableGags(self):
        self.disableGagKeys()
        if self.invGui:
            self.invGui.hide()
            self.invGui.disableControls()
        self.b_setEquippedAttack(-1)

    def resetHeadHpr(self, override = False):
        pass

    def getBackpack(self):
        return None

    def enableAvatarControls(self, wantMouse = 0):
        self.walkControls.enableControls(wantMouse)
        self.avatarMovementEnabled = True

    def disableAvatarControls(self, chat = False):
        self.walkControls.disableControls(chat)
        self.avatarMovementEnabled = False
        self.resetSpeeds()

    def handleJumpLand(self):
        pass

    def handleJumpHardLand(self):
        pass

    def startSmartCamera(self):
        self.smartCamera.startUpdateSmartCamera()

    def resetSmartCamera(self):
        self.stopSmartCamera()
        self.startSmartCamera()

    def stopSmartCamera(self):
        self.smartCamera.stopUpdateSmartCamera()

    def detachCamera(self):
        camera.reparentTo(render)
        camera.setPos(0, 0, 0)
        camera.setHpr(0, 0, 0)

    def printPos(self):
        x, y, z = self.getPos(render)
        h, p, r = self.getHpr(render)
        print("Pos: (%s, %s, %s), Hpr: (%s, %s, %s)" % (x, y, z, h, p, r))

    def printPos_cam(self):
        x, y, z = camera.getPos(render)
        h, p, r = camera.getHpr(render)
        print("Pos: (%s, %s, %s), Hpr: (%s, %s, %s)" % (x, y, z, h, p, r))

    def setWalkSpeedNormal(self):
        pass

    def setWalkSpeedNormalNoJump(self):
        pass

    def setWalkSpeedSlow(self):
        pass

    def setupControls(self):
        pass

    def attachCamera(self):
        self.walkControls.attachCamera()

    def destroyControls(self):
        if not self.walkControls:
            return

        self.walkControls.disableControls()
        self.walkControls.stopControllerUpdate()
        self.walkControls.cleanup()
        self.walkControls = None

    def isMoving(self):
        return self.walkControls.isMoving()

    def areGagsAllowed(self):
        state = (self.isFirstPerson() and self.getFPSCam().mouseEnabled) or (self.isThirdPerson() and self.battleControls)
        return (self.avatarMovementEnabled and self.walkControls.controlsEnabled and
                (self.invGui is not None and self.invGui.getCurrentOrNextState() != 'Select') and state)

    def collisionsOn(self):
        pass

    def collisionsOff(self):
        pass

    def startSmooth(self):
        self.notify.warning("Tried to call startSmooth() on the local avatar!")

    def b_unEquipGag(self):
        self.b_setEquippedAttack(-1)

    def switchToLastSelectedGag(self):
        self.selectGag(self.lastSelectedGag)

    def selectGag(self, gagId, record = True):
        if record:
            # Forget this gag if they ran out of ammo
            if self.lastSelectedGag != -1 and self.getAttackAmmo(self.lastSelectedGag) <= 0:
                self.lastSelectedGag = -1
            else:
                self.lastSelectedGag = self.selectedGag

        self.selectedGag = gagId
        self.needsToSwitchToGag = gagId
        self.b_setEquippedAttack(gagId)

    def setBattleControls(self, flag):
        self.battleControls = flag
        if self.playState:
            self.disableAvatarControls()
            self.enableAvatarControls(1)

    def d_broadcastPositionNow(self):
        self.d_clearSmoothing()
        if self.d_broadcastPosHpr:
            self.d_broadcastPosHpr()

    def b_setLookMode(self, mode):
        self.setLookMode(mode)
        self.sendUpdate('setLookMode', [mode])

    def isFirstPerson(self):
        return self.walkControls.mode == self.walkControls.MFirstPerson and self.battleControls

    def isThirdPerson(self):
        return self.walkControls.mode == self.walkControls.MThirdPerson or not self.battleControls

    def getViewModel(self):
        return self.walkControls.fpsCam.viewModel

    def getFPSCam(self):
        return self.walkControls.fpsCam

    def showCrosshair(self):
        self.crosshair.show()

    def hideCrosshair(self):
        self.crosshair.hide()

    def setupCamera(self):
        base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4./3.))
        base.camLens.setNearFar(CIGlobals.DefaultCameraNear, CIGlobals.DefaultCameraFar)
        self.smartCamera.initializeSmartCamera()
        self.smartCamera.initCameraPositions()
        self.smartCamera.setCameraPositionByIndex(0)

    def resetSpeeds(self):
        self.walkControls.speed = 0.0
        self.walkControls.rotationSpeed = 0.0
        self.walkControls.slideSpeed = 0.0

    def startPlay(self, gags = False, laff = False, wantMouse = 1):
        if self.playState:
            return

        if laff:
            self.createLaffMeter()

        if not self.walkControls.getCollisionsActive():
            self.walkControls.setCollisionsActive(1)
        self.enableAvatarControls(wantMouse)

        if gags:
            self.enableGags(1)

        self.startPosHprBroadcast()
        self.d_broadcastPositionNow()

        self.startTrackAnimToSpeed()

        self.playState = True

    def stopPlay(self):
        if not self.playState:
            return

        self.disableGags()
        self.disableLaffMeter()

        self.collisionsOff()
        if self.walkControls.getCollisionsActive():
            self.walkControls.setCollisionsActive(0, andPlaceOnGround=1)
        self.disableAvatarControls()
        self.stopPosHprBroadcast()

        self.stopTrackAnimToSpeed()

        self.playState = False