Ejemplo n.º 1
0
class Player(DirectObject):
    def __init__(self, flyBot):
        # sword model from https://www.blendswap.com/blends/view/70259
        self.sword = base.loader.loadModel('models/swordModel_1')
        self.sword.setScale(0.1, 0.1, 0.1)
        self.sword.setPos(0.1, 2, 0.2)
        self.sword.setHpr(-30, 0, 30)
        self.flyBot = flyBot.flyBot
        self.sword.reparentTo(self.flyBot)
        self.damage = True
        self.enemiesKilled = 0
        self.health = 50
        self.atLevel = 0

        # image from https://cellcode.us/quotes/illustrator-gradients-color.html
        swordTexture = loader.loadTexture("models/playertexture.jpg")
        self.sword.setTexGen(TextureStage.getDefault(),
                             TexGenAttrib.MWorldPosition)
        self.sword.setTexture(swordTexture)

        # add built-in collision object
        self.swordCollider = self.sword.find("**/swordCollider")

    # display player's current stats
    def displayStats(self):
        self.displayText = DirectLabel(
            text='CURRENT LEVEL: %d \n CURRENT HEALTH: %d \n ENEMIES KILLED: %d'
            % (self.atLevel, self.health, self.enemiesKilled),
            scale=0.06,
            frameColor=(1, 1, 1, 1),
            frameSize=(-5.25, 6.00, -2.50, 1.5))
        self.displayText.setPos(-1, 0, 0.9)

    # change displayed stats
    def changeStats(self, health, enemies):
        # remove the display screen
        self.displayText.removeNode()
        # create new display screen with new stats
        self.health += health
        self.enemiesKilled += enemies
        self.displayStats()
        if self.health <= 0:
            self.displayText.hide()
class CogdoFlyingFuelGui(DirectFrame):

    def __init__(self, parent):
        DirectFrame.__init__(self, relief=None, state=DGG.NORMAL, sortOrder=DGG.BACKGROUND_SORT_INDEX)
        self.reparentTo(parent)
        self.active = 0
        self._initModel()
        self._initIntervals()
        return

    def _initModel(self):
        self.setPos(Globals.Gui.FuelPos2D[0], 0.0, Globals.Gui.FuelPos2D[1])
        self.gui = CogdoUtil.loadFlyingModel('propellerMeter', group='gui')
        self.gui.reparentTo(self)
        self.gui.setBin('fixed', 0)
        self.healthBar = self.gui.find('**/healthBar')
        self.healthBar.setBin('fixed', 1)
        self.healthBar.setColor(*Globals.Gui.FuelNormalColor)
        bottomBarLocator = self.gui.find('**/bottomOfBar_loc')
        bottomBarPos = bottomBarLocator.getPos(render)
        topBarLocator = self.gui.find('**/topOfBar_loc')
        topBarPos = topBarLocator.getPos(render)
        zDist = topBarPos.getZ() - bottomBarPos.getZ()
        self.fuelLowIndicator = self.gui.find('**/fuelLowIndicator')
        self.fuelLowIndicator.setBin('fixed', 2)
        pos = self.fuelLowIndicator.getPos(render)
        newPos = pos
        newPos.setZ(bottomBarPos.getZ() + zDist * Globals.Gameplay.FuelLowAmt)
        self.fuelLowIndicator.setPos(render, newPos)
        self.fuelVeryLowIndicator = self.gui.find('**/fuelVeryLowIndicator')
        self.fuelVeryLowIndicator.setBin('fixed', 2)
        pos = self.fuelVeryLowIndicator.getPos(render)
        newPos = pos
        newPos.setZ(bottomBarPos.getZ() + zDist * Globals.Gameplay.FuelVeryLowAmt)
        self.fuelVeryLowIndicator.setPos(render, newPos)
        self.propellerMain = self.gui.find('**/propellers')
        self.propellerMain.setBin('fixed', 3)
        self.propellerHead = self.gui.find('**/propellerHead')
        self.propellerHead.setBin('fixed', 4)
        self.blades = []
        self.activeBlades = []
        index = 1
        blade = self.propellerMain.find('**/propeller%d' % index)
        while not blade.isEmpty():
            self.blades.append(blade)
            index += 1
            blade = self.propellerMain.find('**/propeller%d' % index)

        for blade in self.blades:
            self.activeBlades.append(blade)

        self.bladeNumberLabel = DirectLabel(parent=self.propellerHead, relief=None, pos=(Globals.Gui.FuelNumBladesPos2D[0], 0, Globals.Gui.FuelNumBladesPos2D[1]), scale=Globals.Gui.FuelNumBladesScale, text=str(len(self.activeBlades)), text_align=TextNode.ACenter, text_fg=(0.0,
         0.0,
         -0.002,
         1), text_shadow=(0.75, 0.75, 0.75, 1), text_font=ToontownGlobals.getInterfaceFont())
        self.bladeNumberLabel.setBin('fixed', 5)
        return

    def _initIntervals(self):
        self._healthIval = LerpFunctionInterval(self.healthBar.setSz, fromData=0.0, toData=1.0, duration=2.0)
        self.baseSpinDuration = 2.0
        self._spinIval = LerpFunctionInterval(self.propellerMain.setR, fromData=0.0, toData=-360.0, duration=self.baseSpinDuration)

    def show(self):
        DirectFrame.show(self)
        self._spinIval.loop()

    def hide(self):
        DirectFrame.hide(self)
        self._spinIval.pause()

    def resetBlades(self):
        self.setBlades(len(self.blades))

    def setBlades(self, fuelState):
        if fuelState not in Globals.Gameplay.FuelStates:
            return
        numBlades = fuelState - 1
        if len(self.activeBlades) != numBlades:
            for i in range(len(self.activeBlades)):
                blade = self.activeBlades.pop()
                blade.stash()

            if numBlades > len(self.blades):
                numBlades = len(self.blades)
            for i in range(numBlades):
                blade = self.blades[i]
                self.activeBlades.append(blade)
                blade.unstash()

            self.bladeNumberLabel['text'] = str(len(self.activeBlades))
            self.bladeNumberLabel.setText()
        self.updateHealthBarColor()

    def bladeLost(self):
        if len(self.activeBlades) > 0:
            blade = self.activeBlades.pop()
            blade.stash()
            self.bladeNumberLabel['text'] = str(len(self.activeBlades))
            self.bladeNumberLabel.setText()
        self.updateHealthBarColor()

    def updateHealthBarColor(self):
        color = Globals.Gui.NumBlades2FuelColor[len(self.activeBlades)]
        self.healthBar.setColor(*color)

    def setPropellerSpinRate(self, newRate):
        self._spinIval.setPlayRate(newRate)

    def setRefuelLerpFromData(self):
        startScale = self.healthBar.getSz()
        self._healthIval.fromData = startScale

    def setFuel(self, fuel):
        self.fuel = fuel

    def update(self):
        self.healthBar.setSz(self.fuel)

    def destroy(self):
        self.bladeNumberLabel.removeNode()
        self.bladeNumberLabel = None
        self._healthIval.clearToInitial()
        del self._healthIval
        self.healthBar = None
        self.fuelLowIndicator = None
        self.fuelVeryLowIndicator = None
        self.propellerMain = None
        self.propellerHead = None
        del self.blades[:]
        del self.activeBlades[:]
        self.gui.detachNode()
        self.gui = None
        DirectFrame.destroy(self)
        return
Ejemplo n.º 3
0
class Avatar(ToonTalker.ToonTalker, Actor, AvatarShared):
    """
    Client side implementation of the base Avatar.

    An Avatar is an animatable character, playable or non-playable, that can be involved
    in combat. Also has the ability to chat, have a nametag, hitbox, and more.
    """

    RealShadows = ConfigVariableBool('want-real-shadows', False)
    AvatarMovedEpsilon = 0.05

    def __init__(self, mat=0):
        try:
            self.Avatar_initialized
            return
        except:
            self.Avatar_initialized = 1

        ToonTalker.ToonTalker.__init__(self)
        #BasePhysicsObject.__init__(self)
        AvatarShared.__init__(self)
        Actor.__init__(self, None, None, None, flattenable=0, setFinal=1)

        # All avatars should be ambient boosted to help them stand out more in BSP levels.
        self.setAmbientBoost()

        self.shapeGroup = CIGlobals.WallGroup | CIGlobals.CharacterGroup

        #self.getGeomNode().showThrough(CIGlobals.ShadowCameraBitmask)

        self.usedAnims = []

        self.moveAnimProperties = {}

        self.mat = mat
        self.chat = ''

        self.nametagNodePath = None
        self.__nameVisible = 1
        self.nametag = NametagGroup()
        self.nametag.setAvatar(self)
        font = CIGlobals.getToonFont()
        self.nametag.setFont(font)
        self.nametag.setChatFont(font)
        self.nametag3d = self.attachNewNode('nametag3d')
        self.nametag3d.setTag('cam', 'nametag')

        self.setTwoSided(False)

        self.forwardSpeed = 0.0
        self.rotateSpeed = 0.0
        self.strafeSpeed = 0.0
        self.currentSpeed = 0.0
        self.standWalkRunReverse = None
        self.currentMoveAction = None

        self.enableBlend()

        self.showNametagInMargins = True
        self.avatarType = None
        self.charName = None
        self.tag = None

        self.splashEffect = None
        self.splashSound = None

        self.shadow = None

        self.prevPos = Point3(0)
        self.wake = None
        self.lastWakeTime = 0.0

        self.thoughtInProg = False

        self.shadowFloorToggle = False
        self.avatarFloorToggle = False
        self.floorTask = taskMgr.add(self.__keepOnFloorTask,
                                     "Avatar.keepOnFloor",
                                     sort=30)

        self.ragdoll = None
        self.ragdollMode = False

        self.healthLabel = None
        self.healthLabelTrack = None
        self.dmgFadeIval = None

        self.forcedTorsoAnim = None
        self.lastForcedTorsoAnim = None

        self.activityTrack = None
        self.wasDoingActivity = False

        self.fadeTrack = None

        self.playedAnims = None

        self.chatSoundTable = {}

        return

    def doScaleUp(self):
        self.scaleInterval(2.0, (1, 1, 1), (0.01, 0.01, 0.01)).start()

    def recordUsedAnim(self, animName):
        if not animName in self.usedAnims:
            self.usedAnims.append(animName)

    def clearFadeTrack(self):
        if self.fadeTrack:
            self.fadeTrack.finish()
        self.fadeTrack = None

    def fadeOut(self, time=1.0):
        self.clearFadeTrack()
        self.fadeTrack = Sequence(
            Func(self.setTransparency, 1),
            LerpColorScaleInterval(self, time, (1, 1, 1, 0), (1, 1, 1, 1)),
            Func(self.hide))
        self.fadeTrack.start()

    def fadeIn(self, time=1.0):
        self.clearFadeTrack()
        self.fadeTrack = Sequence(
            Func(self.setTransparency, 1),
            LerpColorScaleInterval(self, time, (1, 1, 1, 1), (1, 1, 1, 0)),
            Func(self.setTransparency, 0))
        self.fadeTrack.start()

    def getAttackMgr(self):
        return base.cr.attackMgr

    def stopActivity(self):
        if self.activityTrack:
            self.activityTrack.finish()
        self.activityTrack = None
        self.doingActivity = False

    def setActivity(self, activity, timestamp):
        AvatarShared.setActivity(self, activity, timestamp)

        self.stopActivity()

        if activity == -1 or activity not in self.activities:
            return

        self.doingActivity = True
        ts = globalClockDelta.localElapsedTime(timestamp)
        act = self.activities[activity]
        loop = act.shouldLoop()
        self.activityTrack = act.doActivity()
        self.activityTrack.start()
        #if loop:
        #    self.activityTrack.loop()
        #else:
        #    self.activityTrack.start()

    def setForcedTorsoAnim(self, anim):
        self.forcedTorsoAnim = anim

    def hasForcedTorsoAnim(self):
        return self.forcedTorsoAnim is not None

    def getForcedTorsoAnim(self):
        return self.forcedTorsoAnim

    def clearForcedTorsoAnim(self):

        if not self.forcedTorsoAnim is None:
            # Let's switch our current torso and head animation to the
            # animation the legs are running.
            legs = self.getLowerBodySubpart()[0]
            legAnimation = self.getCurrentAnim(partName=legs)
            frame = self.getCurrentFrame(partName=legs, animName=legAnimation)

            def __anim(partName):
                self.stop(partName=partName)
                self.play(animName=legAnimation,
                          partName=partName,
                          fromFrame=frame)

            parts = self.getUpperBodySubpart()
            for part in parts:
                __anim(part)

        self.forcedTorsoAnim = None

    def setPlayRate(self, rate, animName, partName=None):
        if partName or not self.forcedTorsoAnim:
            Actor.setPlayRate(self, rate, animName, partName)
        else:
            parts = self.getLowerBodySubpart() + self.getUpperBodySubpart()
            for part in parts:
                Actor.setPlayRate(self, rate, animName, part)

    def play(self, animName, partName=None, fromFrame=None, toFrame=None):
        self.recordUsedAnim(animName)

        lowerHalfNames = self.getLowerBodySubpart()
        if self.forcedTorsoAnim is None or (not (partName in lowerHalfNames)):
            Actor.play(self,
                       animName,
                       partName=partName,
                       fromFrame=fromFrame,
                       toFrame=toFrame)
        else:
            # The torso and the head must stay in its current animation.
            # Let's only update the pants and the legs animation.
            for part in lowerHalfNames:
                Actor.play(self,
                           animName,
                           partName=part,
                           fromFrame=fromFrame,
                           toFrame=toFrame)

    def loop(self,
             animName,
             restart=1,
             partName=None,
             fromFrame=None,
             toFrame=None):
        self.recordUsedAnim(animName)

        lowerHalfNames = self.getLowerBodySubpart()
        if self.forcedTorsoAnim is None or (not (partName in lowerHalfNames)):
            return Actor.loop(self,
                              animName,
                              restart=restart,
                              partName=partName,
                              fromFrame=fromFrame,
                              toFrame=toFrame)
        else:
            # The torso and the head must stay in its current animation.
            # Let's only update the pants and the legs animation.
            for index, part in enumerate(lowerHalfNames):
                output = Actor.loop(self,
                                    animName,
                                    restart=restart,
                                    partName=part,
                                    fromFrame=fromFrame,
                                    toFrame=toFrame)

    def pingpong(self,
                 animName,
                 restart=1,
                 partName=None,
                 fromFrame=None,
                 toFrame=None):
        self.recordUsedAnim(animName)

        lowerHalfNames = self.getLowerBodySubpart()
        if self.forcedTorsoAnim is None or (not (partName in lowerHalfNames)):
            Actor.pingpong(self,
                           animName,
                           restart=restart,
                           partName=partName,
                           fromFrame=fromFrame,
                           toFrame=toFrame)
        else:
            # The torso and the head must stay in its current animation.
            # Let's only update the pants and the legs animation.
            for part in lowerHalfNames:
                Actor.pingpong(self,
                               animName,
                               restart=restart,
                               partName=part,
                               fromFrame=fromFrame,
                               toFrame=toFrame)

    def getMoveAction(self, forward, rotate, strafe):
        return 0

    def performAnim(self, anim, partName=None, animInfo=None):
        if not animInfo:
            self.loop(anim, partName=partName)
        else:
            extraArgs = animInfo.get('args', {})
            meth = animInfo.get('method', 'loop')
            if meth == 'loop':
                self.loop(anim, **extraArgs)
            elif meth == 'pingpong':
                self.pingpong(anim, **extraArgs)

    def resetMoveAnims(self, anim=None, anim2=None):
        self.resetAnimBlends()
        if self.forcedTorsoAnim is None:
            self.disableBlend()
            self.stop()
            if anim and anim2:
                self.enableBlend()
                self.performAnim(anim, None,
                                 self.moveAnimProperties.get(anim, None))
                self.performAnim(anim2, None,
                                 self.moveAnimProperties.get(anim2, None))
        else:
            parts = self.getLowerBodySubpart()
            for part in parts:
                self.disableBlend(partName=part)
                self.stop(partName=part)
                if anim and anim2:
                    self.enableBlend(partName=part)
                    self.performAnim(anim, part,
                                     self.moveAnimProperties.get(anim, None))
                    self.performAnim(anim2, part,
                                     self.moveAnimProperties.get(anim2, None))

    def resetAnimBlends(self):
        for animName in self.usedAnims:
            self.setControlEffect(animName, 0.0)
        self.usedAnims = []

    def setSpeed(self, forwardSpeed, rotateSpeed, strafeSpeed=0.0):
        if self.ragdollMode:
            return

        self.forwardSpeed = forwardSpeed
        self.rotateSpeed = rotateSpeed
        self.strafeSpeed = strafeSpeed

        action = None
        if self.standWalkRunReverse != None and not self.doingActivity:
            action = self.getMoveAction(forwardSpeed, rotateSpeed, strafeSpeed)
            anim, anim2, minSpeed, maxSpeed, rate, rate2 = self.standWalkRunReverse[
                action]
            if self.currentMoveAction != action or self.lastForcedTorsoAnim != self.forcedTorsoAnim or self.wasDoingActivity:
                self.playingAnim = anim
                self.lastForcedTorsoAnim = self.forcedTorsoAnim
                self.currentMoveAction = action
                self.resetMoveAnims(anim, anim2)

            speed = max(
                Vec3(forwardSpeed, strafeSpeed, rotateSpeed / 15.0).length(),
                minSpeed)
            self.currentSpeed = speed
            ratio = speed / maxSpeed
            ratioClamped = CIGlobals.clamp(ratio, 0, 1)
            self.setControlEffect(anim, 1 - ratioClamped)
            self.setControlEffect(anim2, ratioClamped)

            if ratio > 1:
                self.setPlayRate(rate * ratio, anim)
                self.setPlayRate(rate2 * ratio, anim2)
            else:
                self.setPlayRate(rate, anim)
                self.setPlayRate(rate2, anim2)

            self.wasDoingActivity = False
        elif self.doingActivity and not self.wasDoingActivity:
            self.wasDoingActivity = True
            self.resetMoveAnims()

        return action

    def getRightHandNode(self):
        return NodePath("rightHand")

    def getLeftHandNode(self):
        return NodePath("leftHand")

    def getHeadNode(self):
        return NodePath("head")

    def handleHitByToon(self, player, gagId, distance):
        pass

    def handleHitByEnemy(self, enemy, weaponId, distance):
        pass

    def getLowerBodySubpart(self):
        return ["legs"]

    def getUpperBodySubpart(self):
        return ["torso"]

    def taskName(self, name):
        return name + "-" + str(id(self))

    def uniqueName(self, name):
        return name + "-" + str(id(self))

    def setupHealthLabel(self):
        self.healthLabel = DirectLabel(text="",
                                       text_fg=CIGlobals.PositiveTextColor,
                                       scale=0.9,
                                       relief=None,
                                       text_decal=True,
                                       text_font=CIGlobals.getMickeyFont(),
                                       text_align=TextNode.ACenter)
        self.healthLabel.reparentTo(self)
        self.healthLabel.setBillboardPointEye()
        self.healthLabel.stash()
        self.healthLabel.setLightOff(1)
        self.healthLabel.hide(CIGlobals.ShadowCameraBitmask
                              | CIGlobals.ReflectionCameraBitmask)

    def showAndMoveHealthLabel(self, zoffset=0.5, stashWaitTime=1.0):
        self.unstashHpLabel()
        self.stopMovingHealthLabel()
        x = self.nametag3d.getX()
        y = self.nametag3d.getY()
        z = self.nametag3d.getZ()
        moveTrack = LerpPosInterval(self.healthLabel,
                                    duration=0.5,
                                    pos=(x, y, z + zoffset),
                                    startPos=(x, y, z - 2),
                                    blendType='easeOut')
        self.healthLabelTrack = Sequence(moveTrack, Wait(stashWaitTime),
                                         Func(self.stashHpLabel))
        self.healthLabelTrack.start()

    def stopMovingHealthLabel(self):
        if self.healthLabelTrack != None:
            self.healthLabelTrack.pause()
            self.healthLabelTrack = None

    def stashHpLabel(self):
        self.healthLabel.stash()

    def unstashHpLabel(self):
        self.healthLabel.unstash()

    def doDamageFade(self):
        # Stop the current fade interval if it exists.
        if self.dmgFadeIval:
            self.dmgFadeIval.finish()
            self.dmgFadeIval = None

        geomNode = self.getGeomNode()
        # Do a fade effect when we get hit so we are more aware that we were damaged.
        self.dmgFadeIval = Sequence(
            Func(geomNode.setTransparency, 1),
            LerpColorScaleInterval(geomNode,
                                   0.3, (1, 1, 1, 0.5), (1, 1, 1, 1),
                                   blendType='easeOut'),
            LerpColorScaleInterval(geomNode,
                                   0.3, (1, 1, 1, 1), (1, 1, 1, 0.5),
                                   blendType='easeIn'),
            Func(geomNode.setTransparency, 0))
        self.dmgFadeIval.start()

    def announceHealth(self, level, hp, extraId):
        if not self.healthLabel:
            return

        if hp > 0:
            prefix = "+"
        else:
            prefix = ""

        if extraId != -1:
            prefix = self.EXTRAS[extraId] + "\n" + prefix

        if level == 1:
            self.healthLabel["text_fg"] = CIGlobals.PositiveTextColor
            self.healthLabel['text'] = prefix + str(hp)
        else:
            textFg = CIGlobals.NegativeTextColor
            if level == 2:
                textFg = CIGlobals.OrangeTextColor
            elif level == 3:
                textFg = CIGlobals.YellowTextColor
            self.healthLabel["text_fg"] = textFg
            self.healthLabel['text'] = prefix + str(hp)

        self.showAndMoveHealthLabel(1.0 if extraId != -1 else 0.5)

    def doRagdollMode(self,
                      forceX=0,
                      forceY=0,
                      forceZ=0,
                      forcePosX=0,
                      forcePosY=0,
                      forcePosZ=0):
        if self.ragdollMode:
            return

        forceVec = Vec3(forceX, forceY, forceZ)
        forcePos = Vec3(forcePosX, forcePosY, forcePosZ)

        self.stop()
        self.disableRay()
        self.disableShadowRay()
        if self.shadow:
            self.shadow.hide()
        self.disableBodyCollisions()
        if self.ragdoll:
            self.ragdoll.mode = self.ragdoll.RMRagdoll
            self.ragdoll.setEnabled(True)
            self.ragdoll.attachActor()
            self.ragdoll.applyForce(forceVec, forcePos)

        self.ragdollMode = True

    def getSplash(self):
        if not self.splashEffect:
            self.splashEffect = Splash(render)
            self.splashSound = base.loadSfxOnNode(
                "phase_5.5/audio/sfx/AV_jump_in_water.ogg", self.splashEffect)

        return self.splashEffect

    def getWake(self):
        if not self.wake:
            self.wake = Wake(render, self)

        return self.wake

    def splash(self, x, y, z):
        spl = self.getSplash()
        spl.setPos(x, y, z)
        spl.setScale(2)
        spl.play()

        self.splashSound.play()

    def isLocalAvatar(self):
        if not hasattr(base, 'localAvatar'):
            return False
        return self == base.localAvatar

    def initializeRay(self, *args, **kwargs):
        pass

    def enableShadowRay(self):
        self.shadowFloorToggle = True

    def disableShadowRay(self):
        self.shadowFloorToggle = False

    def enableRay(self):
        self.avatarFloorToggle = True

    def disableRay(self):
        self.avatarFloorToggle = False

    def updateFloorHeight(self, z):
        if self.avatarFloorToggle:
            self.setZ(render, z)
        if self.shadowFloorToggle and self.shadow:
            self.shadow.setZ(render, z)

    def __keepOnFloorTask(self, task):
        # First, check if we are above a ground.
        # If so, go onto that.

        if self.isEmpty():
            return task.done

        # Create water ripples
        time = globalClock.getFrameTime()
        delta = time - self.lastWakeTime
        dt = globalClock.getDt()
        pos = self.getPos(render)
        posDelta = (pos - self.prevPos).lengthSquared()
        moveMag = posDelta / dt
        if moveMag > 5.0 and delta > 0.1:
            if hasattr(base, 'waterReflectionMgr'):
                result = base.waterReflectionMgr.isTouchingAnyWater(
                    pos, pos + (0, 0, self.getHeight()))
                if result[0]:
                    self.getWake().createRipple(result[1],
                                                rate=1,
                                                startFrame=4)
                    self.lastWakeTime = time
        self.prevPos = pos

        # Position is updated from server, don't need to move avatar on client
        return task.cont

        if (not self.avatarFloorToggle and not self.shadowFloorToggle
                or moveMag < self.AvatarMovedEpsilon):

            # Avoid unnecessary ray casting.
            return task.cont

        pFrom = self.getPos(render) + (0, 0, 0.1)

        z = None

        pTo = pFrom - (0, 0, 2000)
        aboveResult = base.physicsWorld.rayTestAll(
            pFrom, pTo, CIGlobals.WallGroup | CIGlobals.FloorGroup
            | CIGlobals.StreetVisGroup)
        aboveGround = False
        if aboveResult.hasHits():
            sortedHits = sorted(aboveResult.getHits(),
                                key=lambda hit:
                                (pFrom - hit.getHitPos()).lengthSquared())
            for i in range(len(sortedHits)):
                hit = sortedHits[i]
                node = hit.getNode()
                np = NodePath(node)
                if self.isAncestorOf(np):
                    continue
                z = hit.getHitPos().getZ()
                break

        if z is not None:
            self.updateFloorHeight(z)
            return task.cont

        # We're not above a ground, check above?
        pTo = pFrom + (0, 0, 2000)
        belowResult = base.physicsWorld.rayTestAll(
            pFrom, pTo, CIGlobals.WallGroup | CIGlobals.FloorGroup
            | CIGlobals.StreetVisGroup)
        if belowResult.hasHits():
            sortedHits = sorted(belowResult.getHits(),
                                key=lambda hit:
                                (pFrom - hit.getHitPos()).lengthSquared())
            for i in range(len(sortedHits)):
                hit = sortedHits[i]
                node = hit.getNode()
                np = NodePath(node)
                if self.isAncestorOf(np):
                    continue
                z = hit.getHitPos().getZ()
                break

        if z is not None:
            self.updateFloorHeight(z)

        return task.cont

    def setupPhysics(self, radius=None, height=None):
        if not radius:
            radius = self.getWidth()
        if not height:
            height = self.getHeight()
        self.notify.debug("setupPhysics(r{0}, h{1}) hitboxData: {2}".format(
            radius, height, self.hitboxData))

        # When the height is passed into BulletCapsuleShape, it's
        # talking about the height only of the cylinder part.
        # But what we want is the height of the entire capsule.
        #height -= (radius * 2)
        # The middle of the capsule is the origin by default. Push the capsule shape up
        # so the very bottom of the capsule is the origin.
        zOfs = (height / 2.0) + radius

        capsule = BulletCapsuleShape(radius, height)
        bodyNode = BulletRigidBodyNode('avatarBodyNode')
        bodyNode.addShape(capsule, TransformState.makePos(Point3(0, 0, zOfs)))
        bodyNode.setKinematic(True)
        bodyNode.setPythonTag("avatar", self)

        BasePhysicsObject.setupPhysics(self, bodyNode, True)

        self.stopWaterCheck()

    def isDistributed(self):
        return hasattr(self, 'doId')

    def chatStompComplete(self, text):
        chatType = CHAT_LONG

        if "ooo" in text.lower():
            chatType = CHAT_HOWL
        elif "!" in text.lower():
            chatType = CHAT_EXCLAIM
        elif "?" in text.lower():
            chatType = CHAT_QUESTION
        elif len(text) <= 9:
            chatType = CHAT_SHORT
        elif 10 <= len(text) <= 19:
            chatType = CHAT_MEDIUM
        elif len(text) >= 20:
            chatType = CHAT_LONG

        snd = self.chatSoundTable.get(chatType, None)
        if isinstance(snd, list):
            snd = random.choice(snd)

        if snd:
            self.playSound(snd)

    def deleteNameTag(self):
        self.deleteNametag3d()

    def disableBodyCollisions(self):
        self.cleanupPhysics()

    def loadAvatar(self):
        self.setupHealthLabel()
        self.setBlend(
            frameBlend=base.config.GetBool("interpolate-frames", False))
        base.avatars.append(self)

    def disable(self):
        try:
            self.Avatar_disabled
        except:
            self.Avatar_disabled = 1
            if self.ragdoll:
                self.ragdoll.cleanup()
            self.ragdoll = None
            self.clearFadeTrack()
            if self in base.avatars:
                base.avatars.remove(self)
            if self.dmgFadeIval:
                self.dmgFadeIval.finish()
            self.stopActivity()
            self.dmgFadeIval = None
            self.stopMovingHealthLabel()
            if self.healthLabel:
                self.healthLabel.removeNode()
            self.healthLabel = None
            self.healthLabelTrack = None
            if self.floorTask:
                self.floorTask.remove()
            self.floorTask = None
            self.disableRay()
            self.deleteNametag3d()
            self.nametag.destroy()
            del self.nametag
            self.nametag3d.removeNode()
            self.nametag3d = None
            self.deleteShadow()
            self.removeLoopTask()
            self.mat = None
            self.tag = None
            self.chat = None
            self.avatarType = None
            self.charName = None
            self.nameTag = None
            self.cleanupPhysics()
            self.moveAnimProperties = None
            self.chatSoundTable = None

            self.lastWakeTime = None
            self.prevPos = None

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

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

            self.splashSound = None

            self.avatarFloorToggle = None
            self.shadowFloorToggle = None

            Actor.cleanup(self)

    def delete(self):
        try:
            self.Avatar_deleted
        except:
            self.Avatar_deleted = 1
            self.removeLoopTask()
            AvatarShared.delete(self)
            Actor.delete(self)

    def getNameTag(self):
        return self.nametag3d

    def getNametagJoints(self):
        return []

    def setChat(self, chatString=None):
        print("setChat on", self.__class__.__name__)
        self.nametag.setChatType(NametagGlobals.CHAT)
        shouldClear = self.autoClearChat
        if self.isThought(chatString):
            self.thoughtInProg = True
            chatString = self.removeThoughtPrefix(chatString)
            self.nametag.setChatBalloonType(NametagGlobals.THOUGHT_BALLOON)
            shouldClear = False
        else:
            self.thoughtInProg = False
            self.nametag.setChatBalloonType(NametagGlobals.CHAT_BALLOON)
        self.nametag.setChatText(chatString, timeout=shouldClear)

    def setName(self, nameString=None, charName=None, createNow=0):
        if not nameString:
            return
        AvatarShared.setName(self, nameString)
        if charName:
            self.charName = charName
        if createNow:
            self.setupNameTag()

    def getName(self):
        return AvatarShared.getName(self)

    def setupNameTag(self, tempName=None):
        if not self._name and not tempName:
            return
        if tempName:
            name = tempName
        else:
            name = self._name
        offset = 0.0
        z = 0.0
        if self.avatarType:
            if self.avatarType in [CIGlobals.Suit]:
                offset = 1.0
                z = self.getHeight()
            elif self.avatarType == CIGlobals.Toon:
                offset = 0.5

        self.deleteNametag3d()
        self.initializeNametag3d()

        if self.avatarType == CIGlobals.Toon:
            self.nametag3d.setZ(self.getHeight() + offset)
        elif self.avatarType == CIGlobals.Suit or self.avatarType == CIGlobals.CChar:
            self.nametag3d.setZ(z + offset)

        if self.avatarType == CIGlobals.Suit:
            self.nametag.setFont(CIGlobals.getSuitFont())
            self.nametag.setChatFont(CIGlobals.getSuitFont())
            self.nametag.setNametagColor(
                NametagGlobals.NametagColors[NametagGlobals.CCSuit])
            self.nametag.setActive(0)
        else:
            self.nametag.setFont(CIGlobals.getToonFont())
            self.nametag.setChatFont(CIGlobals.getToonFont())
            self.nametag.setNametagColor(
                NametagGlobals.NametagColors[NametagGlobals.CCOtherPlayer])
        self.nametag.setText(name)
        if self.showNametagInMargins:
            self.nametag.manage(base.marginManager)
        self.nametag.updateAll()

    def setAvatarScale(self, scale):
        self.getGeomNode().setScale(scale)

    def getShadow(self):
        if hasattr(self, 'shadow'):
            if self.shadow:
                return self.shadow
        return None

    def initShadow(self):
        if metadata.USE_REAL_SHADOWS:
            self.shadow = None
        else:
            self.shadow = loader.loadModel(
                "phase_3/models/props/drop_shadow.bam")
            self.shadow.setScale(CIGlobals.ShadowScales[self.avatarType])
            self.shadow.flattenMedium()
            self.shadow.setBillboardAxis(4)
            self.shadow.setColor(0, 0, 0, 0.5, 1)
            if self.avatarType == CIGlobals.Toon:
                self.shadow.reparentTo(
                    self.getPart('legs').find('**/joint_shadow'))
            elif self.avatarType == CIGlobals.Suit:
                self.shadow.reparentTo(self)
            else:
                self.shadow.reparentTo(self)

        self.enableShadowRay()

    def deleteShadow(self):
        if hasattr(self, 'shadow'):
            if self.shadow:
                self.shadow.removeNode()
                self.shadow = None

    def loopFromFrameToZero(self,
                            animName,
                            restart=1,
                            partName=None,
                            fromFrame=None):
        # Loop an animation from a frame, restarting at 0.
        # This is only used in Make A Toon, but could be used in other things,
        # that are not distributed.
        dur = self.getDuration(animName, fromFrame=fromFrame)
        self.play(animName, partName=partName, fromFrame=fromFrame)
        taskName = self.uniqueName('loopTask')
        taskMgr.doMethodLater(dur,
                              self.loopTask,
                              taskName,
                              extraArgs=[animName, restart, partName],
                              appendTask=True)

    def removeLoopTask(self):
        taskMgr.remove(self.uniqueName('loopTask'))

    def removePart(self, partName, lodName="lodRoot"):
        self.removeLoopTask()
        part = Actor.getPart(self, partName, lodName)

        if part:
            Actor.removePart(self, partName, lodName=lodName)

    def loopTask(self, animName, restart, partName, task):
        self.loop(animName, restart, partName)
        return task.done

    def getGhost(self):
        return 0

    def hideName(self):
        nametag3d = self.nametag.getNametag3d()
        nametag3d.hideNametag()
        nametag3d.showChat()
        nametag3d.showThought()
        nametag3d.update()

    def showName(self):
        if self.__nameVisible and not self.getGhost():
            nametag3d = self.nametag.getNametag3d()
            nametag3d.showNametag()
            nametag3d.showChat()
            nametag3d.showThought()
            nametag3d.update()

    def hideNametag2d(self):
        nametag2d = self.nametag.getNametag2d()
        nametag2d.hideNametag()
        nametag2d.hideChat()
        nametag2d.update()

    def showNametag2d(self):
        nametag2d = self.nametag.getNametag2d()
        if not self.getGhost():
            nametag2d.showNametag()
            nametag2d.showChat()
        else:
            nametag2d.hideNametag()
            nametag2d.hideChat()
        nametag2d.update()

    def hideNametag3d(self):
        nametag3d = self.nametag.getNametag3d()
        nametag3d.hideNametag()
        nametag3d.hideChat()
        nametag3d.hideThought()
        nametag3d.update()

    def showNametag3d(self):
        nametag3d = self.nametag.getNametag3d()
        if self.__nameVisible and (not self.getGhost()):
            nametag3d.showNametag()
            nametag3d.showChat()
            nametag3d.showThought()
        else:
            nametag3d.hideNametag()
            nametag3d.hideChat()
            nametag3d.hideThought()
        nametag3d.update()

    def setPickable(self, flag):
        self.nametag.setActive(flag)

    def clickedNametag(self):
        if self.nametag.getActive():
            messenger.send('clickedNametag', [self])

    def initializeNametag3d(self):
        self.deleteNametag3d()
        nametagNode = self.nametag.getNametag3d()
        self.nametagNodePath = self.nametag3d.attachNewNode(nametagNode)

        for cJoint in self.getNametagJoints():
            cJoint.clearNetTransforms()
            cJoint.addNetTransform(nametagNode)

    def deleteNametag3d(self):
        if self.nametagNodePath:
            self.nametagNodePath.removeNode()
            self.nametagNodePath = None

    def getNameVisible(self):
        return self.__nameVisible

    def setNameVisible(self, visible):
        self.__nameVisible = visible
        if visible:
            self.showName()
        else:
            self.hideName()
class CogdoFlyingFuelGui(DirectFrame):

    def __init__(self, parent):
        DirectFrame.__init__(self, relief=None, state=DGG.NORMAL, sortOrder=DGG.BACKGROUND_SORT_INDEX)
        self.reparentTo(parent)
        self.active = 0
        self._initModel()
        self._initIntervals()
        return

    def _initModel(self):
        self.setPos(Globals.Gui.FuelPos2D[0], 0.0, Globals.Gui.FuelPos2D[1])
        self.gui = CogdoUtil.loadFlyingModel('propellerMeter', group='gui')
        self.gui.reparentTo(self)
        self.gui.setBin('fixed', 0)
        self.healthBar = self.gui.find('**/healthBar')
        self.healthBar.setBin('fixed', 1)
        self.healthBar.setColor(*Globals.Gui.FuelNormalColor)
        bottomBarLocator = self.gui.find('**/bottomOfBar_loc')
        bottomBarPos = bottomBarLocator.getPos(render)
        topBarLocator = self.gui.find('**/topOfBar_loc')
        topBarPos = topBarLocator.getPos(render)
        zDist = topBarPos.getZ() - bottomBarPos.getZ()
        self.fuelLowIndicator = self.gui.find('**/fuelLowIndicator')
        self.fuelLowIndicator.setBin('fixed', 2)
        pos = self.fuelLowIndicator.getPos(render)
        newPos = pos
        newPos.setZ(bottomBarPos.getZ() + zDist * Globals.Gameplay.FuelLowAmt)
        self.fuelLowIndicator.setPos(render, newPos)
        self.fuelVeryLowIndicator = self.gui.find('**/fuelVeryLowIndicator')
        self.fuelVeryLowIndicator.setBin('fixed', 2)
        pos = self.fuelVeryLowIndicator.getPos(render)
        newPos = pos
        newPos.setZ(bottomBarPos.getZ() + zDist * Globals.Gameplay.FuelVeryLowAmt)
        self.fuelVeryLowIndicator.setPos(render, newPos)
        self.propellerMain = self.gui.find('**/propellers')
        self.propellerMain.setBin('fixed', 3)
        self.propellerHead = self.gui.find('**/propellerHead')
        self.propellerHead.setBin('fixed', 4)
        self.blades = []
        self.activeBlades = []
        index = 1
        blade = self.propellerMain.find('**/propeller%d' % index)
        while not blade.isEmpty():
            self.blades.append(blade)
            index += 1
            blade = self.propellerMain.find('**/propeller%d' % index)

        for blade in self.blades:
            self.activeBlades.append(blade)

        self.bladeNumberLabel = DirectLabel(parent=self.propellerHead, relief=None, pos=(Globals.Gui.FuelNumBladesPos2D[0], 0, Globals.Gui.FuelNumBladesPos2D[1]), scale=Globals.Gui.FuelNumBladesScale, text=str(len(self.activeBlades)), text_align=TextNode.ACenter, text_fg=(0.0,
         0.0,
         -0.002,
         1), text_shadow=(0.75, 0.75, 0.75, 1), text_font=ToontownGlobals.getInterfaceFont())
        self.bladeNumberLabel.setBin('fixed', 5)
        return

    def _initIntervals(self):
        self._healthIval = LerpFunctionInterval(self.healthBar.setSz, fromData=0.0, toData=1.0, duration=2.0)
        self.baseSpinDuration = 2.0
        self._spinIval = LerpFunctionInterval(self.propellerMain.setR, fromData=0.0, toData=-360.0, duration=self.baseSpinDuration)

    def show(self):
        DirectFrame.show(self)
        self._spinIval.loop()

    def hide(self):
        DirectFrame.hide(self)
        self._spinIval.pause()

    def resetBlades(self):
        self.setBlades(len(self.blades))

    def setBlades(self, fuelState):
        if fuelState not in Globals.Gameplay.FuelStates:
            return
        numBlades = fuelState - 1
        if len(self.activeBlades) != numBlades:
            for i in range(len(self.activeBlades)):
                blade = self.activeBlades.pop()
                blade.stash()

            if numBlades > len(self.blades):
                numBlades = len(self.blades)
            for i in range(numBlades):
                blade = self.blades[i]
                self.activeBlades.append(blade)
                blade.unstash()

            self.bladeNumberLabel['text'] = str(len(self.activeBlades))
            self.bladeNumberLabel.setText()
        self.updateHealthBarColor()

    def bladeLost(self):
        if len(self.activeBlades) > 0:
            blade = self.activeBlades.pop()
            blade.stash()
            self.bladeNumberLabel['text'] = str(len(self.activeBlades))
            self.bladeNumberLabel.setText()
        self.updateHealthBarColor()

    def updateHealthBarColor(self):
        color = Globals.Gui.NumBlades2FuelColor[len(self.activeBlades)]
        self.healthBar.setColor(*color)

    def setPropellerSpinRate(self, newRate):
        self._spinIval.setPlayRate(newRate)

    def setRefuelLerpFromData(self):
        startScale = self.healthBar.getSz()
        self._healthIval.fromData = startScale

    def setFuel(self, fuel):
        self.fuel = fuel

    def update(self):
        self.healthBar.setSz(self.fuel)

    def destroy(self):
        self.bladeNumberLabel.removeNode()
        self.bladeNumberLabel = None
        self._healthIval.clearToInitial()
        del self._healthIval
        self.healthBar = None
        self.fuelLowIndicator = None
        self.fuelVeryLowIndicator = None
        self.propellerMain = None
        self.propellerHead = None
        del self.blades[:]
        del self.activeBlades[:]
        self.gui.detachNode()
        self.gui = None
        DirectFrame.destroy(self)
        return
Ejemplo n.º 5
0
class DirectTooltip():
    def __init__(self):

        self.tooltipText = DirectLabel(
            text = "Tooltip",
            text_fg = (1,1,1,1),
            text_scale = 0.05,
            text_align = TextNode.ALeft,
            frameColor = (0, 0, 0, 0.75),
            borderWidth = (0.1, 0.1))
        self.tooltipText.setTransparency(True)

        self.textXShift = 0.05
        self.textYShift = -0.08

        self.mousePos = None

        # this will determine when the tooltip should be moved in the
        # respective direction, whereby
        # 1  : display edge
        # <1 : margin inside the window
        # >1 : margin outside the window
        self.xEdgeStartShift = 0.99
        self.yEdgeStartShift = 0.99

        self.tooltipText.hide()

    def show(self, text=None, args=None):
        if text is not None:
            self.tooltipText.setText(text)
            self.tooltipText.resetFrameSize()
        self.tooltipText.show()

        # add the tooltips update task so it will be updated every frame
        base.taskMgr.add(self.updateTooltipPos, "task_updateTooltipPos")

    def delete(self, args=None):
        self.tooltipText.removeNode()

        # remove the tooltips update task
        base.taskMgr.remove("task_updateTooltipPos")

    def updateTooltipPos(self, task):
        # calculate new aspec tratio
        wp = base.win.getProperties()
        aspX = 1.0
        aspY = 1.0
        wpXSize = wp.getXSize()
        wpYSize = wp.getYSize()
        if wpXSize > wpYSize:
            aspX = wpXSize / float(wpYSize)
        else:
            aspY = wpYSize / float(wpXSize)

        # variables to store the mouses current x and y position
        x = 0.0
        y = 0.0
        if base.mouseWatcherNode.hasMouse():
            self.tooltipText.show()
            # get the mouse position
            x = base.mouseWatcherNode.getMouseX()
            y = base.mouseWatcherNode.getMouseY()

            # Move the tooltip to the mouse

            # set the text to the current mouse position
            self.tooltipText.setPos(
                (x*aspX) + self.textXShift,
                0,
                (y*aspY)+self.textYShift)

            bounds = self.tooltipText.getBounds()
            # bounds = left, right, bottom, top

            # calculate the texts bounds respecting its current position
            xLeft = self.tooltipText.getX() + bounds[0]*self.tooltipText.getScale()[0]
            xRight = self.tooltipText.getX() + bounds[1]*self.tooltipText.getScale()[0]
            yUp = self.tooltipText.getZ() + bounds[3]*self.tooltipText.getScale()[1]
            yDown = self.tooltipText.getZ() + bounds[2]*self.tooltipText.getScale()[1]

            # these will be used to shift the text in the desired direction
            xShift = 0.0
            yShift = 0.0
            if xRight/aspX > self.xEdgeStartShift:
                # shift to the left
                xShift = self.xEdgeStartShift - xRight/aspX
            elif xLeft/aspX < -self.xEdgeStartShift:
                # shift to the right
                xShift = -(self.xEdgeStartShift + xLeft/aspX)
            if yUp/aspY > self.yEdgeStartShift:
                # shift down
                yShift = self.yEdgeStartShift - yUp/aspY
            elif yDown/aspY < -self.yEdgeStartShift:
                # shift up
                yShift = -(self.yEdgeStartShift + yDown/aspY)

            # some aspect ratio calculation
            xShift *= aspX
            yShift *= aspY

            # move the tooltip to the new position
            self.tooltipText.setX(self.tooltipText.getX() + xShift)
            self.tooltipText.setZ(self.tooltipText.getZ() + yShift)
        else:
            self.tooltipText.delete()


        # continue the task until it got manually stopped
        return task.cont