示例#1
0
    def setupCollisions(self):

        #player sphere
        cPlayerSphere = CollisionSphere(Point3(0, 0, .5), 10)
        cPlayerNode = CollisionNode("Player")
        cPlayerNode.addSolid(cPlayerSphere)
        
        cPlayerNode.setFromCollideMask(BitMask32.bit(4))
        cPlayerNode.setIntoCollideMask(BitMask32(20))
        
        cPlayerNP = self.player.attachNewNode(cPlayerNode)
        self.cTrav.addCollider(cPlayerNP, self.playerGroundHandler)
        #self.cTrav.addCollider(cPlayerNP, self.cRocketHandler)
        #cPlayerNP.show()
        
        
        #enemy sphere
        cEnemySphere = CollisionSphere(Point3(0, 0, .5), 10)
        cEnemyNode = CollisionNode("Enemy")
        cEnemyNode.addSolid(cEnemySphere)
        
        cEnemyNode.setFromCollideMask(BitMask32.bit(4))
        cEnemyNode.setIntoCollideMask(BitMask32(18))
        
        cEnemyNP = self.enemy.attachNewNode(cEnemyNode)
        self.cTrav.addCollider(cEnemyNP, self.enemyGroundHandler)
示例#2
0
    def __initSceneGraph(self):
        # Parent node for relative position (no scaling)
        self.point_path = render.attachNewNode("star_node")
        self.point_path.setPos(self.position)
        
        #For transforming the object with scaling, colors, shading, etc.
        # Hosting the actual 3d model object.
        #Models & textures
        self.flare_ts = TextureStage('flare')
        self.flare_ts.setMode(TextureStage.MModulateGlow)
        self.model_path = loader.loadModel("models/stars/planet_sphere")
        self.model_path.setTexture(SphericalBody.star_dead_tex, 1)
        self.model_path.reparentTo(self.point_path)
        self.model_path.setScale(self.radius)
        self.model_path.setPythonTag('pyStar', self);
        
        # Collision sphere for object picking
        #-----------------------------------------------------
        # As described in the Tut-Chessboard.py sample: "If this model was
        # any more complex than a single polygon, you should set up a collision
        # sphere around it instead."
        cnode = CollisionNode("coll_sphere_node")
        cnode.setTag('star', str(id(self)))
        #We use no displacement (0,0,0) and no scaling factor (1)
        cnode.addSolid(CollisionSphere(0,0,0,1))
        cnode.setIntoCollideMask(BitMask32.bit(1))
        self.cnode_path = self.model_path.attachNewNode(cnode)
        #For temporary testing, display collision sphere.
#        self.cnode_path.show()
        self.quad_path = None
示例#3
0
    def __initSceneGraph(self):
        
        self.point_path = self.host_planet.point_path.attachNewNode("unit_center_node")
        self.model_path = self.point_path.attachNewNode("unit_node")
        self.model_path.reparentTo(self.point_path)
        self.model_path.setPos(Vec3(0,6,0))
        
        self.model_path.setPythonTag('pyUnit', self)
        
        rad = 1
        cnode = CollisionNode("coll_sphere_node")
        cnode.addSolid(CollisionBox(Point3(-rad,-rad,-rad),Point3(rad,rad,rad)))
        cnode.setIntoCollideMask(BitMask32.bit(1))
        cnode.setTag('unit', str(id(self)))
        self.cnode_path = self.model_path.attachNewNode(cnode)
        #self.cnode_path.show()
        
        tex = loader.loadTexture("models/billboards/flare.png")
        cm = CardMaker('quad')
        cm.setFrameFullscreenQuad()
        self.quad_path = self.model_path.attachNewNode(cm.generate())
        self.quad_path.setTexture(tex)
        self.quad_path.setTransparency(TransparencyAttrib.MAlpha)
        self.quad_path.setBillboardPointEye()

        self.quad_path.setColor(self.player.color)
示例#4
0
 def __init__( self, name, camera=None, rootNp=None, fromCollideMask=None, pickTag=None ):
     gizmo_core.Object.__init__( self, name, camera, rootNp )
     
     self.fromCollideMask = fromCollideMask
     self.pickTag = pickTag
     
     self.selection = []
     self.node = None
     self.collEntry = None
     
     # Create a marquee
     self.marquee = gizmo_core.Marquee( '%sMarquee' % self.name )
     
     # Create collision nodes
     self.collTrav = CollisionTraverser()
     #self.collTrav.showCollisions( render )
     self.collHandler = CollisionHandlerQueue()
     self.pickerRay = CollisionRay()
     
     # Create collision ray
     pickerNode = CollisionNode( self.name )
     pickerNode.addSolid( self.pickerRay )
     pickerNode.setIntoCollideMask( BitMask32.allOff() )
     pickerNp = camera.attachNewNode( pickerNode )
     self.collTrav.addCollider( pickerNp, self.collHandler )
     
     # Create collision mask for the ray if one is specified
     if self.fromCollideMask is not None:
         pickerNode.setFromCollideMask( self.fromCollideMask )
     
     # Bind mouse button events
     eventNames = ['mouse1', 'control-mouse1', 'mouse1-up']
     for eventName in eventNames:
         self.accept( eventName, self.FireEvent, [eventName] )
示例#5
0
  def makePerspective(parent):
    v = Viewport('persp', parent)
    v.camPos = Point3(-19, -19, 19)
    v.camLookAt = Point3(0, 0, 0)

    v.grid = DirectGrid(parent=render)
    collPlane = CollisionNode('PerspGridCol')
    collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0)))
    #oldBitmask = collPlane.getIntoCollideMask()
    #collPlane.setIntoCollideMask(BitMask32.bit(21)|oldBitmask)
    collPlane.setIntoCollideMask(BitMask32.bit(21))
    v.collPlane = NodePath(collPlane)
    v.collPlane.reparentTo(v.grid)

    collPlane2 = CollisionNode('PerspGridCol2')
    collPlane2.addSolid(CollisionPlane(Plane(0, 0, -1, 0)))
    #oldBitmask = collPlane2.getIntoCollideMask()
    #collPlane2.setIntoCollideMask(BitMask32.bit(21)|oldBitmask)
    collPlane2.setIntoCollideMask(BitMask32.bit(21))
    v.collPlane2 = NodePath(collPlane2)
    v.collPlane2.reparentTo(v.grid)

    #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_perspViewGridBack")
    LE_showInOneCam(v.grid, 'persp')
    return v
 def __init__( self, *args, **kwargs ):
     p3d.SingleTask.__init__( self, *args, **kwargs )
     
     self.fromCollideMask = kwargs.pop( 'fromCollideMask', None )
     
     self.node = None
     self.collEntry = None
     
     # Create collision nodes
     self.collTrav = CollisionTraverser()
     #self.collTrav.showCollisions( render )
     self.collHandler = CollisionHandlerQueue()
     self.pickerRay = CollisionRay()
     
     # Create collision ray
     pickerNode = CollisionNode( self.name )
     pickerNode.addSolid( self.pickerRay )
     pickerNode.setIntoCollideMask( BitMask32.allOff() )
     pickerNp = self.camera.attachNewNode( pickerNode )
     self.collTrav.addCollider( pickerNp, self.collHandler )
     
     # Create collision mask for the ray if one is specified
     if self.fromCollideMask is not None:
         pickerNode.setFromCollideMask( self.fromCollideMask )
     
     # Bind mouse button events
     eventNames = ['mouse1', 'control-mouse1', 'mouse1-up']
     for eventName in eventNames:
         self.accept( eventName, self.FireEvent, [eventName] )
    def setupCollisions(self):
        #make a collision traverser, set it to default
        base.cTrav = CollisionTraverser()
        
        
        #self.cHandler = CollisionHandlerEvent()
        self.cHandler = CollisionHandlerPusher()
        
        #set the pattern for the event sent on collision
        # "%in" is substituted with the name of the into object
        #self.cHandler.setInPattern("hit-%in")
        
        cSphere = CollisionSphere((0,0,0), 10) #panda is scaled way down!
        cNode = CollisionNode("vtol")
        cNode.addSolid(cSphere)
        #panda is *only* a from object
        cNode.setFromCollideMask(BitMask32.bit(0))
        cNode.setIntoCollideMask(BitMask32.allOff())
        cNodePath = self.vtol.attachNewNode(cNode)
#        cNodePath.show()
        base.cTrav.addCollider(cNodePath, self.cHandler)
        self.cHandler.addCollider(cNodePath, self.vtol)
        #for b1 in self.house2:
        cTube1 = CollisionTube((-0.4,3,3), (-0.4,3,20), 6.8)
        cTube2 = CollisionTube((-0.4,-3,3), (-0.4,-3,20), 6.8)
        cNode = CollisionNode("models/houses/building")
        cNode.addSolid(cTube1)
        cNode.addSolid(cTube2)
        cNodePath = self.house2.attachNewNode(cNode)
        cTube1 = CollisionTube((-0.4,3,3), (-0.4,3,20), 6.8)
        cTube2 = CollisionTube((-0.4,-3,3), (-0.4,-3,20), 6.8)
        cNode = CollisionNode("models/houses/church")
        cNode.addSolid(cTube1)
        cNode.addSolid(cTube2)
        cNodePath = self.house1.attachNewNode(cNode)
示例#8
0
    def __initSceneGraph(self):

        #load various texture stages of the planet
        self.forge_tex = TextureStage('forge')
        self.forge_tex.setMode(TextureStage.MDecal)
        self.nexus_tex = TextureStage('nexus')
        self.nexus_tex.setMode(TextureStage.MDecal)
        self.extractor_phylon_ge_tex = TextureStage('extractor_phylon_ge')
        self.extractor_phylon_ge_tex.setMode(TextureStage.MDecal)
        
        # Parent node for relative position (no scaling)
        self.point_path = self.parent_star.point_path.attachNewNode("planet_node")
        self.point_path.setPos(self.position)
        
        #Models & textures
        self.model_path = loader.loadModel("models/planets/planet_sphere")
        self.model_path.setTexture(SphericalBody.dead_planet_tex, 1)
        self.model_path.reparentTo(self.point_path)
        self.model_path.setScale(self.radius)
        self.model_path.setPythonTag('pyPlanet', self);
        
        cnode = CollisionNode("coll_sphere_node")
        cnode.setTag('planet', str(id(self)))
        #We use no displacement (0,0,0) and no scaling factor (1)
        cnode.addSolid(CollisionSphere(0,0,0,1))
        cnode.setIntoCollideMask(BitMask32.bit(1))
        # Reparenting the collision sphere so that it 
        # matches the planet perfectly.
        self.cnode_path = self.model_path.attachNewNode(cnode)
        
        self.lines = LineNodePath(parent = self.parent_star.point_path, thickness = 4.0, colorVec = Vec4(1.0, 1.0, 1.0, 0.2))
        self.quad_path = None
示例#9
0
class Agent:
    def __init__(self, model, run, walk, startPos, scale, select,ralph,saysome):

        self.actor = Actor(model, {"run":run, "walk":walk})
        self.actor.reparentTo(render)
        self.actor.setScale(scale)
        self.actor.setPos(startPos)
        self.actor.setHpr(90,0,0)
        self.playerGUI = saysome
        self.myralph = ralph
        self.setAI()

        self.cTrav = CollisionTraverser()

        self.groundRay = CollisionRay(0,0,1000,0,0,-1)  
        self.groundCol = CollisionNode('dinoRay')
        self.groundCol.addSolid(self.groundRay)
        self.groundCol.setFromCollideMask(BitMask32.bit(1))
        self.groundCol.setIntoCollideMask(BitMask32.allOff())
        self.groundColNp = self.actor.attachNewNode(self.groundCol)
        self.groundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.groundColNp, self.groundHandler)

        self.sphere = CollisionSphere(0,0,5,13)
        self.spherecol = CollisionNode('dinoSphere')
        self.spherecol.addSolid(self.sphere)
        self.spherecol.setCollideMask(BitMask32.bit(1))
        self.dinocolhs = self.actor.attachNewNode(self.spherecol)

        #self.dinocolhs.show()
        #self.groundColNp.show()
        #self.cTrav.showCollisions(render)

    def setAI(self):
        #Creating AI World
        self.AIworld = AIWorld(render)
 
        self.AIchar = AICharacter("seeker",self.actor, 380, 50, 250)
        self.AIworld.addAiChar(self.AIchar)
        self.AIbehaviors = self.AIchar.getAiBehaviors()  
        self.AIbehaviors.pursue(self.myralph)

        self.actor.loop('run')
        
        #AI World update        
        taskMgr.add(self.AIUpdate,"AIUpdate")
        
    #to update the AIWorld    
    def AIUpdate(self,task):
        if self.playerGUI.getpausevalue():
            self.AIworld.update()            
        return Task.cont

    def setControl(self, control, value):
        self.controlMap[control] = value

    def getactor(self):
        return self.actor
示例#10
0
 def __init__(self):
     self.picker         = CollisionTraverser()            
     self.pickerQ        = CollisionHandlerQueue()         
     pickerCollN         = CollisionNode('heightChecker')       
     self.pickerNode     = render.attachNewNode(pickerCollN) 
     pickerCollN.setFromCollideMask(BitMask32.bit(1))         
     pickerCollN.setIntoCollideMask(BitMask32.allOff())         
     self.pickerRay      = CollisionRay(0,0,300,0,0,-1)                
     pickerCollN.addSolid(self.pickerRay)      
     self.picker.addCollider(self.pickerNode, self.pickerQ)
 def getFlyBallBubble(self):
     if self.__flyBallBubble == None:
         bubble = CollisionSphere(0, 0, 0, GolfGlobals.GOLF_BALL_RADIUS)
         node = CollisionNode('flyBallBubble')
         node.addSolid(bubble)
         node.setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask)
         node.setIntoCollideMask(BitMask32.allOff())
         self.__flyBallBubble = NodePath(node)
         self.flyBallHandler = CollisionHandlerEvent()
         self.flyBallHandler.addInPattern('flyBallHit-%d' % self.index)
     return self.__flyBallBubble
示例#12
0
 def __init__(self):
     self.picker         = CollisionTraverser()            
     self.pickerQ        = CollisionHandlerQueue()         
     pickerCollN         = CollisionNode('mouseRay')       
     pickerCamN          = base.camera.attachNewNode(pickerCollN) 
     pickerCollN.setFromCollideMask(BitMask32.bit(1))         
     pickerCollN.setIntoCollideMask(BitMask32.allOff())         
     self.pickerRay      = CollisionRay()                
     pickerCollN.addSolid(self.pickerRay)      
     self.picker.addCollider(pickerCamN, self.pickerQ) 
     self.accept('mouse1',self.pick)                
示例#13
0
 def addSpawnTriggers(self, triggerSpheres):
     for (x, y, z, triggerRadius, spawnPtId) in triggerSpheres:
         objectSphere = CollisionSphere(x, y, z, triggerRadius)
         objectName = uniqueName('spawnTriggerSphere')
         objectSphere.setTangible(0)
         objectSphereNode = CollisionNode(objectName)
         objectSphereNode.addSolid(objectSphere)
         objectSphereNode.setIntoCollideMask(PiratesGlobals.WallBitmask)
         objectSphereNodePath = self.builder.collisions.attachNewNode(objectSphereNode)
         self.accept('enter' + objectName, self.handleEnterSphere, extraArgs = [
             spawnPtId])
         self.spawnTriggers.append(objectSphereNodePath)
 def setupEventSphere(self, bitmask, avatarRadius):
     self.avatarRadius = avatarRadius
     cSphere = CollisionSphere(0.0, 0.0, self.avatarRadius + 0.75, self.avatarRadius * 1.04)
     cSphere.setTangible(0)
     cSphereNode = CollisionNode('Flyer.cEventSphereNode')
     cSphereNode.addSolid(cSphere)
     cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
     cSphereNode.setFromCollideMask(bitmask)
     cSphereNode.setIntoCollideMask(BitMask32.allOff())
     self.event = CollisionHandlerEvent()
     self.event.addInPattern('enter%in')
     self.event.addOutPattern('exit%in')
     self.cEventSphereNodePath = cSphereNodePath
 def setupHeadSphere(self, avatarNodePath):
     collSphere = CollisionSphere(0, 0, 0, 1)
     collSphere.setTangible(1)
     collNode = CollisionNode('Flyer.cHeadCollSphere')
     collNode.setFromCollideMask(ToontownGlobals.CeilingBitmask)
     collNode.setIntoCollideMask(BitMask32.allOff())
     collNode.addSolid(collSphere)
     self.cHeadSphereNodePath = avatarNodePath.attachNewNode(collNode)
     self.cHeadSphereNodePath.setZ(base.localAvatar.getHeight() + 1.0)
     self.headCollisionEvent = CollisionHandlerEvent()
     self.headCollisionEvent.addInPattern('%fn-enter-%in')
     self.headCollisionEvent.addOutPattern('%fn-exit-%in')
     base.cTrav.addCollider(self.cHeadSphereNodePath, self.headCollisionEvent)
 def setupFloorEventSphere(self, avatarNodePath, bitmask, avatarRadius):
     cSphere = CollisionSphere(0.0, 0.0, 0.0, 0.75)
     cSphereNode = CollisionNode('Flyer.cFloorEventSphere')
     cSphereNode.addSolid(cSphere)
     cSphereNodePath = avatarNodePath.attachNewNode(cSphereNode)
     cSphereNode.setFromCollideMask(bitmask)
     cSphereNode.setIntoCollideMask(BitMask32.allOff())
     self.floorCollisionEvent = CollisionHandlerEvent()
     self.floorCollisionEvent.addInPattern('%fn-enter-%in')
     self.floorCollisionEvent.addAgainPattern('%fn-again-%in')
     self.floorCollisionEvent.addOutPattern('%fn-exit-%in')
     base.cTrav.addCollider(cSphereNodePath, self.floorCollisionEvent)
     self.cFloorEventSphereNodePath = cSphereNodePath
 def setupWallSphere(self, bitmask, avatarRadius):
     self.avatarRadius = avatarRadius
     cSphere = CollisionSphere(0.0, 0.0, self.avatarRadius + 0.75, self.avatarRadius)
     cSphereNode = CollisionNode('Flyer.cWallSphereNode')
     cSphereNode.addSolid(cSphere)
     cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
     cSphereNode.setFromCollideMask(bitmask)
     cSphereNode.setIntoCollideMask(BitMask32.allOff())
     if config.GetBool('want-fluid-pusher', 0):
         self.pusher = CollisionHandlerFluidPusher()
     else:
         self.pusher = CollisionHandlerPusher()
     self.pusher.addCollider(cSphereNodePath, self.avatarNodePath)
     self.cWallSphereNodePath = cSphereNodePath
class CogdoMazeSplattable:
    def __init__(self, object, name, collisionRadius):
        self.object = object
        self.splat = CogdoUtil.loadMazeModel('splash')
        self.splat.setBillboardPointEye()
        self.splat.setBin('fixed', 40)
        self.splat.setDepthTest(False)
        self.splat.setDepthWrite(False)
        self.splatTrack = None
        self._splatSfxIval = base.cogdoGameAudioMgr.createSfxIval('splat')
        self.initGagCollision(name, collisionRadius)
        return

    def destroy(self):
        self.disableGagCollision()
        if self._splatSfxIval.isPlaying():
            self._splatSfxIval.finish()
        del self._splatSfxIval

    def initGagCollision(self, name, radius):
        self.gagCollisionName = name
        collision = CollisionTube(0, 0, 0, 0, 0, 4, radius)
        collision.setTangible(1)
        self.gagCollNode = CollisionNode(self.gagCollisionName)
        self.gagCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask)
        self.gagCollNode.addSolid(collision)
        self.gagCollNodePath = self.object.attachNewNode(self.gagCollNode)

    def disableGagCollision(self):
        self.gagCollNodePath.removeNode()

    def doSplat(self):
        if self.splatTrack and self.splatTrack.isPlaying():
            self.splatTrack.finish()
        self.splat.reparentTo(render)
        self.splat.setPos(self.object, 0, 0, 3.0)
        self.splat.setY(self.splat.getY() - 1.0)
        self._splatSfxIval.node = self.splat
        self.splatTrack = Parallel(
            self._splatSfxIval,
            Sequence(
                Func(self.splat.showThrough),
                LerpScaleInterval(
                    self.splat,
                    duration=0.5,
                    scale=6,
                    startScale=1,
                    blendType='easeOut'), Func(self.splat.hide)))
        self.splatTrack.start()
示例#19
0
 def setupWallSphere(self, bitmask, avatarRadius):
     self.avatarRadius = avatarRadius
     cSphere = CollisionSphere(0.0, 0.0, self.avatarRadius + 0.75,
                               self.avatarRadius)
     cSphereNode = CollisionNode('Flyer.cWallSphereNode')
     cSphereNode.addSolid(cSphere)
     cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
     cSphereNode.setFromCollideMask(bitmask)
     cSphereNode.setIntoCollideMask(BitMask32.allOff())
     if config.GetBool('want-fluid-pusher', 0):
         self.pusher = CollisionHandlerFluidPusher()
     else:
         self.pusher = CollisionHandlerPusher()
     self.pusher.addCollider(cSphereNodePath, self.avatarNodePath)
     self.cWallSphereNodePath = cSphereNodePath
示例#20
0
class CogdoMazeSplattable:
    def __init__(self, object, name, collisionRadius):
        self.object = object
        self.splat = CogdoUtil.loadMazeModel('splash')
        self.splat.setBillboardPointEye()
        self.splat.setBin('fixed', 40)
        self.splat.setDepthTest(False)
        self.splat.setDepthWrite(False)
        self.splatTrack = None
        self._splatSfxIval = base.cogdoGameAudioMgr.createSfxIval('splat')
        self.initGagCollision(name, collisionRadius)
        return

    def destroy(self):
        self.disableGagCollision()
        if self._splatSfxIval.isPlaying():
            self._splatSfxIval.finish()
        del self._splatSfxIval

    def initGagCollision(self, name, radius):
        self.gagCollisionName = name
        collision = CollisionTube(0, 0, 0, 0, 0, 4, radius)
        collision.setTangible(1)
        self.gagCollNode = CollisionNode(self.gagCollisionName)
        self.gagCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask)
        self.gagCollNode.addSolid(collision)
        self.gagCollNodePath = self.object.attachNewNode(self.gagCollNode)

    def disableGagCollision(self):
        self.gagCollNodePath.removeNode()

    def doSplat(self):
        if self.splatTrack and self.splatTrack.isPlaying():
            self.splatTrack.finish()
        self.splat.reparentTo(render)
        self.splat.setPos(self.object, 0, 0, 3.0)
        self.splat.setY(self.splat.getY() - 1.0)
        self._splatSfxIval.node = self.splat
        self.splatTrack = Parallel(
            self._splatSfxIval,
            Sequence(
                Func(self.splat.showThrough),
                LerpScaleInterval(self.splat,
                                  duration=0.5,
                                  scale=6,
                                  startScale=1,
                                  blendType='easeOut'), Func(self.splat.hide)))
        self.splatTrack.start()
示例#21
0
 def loadLever(self):
     self.lever = self.root.attachNewNode('%sLever' % self.activityName)
     self.leverModel = self.party.defaultLeverModel.copyTo(self.lever)
     self.controlColumn = NodePath('cc')
     column = self.leverModel.find('**/column')
     column.getChildren().reparentTo(self.controlColumn)
     self.controlColumn.reparentTo(column)
     self.stickHinge = self.controlColumn.attachNewNode('stickHinge')
     self.stick = self.party.defaultStickModel.copyTo(self.stickHinge)
     self.stickHinge.setHpr(0.0, 90.0, 0.0)
     self.stick.setHpr(0, -90.0, 0)
     self.stick.flattenLight()
     self.bottom = self.leverModel.find('**/bottom')
     self.bottom.wrtReparentTo(self.controlColumn)
     self.bottomPos = self.bottom.getPos()
     cs = CollisionSphere(0.0, 1.35, 2.0, 1.0)
     cs.setTangible(False)
     cn = CollisionNode(self.leverTriggerEvent)
     cn.addSolid(cs)
     cn.setIntoCollideMask(OTPGlobals.WallBitmask)
     self.leverTrigger = self.root.attachNewNode(cn)
     self.leverTrigger.reparentTo(self.lever)
     self.leverTrigger.stash()
     cs = CollisionTube(0.0, 2.7, 0.0, 0.0, 2.7, 3.0, 1.2)
     cn = CollisionNode('levertube')
     cn.addSolid(cs)
     cn.setIntoCollideMask(OTPGlobals.WallBitmask)
     self.leverTube = self.leverModel.attachNewNode(cn)
     host = base.cr.doId2do.get(self.party.partyInfo.hostId)
     if host is None:
         self.notify.debug('%s loadLever : Host has left the game before lever could be created.' % self.activityName)
         return
     scale = host.getGeomNode().getChild(0).getSz(render)
     self.leverModel.setScale(scale)
     self.controlColumn.setPos(0, 0, 0)
     host.setPosHpr(self.lever, 0, 0, 0, 0, 0, 0)
     host.pose('leverNeutral', 0)
     host.update()
     pos = host.rightHand.getPos(self.controlColumn)
     self.controlColumn.setPos(pos[0], pos[1], pos[2] - 1)
     self.bottom.setZ(host, 0.0)
     self.bottom.setPos(self.bottomPos[0], self.bottomPos[1], self.bottom.getZ())
     lookAtPoint = Point3(0.3, 0, 0.1)
     lookAtUp = Vec3(0, -1, 0)
     self.stickHinge.lookAt(host.rightHand, lookAtPoint, lookAtUp)
     host.play('walk')
     host.update()
     return
 def loadLever(self):
     self.lever = self.root.attachNewNode('%sLever' % self.activityName)
     self.leverModel = self.party.defaultLeverModel.copyTo(self.lever)
     self.controlColumn = NodePath('cc')
     column = self.leverModel.find('**/column')
     column.getChildren().reparentTo(self.controlColumn)
     self.controlColumn.reparentTo(column)
     self.stickHinge = self.controlColumn.attachNewNode('stickHinge')
     self.stick = self.party.defaultStickModel.copyTo(self.stickHinge)
     self.stickHinge.setHpr(0.0, 90.0, 0.0)
     self.stick.setHpr(0, -90.0, 0)
     self.stick.flattenLight()
     self.bottom = self.leverModel.find('**/bottom')
     self.bottom.wrtReparentTo(self.controlColumn)
     self.bottomPos = self.bottom.getPos()
     cs = CollisionSphere(0.0, 1.35, 2.0, 1.0)
     cs.setTangible(False)
     cn = CollisionNode(self.leverTriggerEvent)
     cn.addSolid(cs)
     cn.setIntoCollideMask(OTPGlobals.WallBitmask)
     self.leverTrigger = self.root.attachNewNode(cn)
     self.leverTrigger.reparentTo(self.lever)
     self.leverTrigger.stash()
     cs = CollisionTube(0.0, 2.7, 0.0, 0.0, 2.7, 3.0, 1.2)
     cn = CollisionNode('levertube')
     cn.addSolid(cs)
     cn.setIntoCollideMask(OTPGlobals.WallBitmask)
     self.leverTube = self.leverModel.attachNewNode(cn)
     host = base.cr.doId2do.get(self.party.partyInfo.hostId)
     if host is None:
         self.notify.debug('%s loadLever : Host has left the game before lever could be created.' % self.activityName)
         return
     scale = host.getGeomNode().getChild(0).getSz(render)
     self.leverModel.setScale(scale)
     self.controlColumn.setPos(0, 0, 0)
     host.setPosHpr(self.lever, 0, 0, 0, 0, 0, 0)
     host.pose('leverNeutral', 0)
     host.update()
     pos = host.rightHand.getPos(self.controlColumn)
     self.controlColumn.setPos(pos[0], pos[1], pos[2] - 1)
     self.bottom.setZ(host, 0.0)
     self.bottom.setPos(self.bottomPos[0], self.bottomPos[1], self.bottom.getZ())
     lookAtPoint = Point3(0.3, 0, 0.1)
     lookAtUp = Vec3(0, -1, 0)
     self.stickHinge.lookAt(host.rightHand, lookAtPoint, lookAtUp)
     host.play('walk')
     host.update()
     return
 def setupRay(self, bitmask, floorOffset, reach):
     cRay = CollisionRay(0.0, 0.0, 3.0, 0.0, 0.0, -1.0)
     cRayNode = CollisionNode('Flyer.cRayNode')
     cRayNode.addSolid(cRay)
     self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode)
     cRayNode.setFromCollideMask(bitmask)
     cRayNode.setIntoCollideMask(BitMask32.allOff())
     self.lifter = CollisionHandlerGravity()
     self.lifter.setLegacyMode(self._legacyLifter)
     self.lifter.setGravity(self.getGravity(0))
     self.lifter.addInPattern('%fn-enter-%in')
     self.lifter.addAgainPattern('%fn-again-%in')
     self.lifter.addOutPattern('%fn-exit-%in')
     self.lifter.setOffset(floorOffset)
     self.lifter.setReach(reach)
     self.lifter.addCollider(self.cRayNodePath, self.avatarNodePath)
 def setupRay(self, bitmask, floorOffset, reach):
     cRay = CollisionRay(0.0, 0.0, 3.0, 0.0, 0.0, -1.0)
     cRayNode = CollisionNode('Flyer.cRayNode')
     cRayNode.addSolid(cRay)
     self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode)
     cRayNode.setFromCollideMask(bitmask)
     cRayNode.setIntoCollideMask(BitMask32.allOff())
     self.lifter = CollisionHandlerGravity()
     self.lifter.setLegacyMode(self._legacyLifter)
     self.lifter.setGravity(self.getGravity(0))
     self.lifter.addInPattern('%fn-enter-%in')
     self.lifter.addAgainPattern('%fn-again-%in')
     self.lifter.addOutPattern('%fn-exit-%in')
     self.lifter.setOffset(floorOffset)
     self.lifter.setReach(reach)
     self.lifter.addCollider(self.cRayNodePath, self.avatarNodePath)
 def _initCollisions(self):
     self._camCollRay = CollisionRay()
     camCollNode = CollisionNode('CameraToonRay')
     camCollNode.addSolid(self._camCollRay)
     camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask)
     camCollNode.setIntoCollideMask(0)
     self._camCollNP = self._camera.attachNewNode(camCollNode)
     self._camCollNP.show()
     self._collOffset = Vec3(0, 0, 0.5)
     self._collHandler = CollisionHandlerQueue()
     self._collTrav = CollisionTraverser()
     self._collTrav.addCollider(self._camCollNP, self._collHandler)
     self._betweenCamAndToon = {}
     self._transNP = NodePath('trans')
     self._transNP.reparentTo(render)
     self._transNP.setTransparency(True)
     self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon)
     self._transNP.setBin('fixed', 10000)
示例#26
0
 def _initCollisions(self):
     self._camCollRay = CollisionRay()
     camCollNode = CollisionNode('CameraToonRay')
     camCollNode.addSolid(self._camCollRay)
     camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask)
     camCollNode.setIntoCollideMask(0)
     self._camCollNP = self._camera.attachNewNode(camCollNode)
     self._camCollNP.show()
     self._collOffset = Vec3(0, 0, 0.5)
     self._collHandler = CollisionHandlerQueue()
     self._collTrav = CollisionTraverser()
     self._collTrav.addCollider(self._camCollNP, self._collHandler)
     self._betweenCamAndToon = {}
     self._transNP = NodePath('trans')
     self._transNP.reparentTo(render)
     self._transNP.setTransparency(True)
     self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon)
     self._transNP.setBin('fixed', 10000)
示例#27
0
 def __init__(self, object, name, proximityText):
     DirectObject.__init__(self)
     self.object = object
     self.proximityText = proximityText
     self.proximityEvent = name
     self.enterProximityEvent = 'enter' + name
     self.exitProximityEvent = 'exit' + name
     self.useLabel = None
     self.fader = None
     self.size = 6
     self.disk = None
     proximitySphere = CollisionSphere(0, 0, 0, self.size)
     proximitySphere.setTangible(0)
     proximityNode = CollisionNode(self.proximityEvent)
     proximityNode.setIntoCollideMask(PiratesGlobals.WallBitmask)
     proximityNode.addSolid(proximitySphere)
     self.proximityNodePath = self.object.attachNewNode(proximityNode)
     self.accept(self.enterProximityEvent, self.approach)
     self.accept(self.exitProximityEvent, self.leave)
 def __init__(self, object, name, proximityText):
     DirectObject.__init__(self)
     self.object = object
     self.proximityText = proximityText
     self.proximityEvent = name
     self.enterProximityEvent = 'enter' + name
     self.exitProximityEvent = 'exit' + name
     self.useLabel = None
     self.fader = None
     self.size = 6
     self.disk = None
     proximitySphere = CollisionSphere(0, 0, 0, self.size)
     proximitySphere.setTangible(0)
     proximityNode = CollisionNode(self.proximityEvent)
     proximityNode.setIntoCollideMask(PiratesGlobals.WallBitmask)
     proximityNode.addSolid(proximitySphere)
     self.proximityNodePath = self.object.attachNewNode(proximityNode)
     self.accept(self.enterProximityEvent, self.approach)
     self.accept(self.exitProximityEvent, self.leave)
 def loadAssets(self):
     self.root = render.attachNewNode('golfSpot-%d' % self.index)
     self.root.setPos(*self.positions[self.index])
     self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball')
     self.ballColor = VBase4(1, 1, 1, 1)
     if self.index < len(GolfGlobals.PlayerColors):
         self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index])
         self.ballModel.setColorScale(self.ballColor)
     self.ballModel.reparentTo(self.root)
     self.club = loader.loadModel('phase_6/models/golf/putter')
     self.clubLookatSpot = self.root.attachNewNode('clubLookat')
     self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1))
     cs = CollisionSphere(0, 0, 0, 1)
     cs.setTangible(0)
     cn = CollisionNode(self.triggerName)
     cn.addSolid(cs)
     cn.setIntoCollideMask(ToontownGlobals.WallBitmask)
     self.trigger = self.root.attachNewNode(cn)
     self.trigger.stash()
     self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.ogg')
示例#30
0
 def loadAssets(self):
     self.root = render.attachNewNode('golfSpot-%d' % self.index)
     self.root.setPos(*self.positions[self.index])
     self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball')
     self.ballColor = VBase4(1, 1, 1, 1)
     if self.index < len(GolfGlobals.PlayerColors):
         self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index])
         self.ballModel.setColorScale(self.ballColor)
     self.ballModel.reparentTo(self.root)
     self.club = loader.loadModel('phase_6/models/golf/putter')
     self.clubLookatSpot = self.root.attachNewNode('clubLookat')
     self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1))
     cs = CollisionSphere(0, 0, 0, 1)
     cs.setTangible(0)
     cn = CollisionNode(self.triggerName)
     cn.addSolid(cs)
     cn.setIntoCollideMask(ToontownGlobals.WallBitmask)
     self.trigger = self.root.attachNewNode(cn)
     self.trigger.stash()
     self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.ogg')
 def GenerateCollisionGeometry(geomFaces):
     collisionFaces = []
     
     for geomFace in geomFaces:
         tempVerts = list(geomFace.vertex)
         tempVerts.reverse()
         
         colPoly = CollisionPolygon(*tempVerts) 
         collision = CollisionNode('blockCollision')
         collision.addSolid(colPoly)
         collision.setFromCollideMask(BitMask32.allOff())
         
         if(geomFace.blockFace == BlockFace.TOP):
             collision.setIntoCollideMask(Globals.BLOCK_PICKER_BITMASK)
         else:
             collision.setIntoCollideMask(Globals.BLOCK_PICKER_BITMASK | Globals.WALL_BITMASK)
         
         collisionFaces.append(collision)
         
     return collisionFaces
示例#32
0
 def loadModel(self):
     self.hill = loader.loadModel('phase_12/models/bossbotHQ/mole_hole')
     self.hill.setZ(0.0)
     self.hill.reparentTo(self)
     self.hillColName = 'moleHillCol-%d-%d' % (self.moleField.doId, self.index)
     self.moleField.accept('enter' + self.hillColName, self.moleField.handleEnterHill)
     self.mole = self.attachNewNode('mole')
     self.mole.reparentTo(self)
     self.mole.setScale(0.75)
     self.mole.setZ(-2.5)
     self.moleHead = loader.loadModel('phase_12/models/bossbotHQ/mole_norm')
     self.moleHead.reparentTo(self.mole)
     moleColName = 'moleCol-%d-%s' % (self.moleField.doId, self.index)
     moleSphere = CollisionTube(0, 0, 0, 0, 0, 1, 1)
     collNode = CollisionNode(moleColName)
     collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
     collNode.addSolid(moleSphere)
     self.moleColNodePath = self.mole.attachNewNode(collNode)
     self.moleColNodePath.stash()
     self.moleColNodePath.setScale(1.0)
     self.moleField.accept('enter' + moleColName, self.moleField.handleEnterMole)
示例#33
0
 def loadModel(self):
     self.hill = loader.loadModel('phase_12/models/bossbotHQ/mole_hole')
     self.hill.setZ(0.0)
     self.hill.reparentTo(self)
     self.hillColName = 'moleHillCol-%d-%d' % (self.moleField.doId, self.index)
     self.moleField.accept('enter' + self.hillColName, self.moleField.handleEnterHill)
     self.mole = self.attachNewNode('mole')
     self.mole.reparentTo(self)
     self.mole.setScale(0.75)
     self.mole.setZ(-2.5)
     self.moleHead = loader.loadModel('phase_12/models/bossbotHQ/mole_norm')
     self.moleHead.reparentTo(self.mole)
     moleColName = 'moleCol-%d-%s' % (self.moleField.doId, self.index)
     moleSphere = CollisionTube(0, 0, 0, 0, 0, 1, 1)
     collNode = CollisionNode(moleColName)
     collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
     collNode.addSolid(moleSphere)
     self.moleColNodePath = self.mole.attachNewNode(collNode)
     self.moleColNodePath.stash()
     self.moleColNodePath.setScale(1.0)
     self.moleField.accept('enter' + moleColName, self.moleField.handleEnterMole)
示例#34
0
    def createCollisionHandlers(self):
        # Create a new collision traverser instance. We will use this to determine
        # if any collisions occurred after performing movement.
        self.cTrav = CollisionTraverser()

        camGroundRay = CollisionRay()
        camGroundRay.setOrigin(0, 0, 1000)
        camGroundRay.setDirection(0, 0, -1)
        camGroundCol = CollisionNode('camRay')
        camGroundCol.addSolid(camGroundRay)
        camGroundCol.setFromCollideMask(BitMask32.bit(0))
        camGroundCol.setIntoCollideMask(BitMask32.allOff())
        camGroundColNp = base.camera.attachNewNode(camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(camGroundColNp, self.camGroundHandler)

        # register the collision pusher
        self.pusher = CollisionHandlerPusher()

        # register collision event pattern names
        self.pusher.addInPattern('col-%fn-into')
示例#35
0
 def makeOrthographic(parent, name, campos):
   v = Viewport(name, parent)
   v.lens = OrthographicLens()
   v.lens.setFilmSize(30)
   v.camPos = campos
   v.camLookAt = Point3(0, 0, 0)
   v.grid = DirectGrid(parent=render)
   if name == 'left':
     v.grid.setHpr(0, 0, 90)
     collPlane = CollisionNode('LeftGridCol')
     collPlane.addSolid(CollisionPlane(Plane(1, 0, 0, 0)))
     collPlane.setIntoCollideMask(BitMask32.bit(21))
     v.collPlane = NodePath(collPlane)
     v.collPlane.wrtReparentTo(v.grid)
     #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_leftViewGridBack")
     LE_showInOneCam(v.grid, name)
   elif name == 'front':
     v.grid.setHpr(90, 0, 90)
     collPlane = CollisionNode('FrontGridCol')
     collPlane.addSolid(CollisionPlane(Plane(0, -1, 0, 0)))
     collPlane.setIntoCollideMask(BitMask32.bit(21))
     v.collPlane = NodePath(collPlane)      
     v.collPlane.wrtReparentTo(v.grid)
     #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_frontViewGridBack")
     LE_showInOneCam(v.grid, name)
   else:
     collPlane = CollisionNode('TopGridCol')
     collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0)))
     collPlane.setIntoCollideMask(BitMask32.bit(21))
     v.collPlane = NodePath(collPlane)
     v.collPlane.reparentTo(v.grid)
     #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_topViewGridBack")
     LE_showInOneCam(v.grid, name)
   return v
示例#36
0
 def makeOrthographic(parent, name, campos):
     v = Viewport(name, parent)
     v.lens = OrthographicLens()
     v.lens.setFilmSize(30)
     v.camPos = campos
     v.camLookAt = Point3(0, 0, 0)
     v.grid = DirectGrid(parent=render)
     if name == 'left':
         v.grid.setHpr(0, 0, 90)
         collPlane = CollisionNode('LeftGridCol')
         collPlane.addSolid(CollisionPlane(Plane(1, 0, 0, 0)))
         collPlane.setIntoCollideMask(BitMask32.bit(21))
         v.collPlane = NodePath(collPlane)
         v.collPlane.wrtReparentTo(v.grid)
         #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_leftViewGridBack")
         LE_showInOneCam(v.grid, name)
     elif name == 'front':
         v.grid.setHpr(90, 0, 90)
         collPlane = CollisionNode('FrontGridCol')
         collPlane.addSolid(CollisionPlane(Plane(0, -1, 0, 0)))
         collPlane.setIntoCollideMask(BitMask32.bit(21))
         v.collPlane = NodePath(collPlane)
         v.collPlane.wrtReparentTo(v.grid)
         #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_frontViewGridBack")
         LE_showInOneCam(v.grid, name)
     else:
         collPlane = CollisionNode('TopGridCol')
         collPlane.addSolid(CollisionPlane(Plane(0, 0, 1, 0)))
         collPlane.setIntoCollideMask(BitMask32.bit(21))
         v.collPlane = NodePath(collPlane)
         v.collPlane.reparentTo(v.grid)
         #v.grid.gridBack.findAllMatches("**/+GeomNode")[0].setName("_topViewGridBack")
         LE_showInOneCam(v.grid, name)
     return v
示例#37
0
 def placeCollectibles(self):
     self.placeCol = render.attachNewNode("Collectible-Placeholder")
     self.placeCol.setPos(0,0,0)
     
     # Add the health items to the placeCol node
     for i in range(self.numObjects):
         # Load in the health item model
         self.collect = loader.loadModel(MYDIR+"/ball/jack")
         self.collect.setPos(0,0,0)
         self.collect.setH(90)
         self.collect.setScale(2)
         self.collect.reparentTo(self.placeCol)
         
         self.placeItem(self.collect)
         
         # Add spherical collision detection
         colSphere = CollisionSphere(0,0,0,1)
         sphereNode = CollisionNode('colSphere')
         sphereNode.addSolid(colSphere)
         sphereNode.setFromCollideMask(BitMask32.allOff())
         sphereNode.setIntoCollideMask(BitMask32.bit(1))
         sphereNp = self.collect.attachNewNode(sphereNode)
示例#38
0
    def __init__(self, name, world, pos):
        ActorNode.__init__(self, name)

        self.nodePath = NodePath(self)

        self.world = world

        # init the model or the Actor
        self.model = self.getModel()
        self.model.reparentTo(self.nodePath)

        self.nodePath.setPos(*pos)

        self.prevPos = self.nodePath.getPos()

        # collision detection
        fromObject = self.nodePath.attachNewNode(CollisionNode(name))
        self.addSolids(fromObject)
        fromObject.show()

        # setup the ground ray, needed for detecting the ground
        groundRay = CollisionRay()
        groundRay.setOrigin(0, 0, 1000)
        groundRay.setDirection(0, 0, -1)
        groundCol = CollisionNode('groundRay')
        groundCol.addSolid(groundRay)
        groundCol.setFromCollideMask(BitMask32.bit(0))
        groundCol.setIntoCollideMask(BitMask32.allOff())
        groundColNp = base.camera.attachNewNode(groundCol)
        self.groundHandler = CollisionHandlerQueue()
        self.world.cTrav.addCollider(groundColNp, self.groundHandler)

        #        self.world.cTrav.addCollider(fromObject, self.world.pusher)
        #        self.world.pusher.addCollider(fromObject, self.nodePath)

        self.postInit()
示例#39
0
class characterCollSystem():
    def __init__(self,rootNode,trav,id):
        self.GroundRay=CollisionRay(0,0,10,0,0,-1)
        self.GroundCol = CollisionNode('colDown_'+str(id))
        self.GroundCol.addSolid(self.GroundRay)
        self.GroundCol.setFromCollideMask(BitMask32.bit(1))
        self.GroundCol.setIntoCollideMask(BitMask32.allOff())
        self.GroundColNp = rootNode.attachNewNode(self.GroundCol)
        #self.GroundColNp.show()
        self.GroundHandler = CollisionHandlerQueue()
        trav.addCollider(self.GroundColNp, self.GroundHandler)
        
        self.EnvDetector=CollisionSphere(0, 0, 1, 0.8)
        self.EnvCol = CollisionNode('colEnv_'+str(id))
        self.EnvCol.addSolid(self.EnvDetector)
        self.EnvCol.setFromCollideMask(BitMask32.bit(2))
        self.EnvCol.setIntoCollideMask(BitMask32.allOff())
        self.EnvColNp = rootNode.attachNewNode(self.EnvCol)
        #self.EnvColNp.show()
        self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(self.EnvColNp, rootNode)
        trav.addCollider(self.EnvColNp, self.pusher)
            
        self.trav=trav
示例#40
0
class CogThief(DirectObject):
    """This represents a single cog thief in the cog thief game"""
    notify = directNotify.newCategory("CogThief")
    DefaultSpeedWalkAnim = 4.
    CollisionRadius = 1.25
    MaxFriendsVisible = 4
    Infinity = 100000.0  # just a really big number
    SeparationDistance = 6.0
    MinUrgency = 0.5
    MaxUrgency = 0.75

    def __init__(self, cogIndex, suitType, game, cogSpeed):
        self.cogIndex = cogIndex
        self.suitType = suitType
        self.game = game
        self.cogSpeed = cogSpeed
        suit = Suit.Suit()
        d = SuitDNA.SuitDNA()
        d.newSuit(suitType)
        suit.setDNA(d)
        # cache the walk anim
        suit.pose('walk', 0)
        self.suit = suit
        self.goal = CTGG.NoGoal
        self.goalId = CTGG.InvalidGoalId
        self.lastLocalTimeStampFromAI = 0
        self.lastPosFromAI = Point3(0, 0, 0)
        self.lastThinkTime = 0
        self.doneAdjust = False
        self.barrel = CTGG.NoBarrelCarried
        self.signalledAtReturnPos = False
        self.defaultPlayRate = 1.0
        self.netTimeSentToStartByHit = 0

        # steering loosely based on boid code game programming gems #1
        # "Portions Copyright (C) Steven Woodcock, 2000"
        self.velocity = Vec3(0, 0, 0)
        self.oldVelocity = Vec3(0, 0, 0)
        self.acceleration = Vec3(0, 0, 0)
        self.bodyLength = self.CollisionRadius * 2
        # Desired distance from closest neighbor when flying.
        self.cruiseDistance = 2 * self.bodyLength
        self.maxVelocity = self.cogSpeed
        # Maximum magnitude of acceleration as a fraction of maxSpeed.
        self.maxAcceleration = 5.0
        self.perceptionRange = 6
        self.notify.debug('cogSpeed=%s' % self.cogSpeed)

        self.kaboomSound = loader.loadSfx(
            "phase_4/audio/sfx/MG_cannon_fire_alt.mp3")
        self.kaboom = loader.loadModel(
            'phase_4/models/minigames/ice_game_kaboom')
        self.kaboom.setScale(2.0)
        self.kaboom.setBillboardPointEye()
        self.kaboom.hide()
        self.kaboomTrack = None

        splatName = 'splat-creampie'
        self.splat = globalPropPool.getProp(splatName)
        self.splat.setBillboardPointEye()
        self.splatType = globalPropPool.getPropType(splatName)

        self.pieHitSound = globalBattleSoundCache.getSound(
            'AA_wholepie_only.mp3')

    def destroy(self):
        self.ignoreAll()
        self.suit.delete()
        self.game = None

    def uniqueName(self, baseStr):
        return baseStr + '-' + str(self.game.doId)

    def handleEnterSphere(self, collEntry):
        """Handle the suit colliding with localToon."""
        #assert self.notify.debugStateCall(self)
        intoNp = collEntry.getIntoNodePath()
        self.notify.debug('handleEnterSphere suit %d hit %s' %
                          (self.cogIndex, intoNp))
        if self.game:
            self.game.handleEnterSphere(collEntry)

    def gameStart(self, gameStartTime):
        self.gameStartTime = gameStartTime

        self.initCollisions()
        self.startWalkAnim()

    def gameEnd(self):
        self.moveIval.pause()
        del self.moveIval

        self.shutdownCollisions()

        # keep the suits from walking in place
        self.suit.loop('neutral')

    def initCollisions(self):
        # Make a sphere, give it a unique name, and parent it
        # to the suit.
        self.collSphere = CollisionSphere(0, 0, 0, 1.25)
        # Make he sphere intangible
        self.collSphere.setTangible(1)
        name = "CogThiefSphere-%d" % self.cogIndex
        self.collSphereName = self.uniqueName(name)
        self.collNode = CollisionNode(self.collSphereName)
        self.collNode.setIntoCollideMask(CTGG.BarrelBitmask
                                         | ToontownGlobals.WallBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.suit.attachNewNode(self.collNode)
        #self.collNodePath.hide()

        # Add a hook looking for collisions with localToon
        self.accept('enter' + self.collSphereName, self.handleEnterSphere)

        # we need a taller collision tube to collide against for pie
        self.pieCollSphere = CollisionTube(0, 0, 0, 0, 0, 4,
                                           self.CollisionRadius)
        # Make he sphere intangible
        self.pieCollSphere.setTangible(1)
        name = "CogThiefPieSphere-%d" % self.cogIndex
        self.pieCollSphereName = self.uniqueName(name)
        self.pieCollNode = CollisionNode(self.pieCollSphereName)
        self.pieCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask)
        self.pieCollNode.addSolid(self.pieCollSphere)
        self.pieCollNodePath = self.suit.attachNewNode(self.pieCollNode)
        #self.pieCollNodePath.show()

        # Add a hook looking for collisions with localToon
        #self.accept('enter' + self.pieCollSphereName,
        #            self.handleEnter)

    def shutdownCollisions(self):
        self.ignore(self.uniqueName('enter' + self.collSphereName))

        del self.collSphere
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode

    def updateGoal(self, timestamp, inResponseClientStamp, goalType, goalId,
                   pos):
        """Update our goal and position."""
        assert self.notify.debugStateCall(self)
        self.notify.debug('self.netTimeSentToStartByHit =%s' %
                          self.netTimeSentToStartByHit)
        if not self.game:
            self.notify.debug('updateGoal self.game is None, just returning')
            return
        if not self.suit:
            self.notify.debug('updateGoal self.suit is None, just returning')
            return
        if self.goal == CTGG.NoGoal:
            self.startWalkAnim()

        if goalType == CTGG.NoGoal:
            self.notify.debug('updateGoal setting position to %s' % pos)
            self.suit.setPos(pos)

        self.lastThinkTime = 0
        self.velocity = Vec3(0, 0, 0)
        self.oldVelocity = Vec3(0, 0, 0)
        self.acceleration = Vec3(0, 0, 0)

        if goalType == CTGG.RunAwayGoal:
            #import pdb; pdb.set_trace()
            pass

        if inResponseClientStamp < self.netTimeSentToStartByHit and \
           self.goal == CTGG.NoGoal and \
           goalType == CTGG.RunAwayGoal:
            #import pdb; pdb.set_trace()
            self.notify.warning(
                'ignoring newGoal %s as cog %d was recently hit responsetime=%s hitTime=%s'
                % (CTGG.GoalStr[goalType], self.cogIndex,
                   inResponseClientStamp, self.netTimeSentToStartByHit))
        else:
            self.lastLocalTimeStampFromAI = globalClockDelta.networkToLocalTime(
                timestamp, bits=32)
            self.goal = goalType
            self.goalId = goalId
            self.lastPosFromAI = pos
            self.doneAdjust = False
        self.signalledAtReturnPos = False
        # TODO move the suit to where we expect him to be given the time difference

    def startWalkAnim(self):
        if self.suit:
            self.suit.loop('walk')
            speed = self.cogSpeed  # float(MazeData.CELL_WIDTH) / self.cellWalkDuration
            self.defaultPlayRate = float(self.cogSpeed /
                                         self.DefaultSpeedWalkAnim)
            self.suit.setPlayRate(self.defaultPlayRate, 'walk')

    def think(self):
        """Calculate where we should go."""
        if self.goal == CTGG.ToonGoal:
            self.thinkAboutCatchingToon()
        elif self.goal == CTGG.BarrelGoal:
            self.thinkAboutGettingBarrel()
        elif self.goal == CTGG.RunAwayGoal:
            self.thinkAboutRunAway()

    def thinkAboutCatchingToon(self):
        if not self.game:
            return

        av = self.game.getAvatar(self.goalId)
        if av:
            if not self.lastThinkTime:
                self.lastThinkTime = globalClock.getFrameTime()
            diffTime = globalClock.getFrameTime() - self.lastThinkTime
            avPos = av.getPos()
            myPos = self.suit.getPos()

            if not self.doneAdjust:
                myPos = self.lastPosFromAI
                self.notify.debug(
                    'thinkAboutCatchingToon not doneAdjust setting pos %s' %
                    myPos)
                self.doneAdjust = True

            self.suit.setPos(myPos)

            if self.game.isToonPlayingHitTrack(self.goalId):
                # do nothing, just look at toon
                self.suit.headsUp(av)
                self.velocity = Vec3(0, 0, 0)
                self.oldVelocity = Vec3(0, 0, 0)
                self.acceleration = Vec3(0, 0, 0)
            else:
                self.commonMove()

            newPos = self.suit.getPos()
            self.adjustPlayRate(newPos, myPos, diffTime)

        self.lastThinkTime = globalClock.getFrameTime()

    def convertNetworkStampToGameTime(self, timestamp):
        """Convert a network timestamp to game time."""
        localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32)
        gameTime = self.game.local2GameTime(localStamp)
        return gameTime

    def respondToToonHit(self, timestamp):
        """The toon hit us, react appropriately."""
        assert self.notify.debugStateCall(self)
        localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32)
        # using 1.0 sec as fudge
        #if localStamp > self.lastLocalTimeStampFromAI:
        if self.netTimeSentToStartByHit < timestamp:
            self.clearGoal()
            self.showKaboom()
            # move him to his starting postion
            startPos = CTGG.CogStartingPositions[self.cogIndex]
            oldPos = self.suit.getPos()
            self.suit.setPos(startPos)
            if self.netTimeSentToStartByHit < timestamp:
                self.netTimeSentToStartByHit = timestamp
        else:
            self.notify.debug(
                'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToToonHit'
                % (localStamp, self.lastLocalTimeStampFromAI))
        self.notify.debug(
            'respondToToonHit self.netTimeSentToStartByHit = %s' %
            self.netTimeSentToStartByHit)

    def clearGoal(self):
        """Clear goal and goal id."""
        self.goal = CTGG.NoGoal
        self.goalId = CTGG.InvalidGoalId

    def thinkAboutGettingBarrel(self):
        """Go for  a barrel."""
        if not self.game:
            return

        if not hasattr(self.game, 'barrels'):
            return
        if not self.goalId in xrange(len(self.game.barrels)):
            return

        if not self.lastThinkTime:
            self.lastThinkTime = globalClock.getFrameTime()
        diffTime = globalClock.getFrameTime() - self.lastThinkTime
        barrel = self.game.barrels[self.goalId]
        barrelPos = barrel.getPos()
        myPos = self.suit.getPos()
        if not self.doneAdjust:
            myPos = self.lastPosFromAI
            self.notify.debug(
                'thinkAboutGettingBarrel not doneAdjust setting position to %s'
                % myPos)
            self.suit.setPos(myPos)
            """
            diffTime = globalClock.getFrameTime()- self.lastLocalTimeStampFromAI
            self.notify.debug('doing adjust, diffTime = %s' % diffTime)
            if diffTime < 0:
                # it just looks really weird when it moves backwards
                diffTime = 0
                self.notify.debug('forcing diffTime to %s' % diffTime)
            """
            self.doneAdjust = True
        displacement = barrelPos - myPos
        distanceToToon = displacement.length()
        #self.notify.debug('diffTime = %s' % diffTime)
        self.suit.headsUp(barrel)
        lengthTravelled = diffTime * self.cogSpeed
        #self.notify.debug('lengthTravelled = %s' % lengthTravelled)
        # don't overshoot our target
        if lengthTravelled > distanceToToon:
            lengthTravelled = distanceToToon
            #self.notify.debug('overshooting lengthTravelled = %s' % lengthTravelled)
        displacement.normalize()
        dirVector = displacement
        dirVector *= lengthTravelled
        newPos = myPos + dirVector
        # always keep them grounded
        newPos.setZ(0)
        self.suit.setPos(newPos)
        self.adjustPlayRate(newPos, myPos, diffTime)

        self.lastThinkTime = globalClock.getFrameTime()

    def stopWalking(self, timestamp):
        """Stop the cog from walking."""
        localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32)
        if localStamp > self.lastLocalTimeStampFromAI:
            self.suit.loop('neutral')
            self.clearGoal()

    def thinkAboutRunAway(self):
        """Go for  a barrel."""
        if not self.game:
            return
        if not self.lastThinkTime:
            self.lastThinkTime = globalClock.getFrameTime()
        diffTime = globalClock.getFrameTime() - self.lastThinkTime

        returnPos = CTGG.CogReturnPositions[self.goalId]
        myPos = self.suit.getPos()
        if not self.doneAdjust:
            myPos = self.lastPosFromAI
            self.suit.setPos(myPos)
            """
            diffTime = globalClock.getFrameTime()- self.lastLocalTimeStampFromAI
            self.notify.debug('run away doing adjust, diffTime = %s' % diffTime)
            if diffTime < 0:
                # it just looks really weird when it moves backwards
                diffTime = 0
                self.notify.debug('forcing diffTime to %s' % diffTime)
            """
            self.doneAdjust = True
        displacement = returnPos - myPos
        distanceToToon = displacement.length()
        #self.notify.debug('diffTime = %s' % diffTime)
        tempNp = render.attachNewNode('tempRet')
        tempNp.setPos(returnPos)
        self.suit.headsUp(tempNp)
        tempNp.removeNode()
        lengthTravelled = diffTime * self.cogSpeed
        #self.notify.debug('lengthTravelled = %s' % lengthTravelled)
        # don't overshoot our target
        if lengthTravelled > distanceToToon:
            lengthTravelled = distanceToToon
            #self.notify.debug('overshooting lengthTravelled = %s' % lengthTravelled)
        displacement.normalize()
        dirVector = displacement
        dirVector *= lengthTravelled
        newPos = myPos + dirVector
        # always keep them grounded
        newPos.setZ(0)
        self.suit.setPos(newPos)
        self.adjustPlayRate(newPos, myPos, diffTime)

        if (self.suit.getPos() - returnPos).length() < 0.0001:
            if not self.signalledAtReturnPos and self.barrel >= 0:
                # tell the AI we're at return Pos
                self.game.sendCogAtReturnPos(self.cogIndex, self.barrel)
                self.signalledAtReturnPos = True

        self.lastThinkTime = globalClock.getFrameTime()

    def makeCogCarryBarrel(self, timestamp, inResponseClientStamp, barrelModel,
                           barrelIndex, cogPos):
        """Handle the AI telling us the barrel is attached to a cog."""
        #assert self.notify.debugStateCall(self)
        if not self.game:
            return
        localTimeStamp = globalClockDelta.networkToLocalTime(timestamp,
                                                             bits=32)
        # TODO validate time?
        self.lastLocalTimeStampFromAI = localTimeStamp
        inResponseGameTime = self.convertNetworkStampToGameTime(
            inResponseClientStamp)

        self.notify.debug('inResponseGameTime =%s timeSentToStart=%s' %
                          (inResponseGameTime, self.netTimeSentToStartByHit))
        if inResponseClientStamp  < self.netTimeSentToStartByHit and \
           self.goal == CTGG.NoGoal:
            self.notify.warning('ignoring makeCogCarrybarrel')
        else:
            barrelModel.setPos(0, -1.0, 1.5)
            barrelModel.reparentTo(self.suit)
            self.suit.setPos(cogPos)
            self.barrel = barrelIndex

    def makeCogDropBarrel(self, timestamp, inResponseClientStamp, barrelModel,
                          barrelIndex, barrelPos):
        """Handle the AI telling us the barrel is attached to a cog."""
        #assert self.notify.debugStateCall(self)
        localTimeStamp = globalClockDelta.networkToLocalTime(timestamp,
                                                             bits=32)
        # TODO validate time?
        self.lastLocalTimeStampFromAI = localTimeStamp

        barrelModel.reparentTo(render)
        barrelModel.setPos(barrelPos)

        self.barrel = CTGG.NoBarrelCarried

        #
        #self.suit.setPos(cogPos)

    def respondToPieHit(self, timestamp):
        """The toon hit us, react appropriately."""
        assert self.notify.debugStateCall(self)
        localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32)
        # argh using 1.0 sec as fudge
        #if localStamp  > self.lastLocalTimeStampFromAI:
        if self.netTimeSentToStartByHit < timestamp:
            self.clearGoal()
            self.showSplat()
            # move him to his starting postion
            startPos = CTGG.CogStartingPositions[self.cogIndex]
            oldPos = self.suit.getPos()
            self.suit.setPos(startPos)
            if self.netTimeSentToStartByHit < timestamp:
                self.netTimeSentToStartByHit = timestamp
        else:
            self.notify.debug(
                'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToPieHit'
                % (localStamp, self.lastLocalTimeStampFromAI))
            self.notify.debug(
                'respondToPieHit self.netTimeSentToStartByHit = %s' %
                self.netTimeSentToStartByHit)

    def cleanup(self):
        """Do whatever is necessary to cleanup properly."""
        self.clearGoal()
        self.ignoreAll()
        self.suit.delete()
        if self.kaboomTrack and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()
        self.suit = None
        self.game = None

    def adjustPlayRate(self, newPos, oldPos, diffTime):
        """Adjust animation rate based on how far he's moved."""
        # lets slowdown playrate if they're not moving much
        lengthTravelled = (newPos - oldPos).length()
        if diffTime:
            speed = lengthTravelled / diffTime
        else:
            speed = self.cogSpeed
        rateMult = speed / self.cogSpeed
        newRate = rateMult * self.defaultPlayRate
        self.suit.setPlayRate(newRate, 'walk')

    def commonMove(self):
        """Move the cog thief. Common for all 3 behaviors """
        if not self.lastThinkTime:
            self.lastThinkTime = globalClock.getFrameTime()
        dt = globalClock.getFrameTime() - self.lastThinkTime

        # Step 1:  Update our position.
        # Update our position based on the velocity
        # vector we computed last time around.

        self.oldpos = self.suit.getPos()
        # save off our previous position

        pos = self.suit.getPos()
        pos += self.velocity * dt
        # apply velocities.
        self.suit.setPos(pos)

        # Step 2:  SeeFriends.
        # Determine if we can see any of our flockmates.

        self.seeFriends()

        acc = Vec3(0, 0, 0)

        # well first off we want to move to our target
        self.accumulate(acc, self.getTargetVector())

        # Step 3:  Flocking behavior.
        # Do we see any of our flockmates?  If yes, it's time to implement
        # the first Three Rules (they don't matter if we can't see anybody)

        if self.numFlockmatesSeen > 0:
            #if hasattr(base,'doDebug') and base.doDebug:
            #    import pdb; pdb.set_trace()
            keepDistanceVector = self.keepDistance()
            oldAcc = Vec3(acc)
            self.accumulate(acc, keepDistanceVector)
            if self.cogIndex == 0:
                #self.notify.debug('oldAcc=%s, keepDist=%s newAcc=%s' %
                #                  (oldAcc,keepDistanceVector, acc))
                pass

        # Step 8:  Constrain acceleration
        # If our acceleration change is more than we allow, constrain it

        if (acc.length() > self.maxAcceleration):
            # definitely too much...constrain to maximum change
            acc.normalize()
            acc *= self.maxAcceleration

        # Step 9:  Implementation.
        # Here's where we apply our newly computed acceleration vector
        # to create a new velocity vector to use next update cycle.

        self.oldVelocity = self.velocity
        # save off our previous velocity

        # now add in the acceleration

        self.velocity += acc

        # Step 10:  constraint Y velocity changes.
        # Attempt to restrict flight straight up/down by damping out Y axis velocity.
        # This isn't strictly necessary, but does lead to more realistic looking flight.

        # Step 11:  Constrain our speed.
        # If we're moving faster than we're allowed to move, constrain our velocity.
        if self.velocity.length() > self.maxVelocity:
            self.velocity.normalize()
            self.velocity *= self.maxVelocity

        # Step 12:  Compute roll/pitch/yaw.
        # Compute our orientation after all this speed adjustment nonsense.
        # bah no need, we turn on a dime towards our velocity
        forwardVec = Vec3(1, 0, 0)
        heading = rad2Deg(math.atan2(self.velocity[1], self.velocity[0]))
        heading -= 90
        self.suit.setH(heading)

    def getTargetVector(self):
        """Return a vector to my goal."""
        targetPos = Point3(0, 0, 0)
        if self.goal == CTGG.ToonGoal:
            av = self.game.getAvatar(self.goalId)
            if av:
                targetPos = av.getPos()
        elif self.goal == CTGG.BarrelGoal:
            barrel = self.game.barrels[self.goalId]
            targetPos = barrel.getPos()
        elif self.goal == CTGG.RunAwayGoal:
            targetPos = CTGG.CogReturnPositions[self.goalId]
        targetPos.setZ(0)
        myPos = self.suit.getPos()
        diff = targetPos - myPos
        if diff.length() > 1.0:
            diff.normalize()
            diff *= 1.0

        return diff

    def accumulate(self, accumulator, valueToAdd):
        """Return the magnitude of the accumulated vector."""

        accumulator += valueToAdd

        return accumulator.length()

    def seeFriends(self):
        """Determines which flockmates a given flock boid can see."""
        # clear the existing visibility list of any holdover from last round

        self.clearVisibleList()

        for cogIndex in self.game.cogInfo.keys():
            if cogIndex == self.cogIndex:
                continue

            if self.sameGoal(cogIndex):
                dist = self.canISee(cogIndex)
                if dist != self.Infinity:
                    self.addToVisibleList(cogIndex)
                    if dist < self.distToNearestFlockmate:
                        self.nearestFlockmate = cogIndex
                        self.distToNearestFlockmate = dist

        return self.numFlockmatesSeen

    def clearVisibleList(self):
        """Clears the visibility list and associated fields."""
        self.visibleFriendsList = []
        self.numFlockmatesSeen = 0
        self.nearestFlockmate = None
        self.distToNearestFlockmate = self.Infinity

    def addToVisibleList(self, cogIndex):
        """Add the cog to the visible list."""
        # test:  do we see enough buddies already?
        if self.numFlockmatesSeen < self.MaxFriendsVisible:
            #nope--we can add to this one to the list
            self.visibleFriendsList.append(cogIndex)
            self.numFlockmatesSeen += 1
            if self.cogIndex == 0:
                #self.notify.debug('self.numFlockmatesSeen = %s' % self.numFlockmatesSeen)
                pass

    def canISee(self, cogIndex):
        """Return distance if I can see the other cog, infinity otherwise"""

        if self.cogIndex == cogIndex:
            # well we should never see ourself
            return self.Infinity

        cogThief = self.game.getCogThief(cogIndex)
        distance = self.suit.getDistance(cogThief.suit)

        if distance < self.perceptionRange:
            #self.notify.debug('%s can see %s' % (self.cogIndex, cogIndex))
            return distance

        # fell through; can not see it
        return self.Infinity

    def sameGoal(self, cogIndex):
        """Return true if we have the same goal."""
        cogThief = self.game.getCogThief(cogIndex)
        result = (cogThief.goalId == self.goalId) and (cogThief.goal
                                                       == self.goal)
        return result

    def keepDistance(self):
        """Generates a vector for a flock boid to maintain his
        desired separation distance from the nearest flockmate he sees.
        """
        ratio = self.distToNearestFlockmate / self.SeparationDistance
        nearestThief = self.game.getCogThief(self.nearestFlockmate)
        change = nearestThief.suit.getPos() - self.suit.getPos()

        if ratio < self.MinUrgency:
            ratio = self.MinUrgency
        if ratio > self.MaxUrgency:
            ratio = self.MaxUrgency

        # test:  are we too close to our nearest flockmate?
        if self.distToNearestFlockmate < self.SeparationDistance:
            #self.notify.debug('%d is too close to %d' % (self.cogIndex, self.nearestFlockmate))

            # too close...move away from our neighbor
            change.normalize()
            change *= -(1 - ratio
                        )  # the close we are the more we are pushed away
        elif self.distToNearestFlockmate > self.SeparationDistance:
            # too far away move towards our neighbor
            change.normalize()
            change *= ratio
        else:
            # in the UNLIKELY event we're exactly the right distance away, do nothing
            change = Vec3(0, 0, 0)

        return change

    def showKaboom(self):
        """Show the kaboom graphic and sound."""
        if self.kaboomTrack and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()
        self.kaboom.reparentTo(render)
        self.kaboom.setPos(self.suit.getPos())
        self.kaboom.setZ(3)

        self.kaboomTrack = Parallel(
            SoundInterval(self.kaboomSound, volume=0.5),
            Sequence(
                Func(self.kaboom.showThrough),
                LerpScaleInterval(self.kaboom,
                                  duration=0.5,
                                  scale=Point3(10, 10, 10),
                                  startScale=Point3(1, 1, 1),
                                  blendType='easeOut'),
                Func(self.kaboom.hide),
            ))
        self.kaboomTrack.start()

    def showSplat(self):
        """Show the splat graphic and sound."""
        if self.kaboomTrack and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()
        self.splat.reparentTo(render)
        self.splat.setPos(self.suit.getPos())
        self.splat.setZ(3)

        self.kaboomTrack = Parallel(
            SoundInterval(self.pieHitSound, volume=1.0),
            Sequence(
                Func(self.splat.showThrough),
                LerpScaleInterval(self.splat,
                                  duration=0.5,
                                  scale=1.75,
                                  startScale=Point3(0.1, 0.1, 0.1),
                                  blendType='easeOut'),
                Func(self.splat.hide),
            ))
        self.kaboomTrack.start()
示例#41
0
class CogThief(DirectObject):
    notify = directNotify.newCategory('CogThief')
    DefaultSpeedWalkAnim = 4.0
    CollisionRadius = 1.25
    MaxFriendsVisible = 4
    Infinity = 100000.0
    SeparationDistance = 6.0
    MinUrgency = 0.5
    MaxUrgency = 0.75

    def __init__(self, cogIndex, suitType, game, cogSpeed):
        self.cogIndex = cogIndex
        self.suitType = suitType
        self.game = game
        self.cogSpeed = cogSpeed
        suit = Suit.Suit()
        d = SuitDNA.SuitDNA()
        d.newSuit(suitType)
        suit.setDNA(d)
        suit.pose('walk', 0)
        self.suit = suit
        self.goal = CTGG.NoGoal
        self.goalId = CTGG.InvalidGoalId
        self.lastLocalTimeStampFromAI = 0
        self.lastPosFromAI = Point3(0, 0, 0)
        self.lastThinkTime = 0
        self.doneAdjust = False
        self.barrel = CTGG.NoBarrelCarried
        self.signalledAtReturnPos = False
        self.defaultPlayRate = 1.0
        self.netTimeSentToStartByHit = 0
        self.velocity = Vec3(0, 0, 0)
        self.oldVelocity = Vec3(0, 0, 0)
        self.acceleration = Vec3(0, 0, 0)
        self.bodyLength = self.CollisionRadius * 2
        self.cruiseDistance = 2 * self.bodyLength
        self.maxVelocity = self.cogSpeed
        self.maxAcceleration = 5.0
        self.perceptionRange = 6
        self.notify.debug('cogSpeed=%s' % self.cogSpeed)
        self.kaboomSound = loader.loadSfx(
            'phase_4/audio/sfx/MG_cannon_fire_alt.mp3')
        self.kaboom = loader.loadModel(
            'phase_4/models/minigames/ice_game_kaboom')
        self.kaboom.setScale(2.0)
        self.kaboom.setBillboardPointEye()
        self.kaboom.hide()
        self.kaboomTrack = None
        splatName = 'splat-creampie'
        self.splat = globalPropPool.getProp(splatName)
        self.splat.setBillboardPointEye()
        self.splatType = globalPropPool.getPropType(splatName)
        self.pieHitSound = globalBattleSoundCache.getSound(
            'AA_wholepie_only.mp3')

    def destroy(self):
        self.ignoreAll()
        self.suit.delete()
        self.game = None

    def uniqueName(self, baseStr):
        return baseStr + '-' + str(self.game.doId)

    def handleEnterSphere(self, collEntry):
        intoNp = collEntry.getIntoNodePath()
        self.notify.debug('handleEnterSphere suit %d hit %s' %
                          (self.cogIndex, intoNp))
        if self.game:
            self.game.handleEnterSphere(collEntry)

    def gameStart(self, gameStartTime):
        self.gameStartTime = gameStartTime
        self.initCollisions()
        self.startWalkAnim()

    def gameEnd(self):
        self.moveIval.pause()
        del self.moveIval
        self.shutdownCollisions()
        self.suit.loop('neutral')

    def initCollisions(self):
        self.collSphere = CollisionSphere(0, 0, 0, 1.25)
        self.collSphere.setTangible(1)
        name = 'CogThiefSphere-%d' % self.cogIndex
        self.collSphereName = self.uniqueName(name)
        self.collNode = CollisionNode(self.collSphereName)
        self.collNode.setIntoCollideMask(CTGG.BarrelBitmask
                                         | ToontownGlobals.WallBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.suit.attachNewNode(self.collNode)
        self.accept('enter' + self.collSphereName, self.handleEnterSphere)
        self.pieCollSphere = CollisionTube(0, 0, 0, 0, 0, 4,
                                           self.CollisionRadius)
        self.pieCollSphere.setTangible(1)
        name = 'CogThiefPieSphere-%d' % self.cogIndex
        self.pieCollSphereName = self.uniqueName(name)
        self.pieCollNode = CollisionNode(self.pieCollSphereName)
        self.pieCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask)
        self.pieCollNode.addSolid(self.pieCollSphere)
        self.pieCollNodePath = self.suit.attachNewNode(self.pieCollNode)

    def shutdownCollisions(self):
        self.ignore(self.uniqueName('enter' + self.collSphereName))
        del self.collSphere
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode

    def updateGoal(self, timestamp, inResponseClientStamp, goalType, goalId,
                   pos):
        self.notify.debug('self.netTimeSentToStartByHit =%s' %
                          self.netTimeSentToStartByHit)
        if not self.game:
            self.notify.debug('updateGoal self.game is None, just returning')
            return None

        if not self.suit:
            self.notify.debug('updateGoal self.suit is None, just returning')
            return None

        if self.goal == CTGG.NoGoal:
            self.startWalkAnim()

        if goalType == CTGG.NoGoal:
            self.notify.debug('updateGoal setting position to %s' % pos)
            self.suit.setPos(pos)

        self.lastThinkTime = 0
        self.velocity = Vec3(0, 0, 0)
        self.oldVelocity = Vec3(0, 0, 0)
        self.acceleration = Vec3(0, 0, 0)
        if goalType == CTGG.RunAwayGoal:
            pass
        1
        if inResponseClientStamp < self.netTimeSentToStartByHit and self.goal == CTGG.NoGoal and goalType == CTGG.RunAwayGoal:
            self.notify.warning(
                'ignoring newGoal %s as cog %d was recently hit responsetime=%s hitTime=%s'
                % (CTGG.GoalStr[goalType], self.cogIndex,
                   inResponseClientStamp, self.netTimeSentToStartByHit))
        else:
            self.lastLocalTimeStampFromAI = globalClockDelta.networkToLocalTime(
                timestamp, bits=32)
            self.goal = goalType
            self.goalId = goalId
            self.lastPosFromAI = pos
            self.doneAdjust = False
        self.signalledAtReturnPos = False

    def startWalkAnim(self):
        if self.suit:
            self.suit.loop('walk')
            speed = self.cogSpeed
            self.defaultPlayRate = float(self.cogSpeed /
                                         self.DefaultSpeedWalkAnim)
            self.suit.setPlayRate(self.defaultPlayRate, 'walk')

    def think(self):
        if self.goal == CTGG.ToonGoal:
            self.thinkAboutCatchingToon()
        elif self.goal == CTGG.BarrelGoal:
            self.thinkAboutGettingBarrel()
        elif self.goal == CTGG.RunAwayGoal:
            self.thinkAboutRunAway()

    def thinkAboutCatchingToon(self):
        if not self.game:
            return None

        av = self.game.getAvatar(self.goalId)
        if av:
            if not self.lastThinkTime:
                self.lastThinkTime = globalClock.getFrameTime()

            diffTime = globalClock.getFrameTime() - self.lastThinkTime
            avPos = av.getPos()
            myPos = self.suit.getPos()
            if not self.doneAdjust:
                myPos = self.lastPosFromAI
                self.notify.debug(
                    'thinkAboutCatchingToon not doneAdjust setting pos %s' %
                    myPos)
                self.doneAdjust = True

            self.suit.setPos(myPos)
            if self.game.isToonPlayingHitTrack(self.goalId):
                self.suit.headsUp(av)
                self.velocity = Vec3(0, 0, 0)
                self.oldVelocity = Vec3(0, 0, 0)
                self.acceleration = Vec3(0, 0, 0)
            else:
                self.commonMove()
            newPos = self.suit.getPos()
            self.adjustPlayRate(newPos, myPos, diffTime)

        self.lastThinkTime = globalClock.getFrameTime()

    def convertNetworkStampToGameTime(self, timestamp):
        localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32)
        gameTime = self.game.local2GameTime(localStamp)
        return gameTime

    def respondToToonHit(self, timestamp):
        localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32)
        if self.netTimeSentToStartByHit < timestamp:
            self.clearGoal()
            self.showKaboom()
            startPos = CTGG.CogStartingPositions[self.cogIndex]
            oldPos = self.suit.getPos()
            self.suit.setPos(startPos)
            if self.netTimeSentToStartByHit < timestamp:
                self.netTimeSentToStartByHit = timestamp

        else:
            self.notify.debug(
                'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToToonHit'
                % (localStamp, self.lastLocalTimeStampFromAI))
        self.notify.debug(
            'respondToToonHit self.netTimeSentToStartByHit = %s' %
            self.netTimeSentToStartByHit)

    def clearGoal(self):
        self.goal = CTGG.NoGoal
        self.goalId = CTGG.InvalidGoalId

    def thinkAboutGettingBarrel(self):
        if not self.game:
            return None

        if not hasattr(self.game, 'barrels'):
            return None

        if self.goalId not in xrange(len(self.game.barrels)):
            return None

        if not self.lastThinkTime:
            self.lastThinkTime = globalClock.getFrameTime()

        diffTime = globalClock.getFrameTime() - self.lastThinkTime
        barrel = self.game.barrels[self.goalId]
        barrelPos = barrel.getPos()
        myPos = self.suit.getPos()
        if not self.doneAdjust:
            myPos = self.lastPosFromAI
            self.notify.debug(
                'thinkAboutGettingBarrel not doneAdjust setting position to %s'
                % myPos)
            self.suit.setPos(myPos)
            self.doneAdjust = True

        displacement = barrelPos - myPos
        distanceToToon = displacement.length()
        self.suit.headsUp(barrel)
        lengthTravelled = diffTime * self.cogSpeed
        if lengthTravelled > distanceToToon:
            lengthTravelled = distanceToToon

        displacement.normalize()
        dirVector = displacement
        dirVector *= lengthTravelled
        newPos = myPos + dirVector
        newPos.setZ(0)
        self.suit.setPos(newPos)
        self.adjustPlayRate(newPos, myPos, diffTime)
        self.lastThinkTime = globalClock.getFrameTime()

    def stopWalking(self, timestamp):
        localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32)
        if localStamp > self.lastLocalTimeStampFromAI:
            self.suit.loop('neutral')
            self.clearGoal()

    def thinkAboutRunAway(self):
        if not self.game:
            return None

        if not self.lastThinkTime:
            self.lastThinkTime = globalClock.getFrameTime()

        diffTime = globalClock.getFrameTime() - self.lastThinkTime
        returnPos = CTGG.CogReturnPositions[self.goalId]
        myPos = self.suit.getPos()
        if not self.doneAdjust:
            myPos = self.lastPosFromAI
            self.suit.setPos(myPos)
            self.doneAdjust = True

        displacement = returnPos - myPos
        distanceToToon = displacement.length()
        tempNp = render.attachNewNode('tempRet')
        tempNp.setPos(returnPos)
        self.suit.headsUp(tempNp)
        tempNp.removeNode()
        lengthTravelled = diffTime * self.cogSpeed
        if lengthTravelled > distanceToToon:
            lengthTravelled = distanceToToon

        displacement.normalize()
        dirVector = displacement
        dirVector *= lengthTravelled
        newPos = myPos + dirVector
        newPos.setZ(0)
        self.suit.setPos(newPos)
        self.adjustPlayRate(newPos, myPos, diffTime)
        if (self.suit.getPos() - returnPos).length() < 0.0001:
            if not (self.signalledAtReturnPos) and self.barrel >= 0:
                self.game.sendCogAtReturnPos(self.cogIndex, self.barrel)
                self.signalledAtReturnPos = True

        self.lastThinkTime = globalClock.getFrameTime()

    def makeCogCarryBarrel(self, timestamp, inResponseClientStamp, barrelModel,
                           barrelIndex, cogPos):
        if not self.game:
            return None

        localTimeStamp = globalClockDelta.networkToLocalTime(timestamp,
                                                             bits=32)
        self.lastLocalTimeStampFromAI = localTimeStamp
        inResponseGameTime = self.convertNetworkStampToGameTime(
            inResponseClientStamp)
        self.notify.debug('inResponseGameTime =%s timeSentToStart=%s' %
                          (inResponseGameTime, self.netTimeSentToStartByHit))
        if inResponseClientStamp < self.netTimeSentToStartByHit and self.goal == CTGG.NoGoal:
            self.notify.warning('ignoring makeCogCarrybarrel')
        else:
            barrelModel.setPos(0, -1.0, 1.5)
            barrelModel.reparentTo(self.suit)
            self.suit.setPos(cogPos)
            self.barrel = barrelIndex

    def makeCogDropBarrel(self, timestamp, inResponseClientStamp, barrelModel,
                          barrelIndex, barrelPos):
        localTimeStamp = globalClockDelta.networkToLocalTime(timestamp,
                                                             bits=32)
        self.lastLocalTimeStampFromAI = localTimeStamp
        barrelModel.reparentTo(render)
        barrelModel.setPos(barrelPos)
        self.barrel = CTGG.NoBarrelCarried

    def respondToPieHit(self, timestamp):
        localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32)
        if self.netTimeSentToStartByHit < timestamp:
            self.clearGoal()
            self.showSplat()
            startPos = CTGG.CogStartingPositions[self.cogIndex]
            oldPos = self.suit.getPos()
            self.suit.setPos(startPos)
            if self.netTimeSentToStartByHit < timestamp:
                self.netTimeSentToStartByHit = timestamp

        else:
            self.notify.debug(
                'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToPieHit'
                % (localStamp, self.lastLocalTimeStampFromAI))
            self.notify.debug(
                'respondToPieHit self.netTimeSentToStartByHit = %s' %
                self.netTimeSentToStartByHit)

    def cleanup(self):
        self.clearGoal()
        self.ignoreAll()
        self.suit.delete()
        if self.kaboomTrack and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()

        self.suit = None
        self.game = None

    def adjustPlayRate(self, newPos, oldPos, diffTime):
        lengthTravelled = (newPos - oldPos).length()
        if diffTime:
            speed = lengthTravelled / diffTime
        else:
            speed = self.cogSpeed
        rateMult = speed / self.cogSpeed
        newRate = rateMult * self.defaultPlayRate
        self.suit.setPlayRate(newRate, 'walk')

    def commonMove(self):
        if not self.lastThinkTime:
            self.lastThinkTime = globalClock.getFrameTime()

        dt = globalClock.getFrameTime() - self.lastThinkTime
        self.oldpos = self.suit.getPos()
        pos = self.suit.getPos()
        pos += self.velocity * dt
        self.suit.setPos(pos)
        self.seeFriends()
        acc = Vec3(0, 0, 0)
        self.accumulate(acc, self.getTargetVector())
        if self.numFlockmatesSeen > 0:
            keepDistanceVector = self.keepDistance()
            oldAcc = Vec3(acc)
            self.accumulate(acc, keepDistanceVector)
            if self.cogIndex == 0:
                pass

        if acc.length() > self.maxAcceleration:
            acc.normalize()
            acc *= self.maxAcceleration

        self.oldVelocity = self.velocity
        self.velocity += acc
        if self.velocity.length() > self.maxVelocity:
            self.velocity.normalize()
            self.velocity *= self.maxVelocity

        forwardVec = Vec3(1, 0, 0)
        heading = rad2Deg(math.atan2(self.velocity[1], self.velocity[0]))
        heading -= 90
        self.suit.setH(heading)

    def getTargetVector(self):
        targetPos = Point3(0, 0, 0)
        if self.goal == CTGG.ToonGoal:
            av = self.game.getAvatar(self.goalId)
            if av:
                targetPos = av.getPos()

        elif self.goal == CTGG.BarrelGoal:
            barrel = self.game.barrels[self.goalId]
            targetPos = barrel.getPos()
        elif self.goal == CTGG.RunAwayGoal:
            targetPos = CTGG.CogReturnPositions[self.goalId]

        targetPos.setZ(0)
        myPos = self.suit.getPos()
        diff = targetPos - myPos
        if diff.length() > 1.0:
            diff.normalize()
            diff *= 1.0

        return diff

    def accumulate(self, accumulator, valueToAdd):
        accumulator += valueToAdd
        return accumulator.length()

    def seeFriends(self):
        self.clearVisibleList()
        for cogIndex in self.game.cogInfo.keys():
            if cogIndex == self.cogIndex:
                continue

            if self.sameGoal(cogIndex):
                dist = self.canISee(cogIndex)
                if dist != self.Infinity:
                    self.addToVisibleList(cogIndex)
                    if dist < self.distToNearestFlockmate:
                        self.nearestFlockmate = cogIndex
                        self.distToNearestFlockmate = dist

            dist != self.Infinity

        return self.numFlockmatesSeen

    def clearVisibleList(self):
        self.visibleFriendsList = []
        self.numFlockmatesSeen = 0
        self.nearestFlockmate = None
        self.distToNearestFlockmate = self.Infinity

    def addToVisibleList(self, cogIndex):
        if self.numFlockmatesSeen < self.MaxFriendsVisible:
            self.visibleFriendsList.append(cogIndex)
            self.numFlockmatesSeen += 1
            if self.cogIndex == 0:
                pass

    def canISee(self, cogIndex):
        if self.cogIndex == cogIndex:
            return self.Infinity

        cogThief = self.game.getCogThief(cogIndex)
        distance = self.suit.getDistance(cogThief.suit)
        if distance < self.perceptionRange:
            return distance

        return self.Infinity

    def sameGoal(self, cogIndex):
        cogThief = self.game.getCogThief(cogIndex)
        if cogThief.goalId == self.goalId:
            pass
        result = cogThief.goal == self.goal
        return result

    def keepDistance(self):
        ratio = self.distToNearestFlockmate / self.SeparationDistance
        nearestThief = self.game.getCogThief(self.nearestFlockmate)
        change = nearestThief.suit.getPos() - self.suit.getPos()
        if ratio < self.MinUrgency:
            ratio = self.MinUrgency

        if ratio > self.MaxUrgency:
            ratio = self.MaxUrgency

        if self.distToNearestFlockmate < self.SeparationDistance:
            change.normalize()
            change *= -(1 - ratio)
        elif self.distToNearestFlockmate > self.SeparationDistance:
            change.normalize()
            change *= ratio
        else:
            change = Vec3(0, 0, 0)
        return change

    def showKaboom(self):
        if self.kaboomTrack and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()

        self.kaboom.reparentTo(render)
        self.kaboom.setPos(self.suit.getPos())
        self.kaboom.setZ(3)
        self.kaboomTrack = Parallel(
            SoundInterval(self.kaboomSound, volume=0.5),
            Sequence(
                Func(self.kaboom.showThrough),
                LerpScaleInterval(self.kaboom,
                                  duration=0.5,
                                  scale=Point3(10, 10, 10),
                                  startScale=Point3(1, 1, 1),
                                  blendType='easeOut'),
                Func(self.kaboom.hide)))
        self.kaboomTrack.start()

    def showSplat(self):
        if self.kaboomTrack and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()

        self.splat.reparentTo(render)
        self.splat.setPos(self.suit.getPos())
        self.splat.setZ(3)
        self.kaboomTrack = Parallel(
            SoundInterval(self.pieHitSound, volume=1.0),
            Sequence(
                Func(self.splat.showThrough),
                LerpScaleInterval(self.splat,
                                  duration=0.5,
                                  scale=1.75,
                                  startScale=Point3(0.10000000000000001,
                                                    0.10000000000000001,
                                                    0.10000000000000001),
                                  blendType='easeOut'), Func(self.splat.hide)))
        self.kaboomTrack.start()
示例#42
0
class DistributedFireworksCannon(
        DistributedFireworkShow.DistributedFireworkShow):
    notify = directNotify.newCategory('DistributedFireworksCannon')

    def __init__(self, cr):
        DistributedFireworkShow.DistributedFireworkShow.__init__(self, cr)
        self.fireworksGui = None
        self.load()
        return

    def generateInit(self):
        DistributedFireworkShow.DistributedFireworkShow.generateInit(self)
        self.fireworksSphereEvent = self.uniqueName('fireworksSphere')
        self.fireworksSphereEnterEvent = 'enter' + self.fireworksSphereEvent
        self.fireworksGuiDoneEvent = 'fireworksGuiDone'
        self.shootEvent = 'fireworkShootEvent'
        self.collSphere = CollisionSphere(0, 0, 0, 2.5)
        self.collSphere.setTangible(1)
        self.collNode = CollisionNode(self.fireworksSphereEvent)
        self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.geom.attachNewNode(self.collNode)

    def generate(self):
        DistributedFireworkShow.DistributedFireworkShow.generate(self)

    def announceGenerate(self):
        self.notify.debug('announceGenerate')
        self.accept(self.fireworksSphereEnterEvent, self.__handleEnterSphere)

    def disable(self):
        self.notify.debug('disable')
        self.ignore(self.fireworksSphereEnterEvent)
        self.ignore(self.shootEvent)
        self.ignore(self.fireworksGuiDoneEvent)
        if self.fireworksGui:
            self.fireworksGui.destroy()
            self.fireworksGui = None
        DistributedFireworkShow.DistributedFireworkShow.disable(self)
        return

    def delete(self):
        self.notify.debug('delete')
        self.geom.removeNode()
        DistributedFireworkShow.DistributedFireworkShow.delete(self)

    def load(self):
        self.geom = loader.loadModel('phase_5/models/props/trashcan_TT.bam')
        self.geom.reparentTo(base.cr.playGame.hood.loader.geom)
        self.geom.setScale(0.5)

    def __handleEnterSphere(self, collEntry):
        self.notify.debug('handleEnterSphere()')
        self.ignore(self.fireworksSphereEnterEvent)
        self.sendUpdate('avatarEnter', [])

    def __handleFireworksDone(self):
        self.ignore(self.fireworksGuiDoneEvent)
        self.ignore(self.shootEvent)
        self.sendUpdate('avatarExit')
        self.fireworksGui.destroy()
        self.fireworksGui = None
        return

    def freeAvatar(self):
        base.localAvatar.posCamera(0, 0)
        base.cr.playGame.getPlace().setState('walk')
        self.accept(self.fireworksSphereEnterEvent, self.__handleEnterSphere)

    def setMovie(self, mode, avId, timestamp):
        timeStamp = globalClockDelta.localElapsedTime(timestamp)
        isLocalToon = avId == base.localAvatar.doId
        if mode == FIREWORKS_MOVIE_CLEAR:
            self.notify.debug('setMovie: clear')
            return
        elif mode == FIREWORKS_MOVIE_GUI:
            self.notify.debug('setMovie: gui')
            if isLocalToon:
                self.fireworksGui = FireworksGui.FireworksGui(
                    self.fireworksGuiDoneEvent, self.shootEvent)
                self.accept(self.fireworksGuiDoneEvent,
                            self.__handleFireworksDone)
                self.accept(self.shootEvent, self.localShootFirework)
            return
        else:
            self.notify.warning('unknown mode in setMovie: %s' % mode)

    def setPosition(self, x, y, z):
        self.pos = [x, y, z]
        self.geom.setPos(x, y, z)

    def localShootFirework(self, index):
        style = index
        col1, col2 = self.fireworksGui.getCurColor()
        amp = 30
        dummy = base.localAvatar.attachNewNode('dummy')
        dummy.setPos(0, 100, 60)
        pos = dummy.getPos(render)
        dummy.removeNode()
        print 'lauFirework: %s, col=%s' % (index, col1)
        self.d_requestFirework(pos[0], pos[1], pos[2], style, col1, col2)
示例#43
0
class Character: 
    
    """A character with an animated avatar that moves left, right or forward 
       according to the controls turned on or off in self.controlMap. 
    
    Public fields: 
    self.controlMap -- The character's movement controls 
    self.actor -- The character's Actor (3D animated model) 
    
    
    Public functions: 
    __init__ -- Initialise the character 
    move -- Move and animate the character for one frame. This is a task 
            function that is called every frame by Panda3D. 
    setControl -- Set one of the character's controls on or off. 
    
    """ 

    def __init__(self, model, run, walk, startPos, scale):        
        """Initialise the character. 
        
        Arguments: 
        model -- The path to the character's model file (string) 
           run : The path to the model's run animation (string) 
           walk : The path to the model's walk animation (string) 
           startPos : Where in the world the character will begin (pos) 
           scale : The amount by which the size of the model will be scaled 
                   (float) 
                    
           """ 

        self.controlMap = {"left":0, "right":0, "up":0, "down":0} 

        self.actor = Actor(Config.MYDIR+model, 
                                 {"run":Config.MYDIR+run, 
                                  "walk":Config.MYDIR+walk})        
        self.actor.reparentTo(render) 
        self.actor.setScale(scale) 
        self.actor.setPos(startPos) 

        self.controller = Controller.LocalController(self)
        
        taskMgr.add(self.move,"moveTask") # Note: deriving classes DO NOT need 
                                          # to add their own move tasks to the 
                                          # task manager. If they override 
                                          # self.move, then their own self.move 
                                          # function will get called by the 
                                          # task manager (they must then 
                                          # explicitly call Character.move in 
                                          # that function if they want it). 
        self.prevtime = 0 
        self.isMoving = False 

        # We will detect the height of the terrain by creating a collision 
        # ray and casting it downward toward the terrain.  One ray will 
        # start above ralph's head, and the other will start above the camera. 
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it 
        # hits the terrain, we can detect the height.  If it hits anything 
        # else, we rule that the move is illegal. 

        self.cTrav = CollisionTraverser() 

        self.groundRay = CollisionRay() 
        self.groundRay.setOrigin(0,0,1000) 
        self.groundRay.setDirection(0,0,-1) 
        self.groundCol = CollisionNode('ralphRay') 
        self.groundCol.addSolid(self.groundRay) 
        self.groundCol.setFromCollideMask(BitMask32.bit(1)) 
        self.groundCol.setIntoCollideMask(BitMask32.allOff()) 
        self.groundColNp = self.actor.attachNewNode(self.groundCol)
        self.groundHandler = CollisionHandlerQueue() 
        self.cTrav.addCollider(self.groundColNp, self.groundHandler) 

        # Uncomment this line to see the collision rays 
        # self.groundColNp.show() 

        #Uncomment this line to show a visual representation of the
        #collisions occuring 
        # self.cTrav.showCollisions(render) 

    def move(self, task): 
        """Move and animate the character for one frame. 
        
        This is a task function that is called every frame by Panda3D. 
        The character is moved according to which of it's movement controls 
        are set, and the function keeps the character's feet on the ground 
        and stops the character from moving if a collision is detected. 
        This function also handles playing the characters movement 
        animations. 

        Arguments: 
        task -- A direct.task.Task object passed to this function by Panda3D. 
        
        Return: 
        Task.cont -- To tell Panda3D to call this task function again next 
                     frame. 
        """ 
        
        elapsed = task.time - self.prevtime 

        # save the character's initial position so that we can restore it, 
        # in case he falls off the map or runs into something. 

        startpos = self.actor.getPos() 

        # pass on input
        self.controller.move(task, elapsed)
        
        # If the character is moving, loop the run animation. 
        # If he is standing still, stop the animation. 

        if (self.controlMap["up"]!=0) or (self.controlMap["left"]!=0) or (self.controlMap["right"]!=0) or (self.controlMap["down"]!=0): 
            
            if self.isMoving is False: 
                self.actor.loop("run") 
                self.isMoving = True 
        else: 
            if self.isMoving: 
                self.actor.stop() 
                self.actor.pose("walk",5) 
                self.isMoving = False 

        # Now check for collisions. 

        self.cTrav.traverse(render) 

        # Adjust the character's Z coordinate.  If the character's ray hit terrain, 
        # update his Z. If it hit anything else, or didn't hit anything, put 
        # him back where he was last frame. 

        entries = [] 
        for i in range(self.groundHandler.getNumEntries()): 
            entry = self.groundHandler.getEntry(i) 
            entries.append(entry) 
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), 
                                     x.getSurfacePoint(render).getZ())) 
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.actor.setZ(entries[0].getSurfacePoint(render).getZ()) 
        else: 
            self.actor.setPos(startpos) 

        # Store the task time and continue. 
        self.prevtime = task.time 
        return Task.cont 

    def setControl(self, control, value): 
        """Set the state of one of the character's movement controls. 
        
        Arguments: 
        See self.controlMap in __init__. 
        control -- The control to be set, must be a string matching one of 
                   the strings in self.controlMap. 
        value -- The value to set the control to. 
        
        """ 

        # FIXME: this function is duplicated in Camera and Character, and 
        # keyboard control settings are spread throughout the code. Maybe 
        # add a Controllable class? 
        
        self.controlMap[control] = value 
示例#44
0
class CogdoFlyingLevel(DirectObject):
    notify = directNotify.newCategory('CogdoFlyingLevel')

    def __init__(self, parent, frameModel, startPlatformModel,
                 endPlatformModel, quadLengthUnits, quadVisibilityAhead,
                 quadVisibiltyBehind):
        self.parent = parent
        self.quadLengthUnits = quadLengthUnits
        self._halfQuadLengthUnits = quadLengthUnits / 2.0
        self.quadVisibiltyAhead = quadVisibilityAhead
        self.quadVisibiltyBehind = quadVisibiltyBehind
        self._frameModel = frameModel
        self.root = NodePath('CogdoFlyingLevel')
        self.quadrantRoot = NodePath('QuadrantsRoot')
        self.quadrantRoot.reparentTo(self.root)
        self._startPlatformModel = startPlatformModel
        self._startPlatformModel.reparentTo(self.root)
        self._startPlatformModel.setZ(Globals.Level.StartPlatformHeight)
        self._endPlatformModel = endPlatformModel
        self._endPlatformModel.reparentTo(self.root)
        self._endPlatformModel.setZ(Globals.Level.EndPlatformHeight)
        self.wallR = self._frameModel.find('**/wallR')
        self.wallL = self._frameModel.find('**/wallL')
        self._exit = CogdoGameExit()
        self._exit.reparentTo(self._endPlatformModel)
        loc = self._endPlatformModel.find('**/exit_loc')
        offset = loc.getPos(render)
        self._exit.setPos(render, offset)
        self.quadrants = []
        self.visibleQuadIndices = []
        self._numQuads = 0
        self._currentQuadNum = -1
        self._camera = None
        self._initCollisions()
        self.upLimit = self._frameModel.find('**/limit_up').getZ(render)
        self.downLimit = self._frameModel.find('**/limit_down').getZ(render)
        self.leftLimit = self._frameModel.find('**/limit_left').getX(
            render) - 30.0
        self.rightLimit = self._frameModel.find('**/limit_right').getX(
            render) + 30.0
        self.backLimit = -self.quadLengthUnits
        self.forwardLimit = self.quadLengthUnits * 20
        self._frameModel.flattenStrong()
        self.gatherableFactory = CogdoFlyingGatherableFactory()
        self.obstacleFactory = CogdoFlyingObtacleFactory()
        return

    def getExit(self):
        return self._exit

    def getBounds(self):
        return ((self.leftLimit, self.rightLimit),
                (self.backLimit, self.forwardLimit), (self.downLimit,
                                                      self.upLimit))

    def getGatherable(self, serialNum):
        for quadrant in self.quadrants:
            for gatherable in quadrant.gatherables:
                if gatherable.serialNum == serialNum:
                    return gatherable

        return None

    def ready(self):
        self.gatherableFactory.destroy()
        del self.gatherableFactory
        self.obstacleFactory.destroy()
        del self.obstacleFactory
        self._initStartEndPlatforms()
        self._frameModel.reparentTo(self.root)
        self.root.reparentTo(self.parent)
        self.root.stash()

    def _initStartEndPlatforms(self):
        self.startPlatform = CogdoFlyingPlatform(
            self._startPlatformModel,
            Globals.Level.PlatformTypes.StartPlatform)
        self.endPlatform = CogdoFlyingPlatform(
            self._endPlatformModel, Globals.Level.PlatformTypes.EndPlatform)
        self._endPlatformModel.setY(self.convertQuadNumToY(self._numQuads))
        self.backLimit = self._startPlatformModel.getY(
            render) - Globals.Level.StartPlatformLength * 0.7
        self.forwardLimit = self._endPlatformModel.getY(
            render) + Globals.Level.EndPlatformLength * 0.7

    def _initCollisions(self):
        self.collPlane = CollisionPlane(
            Plane(Vec3(0, 0, 1.0), Point3(0, 0, 10)))
        self.collPlane.setTangible(0)
        self.collNode = CollisionNode('fogPlane')
        self.collNode.setIntoCollideMask(OTPGlobals.FloorBitmask)
        self.collNode.addSolid(self.collPlane)
        self.collNodePath = self.root.attachNewNode(self.collNode)
        self.collNodePath.hide()

    def destroy(self):
        del self.collPlane
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode
        for quadrant in self.quadrants:
            quadrant.destroy()

        self._exit.destroy()
        del self._exit
        self.root.removeNode()
        del self.root

    def onstage(self):
        self.root.unstash()
        self.update(0.0)

    def offstage(self):
        self.root.stash()

    def start(self, startTime=0.0):
        self._startTime = startTime

    def stop(self):
        pass

    def getLength(self):
        return self.quadLengthUnits * self.getNumQuadrants()

    def appendQuadrant(self, model):
        quadrant = CogdoFlyingLevelQuadrant(self._numQuads, model, self,
                                            self.root)
        if self._numQuads == 0:
            quadrant.generateGatherables(self._startPlatformModel)
        quadrant.offstage()
        self.quadrants.append(quadrant)
        self._numQuads = len(self.quadrants)

    def getNumQuadrants(self):
        return self._numQuads

    def setCamera(self, camera):
        self._camera = camera

    def getCameraActualQuadrant(self):
        camY = self._camera.getY(render)
        y = self.root.getY(render)
        return self.convertYToQuadNum(camY - y)

    def update(self, dt=0.0):
        if self._camera is None:
            return
        quadNum = clamp(self.getCameraActualQuadrant(), 0, self._numQuads - 1)
        if quadNum < self._numQuads:
            self.quadrants[quadNum].update(dt)
            if quadNum + 1 < self._numQuads:
                self.quadrants[quadNum + 1].update(dt)
            if quadNum != self._currentQuadNum:
                self._switchToQuadrant(quadNum)
        return

    def _switchToQuadrant(self, quadNum):
        self.visibleQuadIndices = []
        if quadNum >= 0:
            if quadNum > 0:
                self.quadrants[max(quadNum - self.quadVisibiltyBehind,
                                   0)].onstage()
            for i in range(
                    quadNum,
                    min(quadNum + self.quadVisibiltyAhead + 1,
                        self._numQuads)):
                self.quadrants[i].onstage()
                self.visibleQuadIndices.append(i)
                if i == 0:
                    self.startPlatform.onstage()
                elif i == self._numQuads - 1:
                    self.endPlatform.onstage()

        self._currentQuadNum = quadNum
        for i in range(
                0, max(
                    self._currentQuadNum - self.quadVisibiltyBehind,
                    0)) + range(
                        min(self._currentQuadNum + self.quadVisibiltyAhead + 1,
                            self._numQuads), self._numQuads):
            self.quadrants[i].offstage()
            if i == 0:
                self.startPlatform.offstage()
            elif i == self._numQuads - 1:
                self.endPlatform.offstage()

    def convertQuadNumToY(self, quadNum):
        return quadNum * self.quadLengthUnits

    def convertYToQuadNum(self, y):
        return int(y / self.quadLengthUnits)

    def convertCenterYToQuadNum(self, y):
        return self.convertYToQuadNum(y + self._halfQuadLengthUnits)
class DistributedPartyTrampolineActivity(DistributedPartyActivity):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyTrampolineActivity')

    def __init__(self, cr, doJellyBeans = True, doTricks = False, texture = None):
        DistributedPartyTrampolineActivity.notify.debug('__init__')
        DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityTypes.GuestInitiated, wantLever=False, wantRewardGui=True)
        self.doJellyBeans = doJellyBeans
        self.doTricks = doTricks
        self.texture = texture
        self.toon = None
        self.trampHeight = 3.6
        self.trampK = 400.0
        self.normalTrampB = 2.5
        self.leavingTrampB = 8.0
        self.trampB = self.normalTrampB
        self.g = -32.0
        self.jumpBoost = 330.0
        self.beginningBoost = 500.0
        self.beginningBoostThreshold = self.trampHeight + 1.5
        self.earlyJumpThreshold = 75.0
        self.boingThreshold = 300.0
        self.turnFactor = 120.0
        self.stepDT = 0.001
        self.targetCameraPos = Point3(0.0, 40.0, 10.0)
        self.cameraSpeed = 2.0
        self.hopOffPos = Point3(16.0, 0.0, 0.0)
        self.indicatorFactor = 0.0095
        self.dropShadowCutoff = 15.0
        self.minHeightForText = 15.0
        self.heightTextOffset = -0.065
        self.beanOffset = 0.5
        self.guiBeanOffset = -0.02
        self.jumpTextShown = False
        self.toonJumped = False
        self.turnLeft = False
        self.turnRight = False
        self.leavingTrampoline = False
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.lastPeak = 0.0
        self.beginRoundInterval = None
        self.hopOnAnim = None
        self.hopOffAnim = None
        self.flashTextInterval = None
        self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans
        self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus
        self.jellyBeanStartHeight = 20.0
        self.jellyBeanStopHeight = 90.0
        self.jellyBeanColors = [VBase4(1.0, 0.5, 0.5, 1.0),
         VBase4(0.5, 1.0, 0.5, 1.0),
         VBase4(0.5, 1.0, 1.0, 1.0),
         VBase4(1.0, 1.0, 0.4, 1.0),
         VBase4(0.4, 0.4, 1.0, 1.0),
         VBase4(1.0, 0.5, 1.0, 1.0)]
        delta = (self.jellyBeanStopHeight - self.jellyBeanStartHeight) / (self.numJellyBeans - 1)
        self.jellyBeanPositions = [ self.jellyBeanStartHeight + n * delta for n in xrange(self.numJellyBeans) ]
        self.doSimulateStep = False
        return

    def load(self):
        DistributedPartyTrampolineActivity.notify.debug('load')
        DistributedPartyActivity.load(self)
        self.loadModels()
        self.loadCollision()
        self.loadGUI()
        self.loadSounds()
        self.loadIntervals()
        self.activityFSM = TrampolineActivityFSM(self)
        self.activityFSM.request('Idle')
        self.animFSM = TrampolineAnimFSM(self)
        self.setBestHeightInfo('', 0)

    def loadModels(self):
        self.tramp = self.root.attachNewNode(self.uniqueName('tramp'))
        self.trampActor = Actor('phase_13/models/parties/trampoline_model', {'emptyAnim': 'phase_13/models/parties/trampoline_anim'})
        self.trampActor.reparentTo(self.tramp)
        if self.texture:
            reskinNode = self.tramp.find('**/trampoline/__Actor_modelRoot/-GeomNode')
            reskinNode.setTexture(loader.loadTexture(self.texture), 100)
        self.surface = NodePath(self.uniqueName('trampSurface'))
        self.surface.reparentTo(self.tramp)
        self.surface.setZ(self.trampHeight)
        self.trampActor.controlJoint(self.surface, 'modelRoot', 'trampoline_joint1')
        self.sign.setPos(PartyGlobals.TrampolineSignOffset)
        self.beans = [ loader.loadModelCopy('phase_4/models/props/jellybean4') for i in xrange(self.numJellyBeans) ]
        for bean in self.beans:
            bean.find('**/jellybean').setP(-35.0)
            bean.setScale(3.0)
            bean.setTransparency(True)
            bean.reparentTo(self.tramp)
            bean.stash()

        self.beans[-1].setScale(8.0)

    def loadCollision(self):
        collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4)
        collTube.setTangible(True)
        self.trampolineCollision = CollisionNode(self.uniqueName('TrampolineCollision'))
        self.trampolineCollision.addSolid(collTube)
        self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask | OTPGlobals.WallBitmask)
        self.trampolineCollisionNP = self.tramp.attachNewNode(self.trampolineCollision)
        collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0)
        collSphere.setTangible(False)
        self.trampolineTrigger = CollisionNode(self.uniqueName('TrampolineTrigger'))
        self.trampolineTrigger.addSolid(collSphere)
        self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask)
        self.trampolineTriggerNP = self.tramp.attachNewNode(self.trampolineTrigger)
        self.accept('enter%s' % self.uniqueName('TrampolineTrigger'), self.onTrampolineTrigger)

    def loadGUI(self):
        self.gui = loader.loadModel('phase_13/models/parties/trampolineGUI')
        self.gui.reparentTo(base.a2dTopLeft)
        self.gui.setPos(0.115, 0, -1)
        self.gui.hide()
        self.toonIndicator = self.gui.find('**/trampolineGUI_MovingBar')
        jumpLineLocator = self.gui.find('**/jumpLine_locator')
        guiBean = self.gui.find('**/trampolineGUI_GreenJellyBean')
        self.gui.find('**/trampolineGUI_GreenJellyBean').stash()
        self.guiBeans = [ guiBean.instanceUnderNode(jumpLineLocator, self.uniqueName('guiBean%d' % i)) for i in xrange(self.numJellyBeans) ]
        self.guiBeans[-1].setScale(1.5)
        heightTextNode = TextNode(self.uniqueName('TrampolineActivity.heightTextNode'))
        heightTextNode.setFont(ToontownGlobals.getSignFont())
        heightTextNode.setAlign(TextNode.ALeft)
        heightTextNode.setText('0.0')
        heightTextNode.setShadow(0.05, 0.05)
        heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0)
        heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0)
        self.heightText = jumpLineLocator.attachNewNode(heightTextNode)
        self.heightText.setX(0.15)
        self.heightText.setScale(0.1)
        self.heightText.setAlphaScale(0.0)
        self.quitEarlyButtonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui')
        quitEarlyUp = self.quitEarlyButtonModels.find('**//InventoryButtonUp')
        quitEarlyDown = self.quitEarlyButtonModels.find('**/InventoryButtonDown')
        quitEarlyRollover = self.quitEarlyButtonModels.find('**/InventoryButtonRollover')
        self.quitEarlyButton = DirectButton(parent=base.a2dTopRight, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-0.183, 0, -0.4), scale=0.09, command=self.leaveTrampoline)
        self.quitEarlyButton.stash()
        self.flashText = OnscreenText(text='', pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True)
        self.timer = PartyUtils.getNewToontownTimer()
        self.timer.posInTopRightCorner()
        return

    def loadSounds(self):
        self.jellyBeanSound = base.loadSfx('phase_4/audio/sfx/sparkly.ogg')
        self.boingSound = base.loadSfx('phase_4/audio/sfx/target_trampoline_2.ogg')
        self.whistleSound = base.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg')

    def loadIntervals(self):

        def prepareHeightText():
            self.heightText.node().setText(TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ()))
            self.heightText.setZ(self.indicatorFactor * self.toon.getZ() + self.heightTextOffset)

        self.heightTextInterval = Sequence(Func(prepareHeightText), LerpFunc(self.heightText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0))

    def unload(self):
        DistributedPartyTrampolineActivity.notify.debug('unload')
        if self.hopOnAnim and self.hopOnAnim.isPlaying():
            self.hopOnAnim.finish()
        if self.hopOffAnim and self.hopOffAnim.isPlaying():
            self.hopOffAnim.finish()
        if self.beginRoundInterval and self.beginRoundInterval.isPlaying():
            self.beginRoundInterval.finish()
        if self.flashTextInterval and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        if self.heightTextInterval and self.heightTextInterval.isPlaying():
            self.heightTextInterval.finish()
        self.timer.stop()
        DistributedPartyActivity.unload(self)
        taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask'))
        taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask'))
        self.ignoreAll()
        del self.heightTextInterval
        del self.beginRoundInterval
        del self.hopOnAnim
        del self.hopOffAnim
        del self.flashTextInterval
        if hasattr(self, 'beanAnims'):
            self.cleanupJellyBeans()
        self.quitEarlyButton.destroy()
        del self.quitEarlyButton
        del self.gui
        del self.activityFSM
        del self.animFSM
        return

    def setBestHeightInfo(self, toonName, height):
        self.bestHeightInfo = (toonName, height)
        DistributedPartyTrampolineActivity.notify.debug('%s has the best height of %d' % (toonName, height))
        if height > 0:
            self.setSignNote(TTLocalizer.PartyTrampolineBestHeight % self.bestHeightInfo)
        else:
            self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet)

    def leaveTrampoline(self):
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp)
            self.leavingTrampoline = True
            self.timer.reset()
            self.trampB = self.leavingTrampB
            self.ignore('control')
            self.quitEarlyButton.stash()
            self.gui.hide()
        return

    def requestAnim(self, request):
        self.animFSM.request(request)

    def b_requestAnim(self, request):
        self.requestAnim(request)
        self.sendUpdate('requestAnim', [request])

    def requestAnimEcho(self, request):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.requestAnim(request)
        return

    def removeBeans(self, beansToRemove):
        for i in beansToRemove:
            height, bean, guiBean, beanAnim = self.beanDetails[i]
            guiBean.stash()
            if i in self.beansToCollect:
                self.beansToCollect.remove(i)
            else:
                self.notify.warning('removeBeans avoided a crash, %d not in self.beansToCollect' % i)
            self.poofBean(bean, beanAnim)

    def b_removeBeans(self, beansToRemove):
        self.removeBeans(beansToRemove)
        self.sendUpdate('removeBeans', [beansToRemove])

    def removeBeansEcho(self, beansToRemove):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.removeBeans(beansToRemove)
        return

    def joinRequestDenied(self, reason):
        DistributedPartyActivity.joinRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny)
        base.cr.playGame.getPlace().fsm.request('walk')

    def exitRequestDenied(self, reason):
        DistributedPartyActivity.exitRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny)

    def setState(self, newState, timestamp):
        DistributedPartyTrampolineActivity.notify.debug('setState( newState=%s, ... )' % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        self.activityFSM.request(newState)

    def startIdle(self):
        DistributedPartyTrampolineActivity.notify.debug('startIdle')

    def finishIdle(self):
        DistributedPartyTrampolineActivity.notify.debug('finishIdle')

    def startRules(self):
        DistributedPartyTrampolineActivity.notify.debug('startRules')
        if self.doJellyBeans:
            self.setupJellyBeans()
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self.acquireToon()
        return

    def startActive(self):
        DistributedPartyTrampolineActivity.notify.debug('startActive')
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            base.setCellsActive(base.bottomCells, True)
            self.accept('arrow_left', self.onLeft)
            self.accept('arrow_left-up', self.onLeftUp)
            self.accept('arrow_right', self.onRight)
            self.accept('arrow_right-up', self.onRightUp)
            self.beginRoundInterval = Sequence(Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady), Wait(1.2), Func(self.flashMessage, TTLocalizer.PartyTrampolineGo), Func(self.beginRound))
            self.beginRoundInterval.start()
        return

    def finishActive(self):
        DistributedPartyTrampolineActivity.notify.debug('finishActive')
        if self.doJellyBeans:
            self.cleanupJellyBeans()

    def setupJellyBeans(self):
        self.beanAnims = []
        self.beansToCollect = []
        self.beanDetails = []
        self.numBeansCollected = 0
        for i in xrange(self.numJellyBeans):
            bean = self.beans[i]
            guiBean = self.guiBeans[i]
            height = self.jellyBeanPositions[i]
            color = random.choice(self.jellyBeanColors)
            bean.find('**/jellybean').setColor(color)
            if self.toon.doId == base.localAvatar.doId:
                bean.setAlphaScale(1.0)
            else:
                bean.setAlphaScale(0.5)
            guiBean.setColor(color)
            bean.setZ(height + self.toon.getHeight() + self.beanOffset)
            guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset)
            bean.setH(0.0)
            bean.unstash()
            guiBean.unstash()
            beanAnim = bean.hprInterval(1.5, VBase3((i % 2 * 2 - 1) * 360.0, 0.0, 0.0))
            beanAnim.loop()
            self.beanAnims.append(beanAnim)
            self.beanDetails.append((height,
             bean,
             guiBean,
             beanAnim))

        self.beansToCollect = range(self.numJellyBeans)

    def cleanupJellyBeans(self):
        for bean in self.beans:
            bean.stash()

        for guiBean in self.guiBeans:
            guiBean.stash()

        if hasattr(self, 'beanAnims'):
            for beanAnim in self.beanAnims:
                beanAnim.finish()

            del self.beanAnims
            del self.beansToCollect

    def beginRound(self):
        base.playSfx(self.whistleSound)
        self.timer.setTime(PartyGlobals.TrampolineDuration)
        self.timer.countdown(PartyGlobals.TrampolineDuration)
        self.timer.show()
        self.gui.show()
        self.quitEarlyButton.unstash()
        self.notify.debug('Accepting contorl')
        self.accept('control', self.onJump)
        self.notify.debug('setting simulate step to true')
        self.doSimulateStep = True

    def acquireToon(self):
        self.toon.disableSmartCameraViews()
        self.toon.stopUpdateSmartCamera()
        camera.wrtReparentTo(render)
        self.toon.dropShadow.reparentTo(hidden)
        self.toon.startPosHprBroadcast(period=0.2)
        self.toonAcceleration = 0.0
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.trampB = self.normalTrampB
        self.leavingTrampoline = False
        self.hopOnAnim = Sequence(Func(self.toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, Point3(0.0, 0.0, self.trampHeight), 5.0, self.tramp), Func(self.postHopOn))
        self.hopOnAnim.start()

    def postHopOn(self):
        self.toon.setH(self.toon.getH() + 90.0)
        self.toon.dropShadow.reparentTo(self.surface)
        self.timeLeftToSimulate = 0.0
        self.doSimulateStep = False
        taskMgr.add(self.updateTask, self.uniqueName('TrampolineActivity.updateTask'))
        base.setCellsActive(base.leftCells, False)
        base.setCellsActive(base.bottomCells, False)
        DistributedPartyActivity.startRules(self)

    def releaseToon(self):
        self._hideFlashMessage()
        self.ignore('arrow_left')
        self.ignore('arrow_left-up')
        self.ignore('arrow_right')
        self.ignore('arrow_right-up')
        taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask'))
        self.hopOffAnim = Sequence(self.toon.hprInterval(0.5, VBase3(-90.0, 0.0, 0.0), other=self.tramp), Func(self.toon.b_setAnimState, 'jump', 1.0), Func(self.toon.dropShadow.reparentTo, hidden), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0, self.tramp), Func(self.postHopOff))
        self.hopOffAnim.start()

    def postHopOff(self):
        base.setCellsActive(base.leftCells, True)
        self.timer.stop()
        self.timer.hide()
        self.toon.dropShadow.reparentTo(self.toon.getShadowJoint())
        self.toon.dropShadow.setAlphaScale(1.0)
        self.toon.dropShadow.setScale(1.0)
        self.b_requestAnim('Off')
        camera.reparentTo(base.localAvatar)
        base.localAvatar.startUpdateSmartCamera()
        base.localAvatar.enableSmartCameraViews()
        base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex)
        place = base.cr.playGame.getPlace()
        if self.doJellyBeans:
            self.sendUpdate('awardBeans', [self.numBeansCollected, int(self.topHeight)])
            if int(self.topHeight) > self.bestHeightInfo[1]:
                self.sendUpdate('reportHeightInformation', [int(self.topHeight)])
        self.d_toonExitDemand()

    def onTrampolineTrigger(self, collEntry):
        if self.activityFSM.state == 'Idle' and self.toon == None and base.cr.playGame.getPlace().fsm.getCurrentState().getName() == 'walk':
            base.cr.playGame.getPlace().fsm.request('activity')
            self.d_toonJoinRequest()
        else:
            self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied, duration=2.0)
        return

    def onJump(self):
        self.notify.debug('got onJump')
        if self.toon != None and self.toon.getZ() < self.trampHeight:
            self.toonJumped = True
            self.b_requestAnim('Jump')
        else:
            self.notify.debug('z is less than tramp height')
        return

    def onLeft(self):
        self.turnLeft = True

    def onLeftUp(self):
        self.turnLeft = False

    def onRight(self):
        self.turnRight = True

    def onRightUp(self):
        self.turnRight = False

    def handleToonJoined(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonJoined')
        self.toon = self.getAvatar(toonId)
        if self.toon != None and not self.toon.isEmpty():
            self.oldJumpSquatPlayRate = self.toon.getPlayRate('jump-squat')
            self.oldJumpLandPlayRate = self.toon.getPlayRate('jump-land')
            self.toon.setPlayRate(2.5, 'jump-squat')
            self.toon.setPlayRate(2.0, 'jump-land')
            self.turnLeft = False
            self.turnRight = False
            self.activityFSM.request('Rules')
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.add(self.remoteUpdateTask, self.uniqueName('TrampolineActivity.remoteUpdateTask'))
        else:
            self.notify.warning('handleToonJoined could not get toon %d' % toonId)
        return

    def handleToonExited(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonExited')
        if self.toon != None:
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask'))
            self.surface.setZ(self.trampHeight)
            self.toon.setPlayRate(self.oldJumpSquatPlayRate, 'jump-squat')
            self.toon.setPlayRate(self.oldJumpLandPlayRate, 'jump-land')
            self.toon = None
        return

    def handleToonDisabled(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonDisabled')
        DistributedPartyTrampolineActivity.notify.debug('avatar ' + str(toonId) + ' disabled')
        if base.localAvatar.doId == toonId:
            self.releaseToon()

    def handleRulesDone(self):
        self.sendUpdate('toonReady')
        self.finishRules()

    def getTitle(self):
        if self.doJellyBeans:
            return TTLocalizer.PartyTrampolineJellyBeanTitle
        elif self.doTricks:
            return TTLocalizer.PartyTrampolineTricksTitle
        else:
            return DistributedPartyActivity.getTitle(self)

    def getInstructions(self):
        return TTLocalizer.PartyTrampolineActivityInstructions

    def updateTask(self, task):
        z = self.toon.getZ()
        dt = globalClock.getDt()
        if self.doSimulateStep:
            self.timeLeftToSimulate += dt
            while self.timeLeftToSimulate >= self.stepDT:
                z, a = self.simulateStep(z)
                self.timeLeftToSimulate -= self.stepDT

        self.toon.setZ(z)
        if z <= self.trampHeight:
            self.surface.setZ(z)
        else:
            self.surface.setZ(self.trampHeight)
        self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor)
        if self.turnLeft:
            self.toon.setH(self.toon.getH() + self.turnFactor * dt)
        if self.turnRight:
            self.toon.setH(self.toon.getH() - self.turnFactor * dt)
        currentPos = base.camera.getPos(self.toon)
        vec = self.targetCameraPos - currentPos
        newPos = currentPos + vec * (dt * self.cameraSpeed)
        base.camera.setPos(self.toon, newPos)
        base.camera.lookAt(self.toon)
        #if z > self.trampHeight:
        #    heightFactor = 1.0 - min(1.0, (z - self.trampHeight) / self.dropShadowCutoff)
        #    self.toon.dropShadow.setAlphaScale(heightFactor)
        #    self.toon.dropShadow.setScale(max(0.1, heightFactor))
        #else:
        #    self.toon.dropShadow.setAlphaScale(1.0)
        #    self.toon.dropShadow.setScale(1.0)
        if self.leavingTrampoline and z < self.trampHeight and abs(a) < 0.1:
            self.releaseToon()
        return Task.cont

    def simulateStep(self, z):
        if z >= self.trampHeight:
            a = self.g
            self.toonJumped = False
        else:
            a = self.g + self.trampK * (self.trampHeight - z) - self.trampB * self.toonVelocity
            if self.toonJumped:
                if self.lastPeak > self.earlyJumpThreshold or self.toonVelocity >= -300000.0:
                    a += self.jumpBoost
                    if self.lastPeak < self.beginningBoostThreshold:
                        a += self.beginningBoost
        lastVelocity = self.toonVelocity
        self.toonVelocity += a * self.stepDT
        if lastVelocity > 0.0 and self.toonVelocity <= 0.0:
            topOfJump = True
            bottomOfJump = False
        elif lastVelocity < 0.0 and self.toonVelocity >= 0.0:
            topOfJump = False
            bottomOfJump = True
        else:
            topOfJump = False
            bottomOfJump = False
        newZ = z + self.toonVelocity * self.stepDT
        if newZ > self.topHeight:
            self.topHeight = newZ
            if self.doJellyBeans:
                self.collectJellyBeans(newZ)
        if topOfJump:
            self.lastPeak = newZ
            if newZ >= self.minHeightForText:
                self.heightTextInterval.start()
        if topOfJump:
            if newZ > self.trampHeight + 20.0:
                self.b_requestAnim('Falling')
            elif self.animFSM.state == 'Jump':
                self.b_requestAnim('Falling')
        if newZ <= self.trampHeight and z > self.trampHeight:
            if self.animFSM.state == 'Falling':
                self.b_requestAnim('Land')
            elif self.animFSM.state != 'Neutral':
                self.b_requestAnim('Neutral')
        if bottomOfJump and a > self.boingThreshold:
            base.playSfx(self.boingSound)
        return (newZ, a)

    def collectJellyBeans(self, z):
        beansToRemove = []
        for i in self.beansToCollect:
            height = self.beanDetails[i][0]
            if height <= z:
                beansToRemove.append(i)

        if len(beansToRemove) > 0:
            base.playSfx(self.jellyBeanSound)
            self.numBeansCollected += len(beansToRemove)
            self.b_removeBeans(beansToRemove)

    def remoteUpdateTask(self, task):
        if self.toon != None and not self.toon.isEmpty():
            z = self.toon.getZ()
            if z <= self.trampHeight:
                self.surface.setZ(z)
            else:
                self.surface.setZ(self.trampHeight)
        return Task.cont

    def poofBean(self, bean, beanAnim):
        if bean == None:
            self.notify.warning('poofBean, returning immediately as bean is None')
            return
        if bean.isEmpty():
            self.notify.warning('poofBean, returning immediately as bean is empty')
            return
        currentAlpha = bean.getColorScale()[3]
        currentScale = bean.getScale()
        poofAnim = Sequence(Parallel(LerpFunc(bean.setAlphaScale, fromData=currentAlpha, toData=0.0, duration=0.25), LerpFunc(bean.setScale, fromData=currentScale, toData=currentScale * 5.0, duration=0.25)), Func(bean.stash), Func(beanAnim.finish), Func(bean.setAlphaScale, currentAlpha), Func(bean.setScale, currentScale))
        poofAnim.start()
        return

    def _showFlashMessage(self, message):
        if self.isDisabled():
            return
        if self.flashTextInterval is not None and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        self.flashText.setText(message)
        self.flashText.setAlphaScale(1.0)
        self.flashText.unstash()
        return

    def _hideFlashMessage(self, duration = 0.0):
        if self.isDisabled():
            pass
        self.flashTextInterval = Sequence(Wait(duration), LerpFunc(self.flashText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), Func(self.flashText.stash))
        self.flashTextInterval.start()

    def flashMessage(self, message, duration = 0.5):
        self._showFlashMessage(message)
        self._hideFlashMessage(duration)
示例#46
0
class DistributedCogKart(DistributedElevatorExt.DistributedElevatorExt):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedCogKart')
    JumpOutOffsets = ((6.5, -2, -0.025), (-6.5, -2, -0.025), (3.75, 5, -0.025),
                      (-3.75, 5, -0.025))

    def __init__(self, cr):
        DistributedElevatorExt.DistributedElevatorExt.__init__(self, cr)
        self.type = ElevatorConstants.ELEVATOR_COUNTRY_CLUB
        self.kartModelPath = 'phase_12/models/bossbotHQ/Coggolf_cart3.bam'
        self.leftDoor = None
        self.rightDoor = None
        self.fillSlotTrack = None
        return

    def generate(self):
        DistributedElevatorExt.DistributedElevatorExt.generate(self)
        self.loader = self.cr.playGame.hood.loader
        if self.loader:
            self.notify.debug('Loader has been loaded')
            self.notify.debug(str(self.loader))
        else:
            self.notify.debug('Loader has not been loaded')
        self.golfKart = render.attachNewNode('golfKartNode')
        self.kart = loader.loadModel(self.kartModelPath)
        self.kart.setPos(0, 0, 0)
        self.kart.setScale(1)
        self.kart.reparentTo(self.golfKart)
        self.golfKart.reparentTo(self.loader.geom)
        self.wheels = self.kart.findAllMatches('**/wheelNode*')
        self.numWheels = self.wheels.getNumPaths()

    def announceGenerate(self):
        DistributedElevatorExt.DistributedElevatorExt.announceGenerate(self)
        angle = self.startingHpr[0]
        angle -= 90
        radAngle = deg2Rad(angle)
        unitVec = Vec3(math.cos(radAngle), math.sin(radAngle), 0)
        unitVec *= 45.0
        self.endPos = self.startingPos + unitVec
        self.endPos.setZ(0.5)
        dist = Vec3(self.endPos - self.enteringPos).length()
        wheelAngle = dist / (4.8 * 1.4 * math.pi) * 360
        self.kartEnterAnimateInterval = Parallel(
            LerpHprInterval(
                self.wheels[0], 5.0,
                Vec3(self.wheels[0].getH(), wheelAngle,
                     self.wheels[0].getR())),
            LerpHprInterval(
                self.wheels[1], 5.0,
                Vec3(self.wheels[1].getH(), wheelAngle,
                     self.wheels[1].getR())),
            LerpHprInterval(
                self.wheels[2], 5.0,
                Vec3(self.wheels[2].getH(), wheelAngle,
                     self.wheels[2].getR())),
            LerpHprInterval(
                self.wheels[3], 5.0,
                Vec3(self.wheels[3].getH(), wheelAngle,
                     self.wheels[3].getR())),
            name='CogKartAnimate')
        trolleyExitTrack1 = Parallel(LerpPosInterval(self.golfKart, 5.0,
                                                     self.endPos),
                                     self.kartEnterAnimateInterval,
                                     name='CogKartExitTrack')
        self.trolleyExitTrack = Sequence(trolleyExitTrack1)
        self.trolleyEnterTrack = Sequence(
            LerpPosInterval(self.golfKart,
                            5.0,
                            self.startingPos,
                            startPos=self.enteringPos))
        self.closeDoors = Sequence(self.trolleyExitTrack,
                                   Func(self.onDoorCloseFinish))
        self.openDoors = Sequence(self.trolleyEnterTrack)

    def delete(self):
        DistributedElevatorExt.DistributedElevatorExt.delete(self)
        if hasattr(self, 'elevatorFSM'):
            del self.elevatorFSM

    def setBldgDoId(self, bldgDoId):
        self.bldg = None
        self.setupElevatorKart()
        return

    def setupElevatorKart(self):
        collisionRadius = ElevatorConstants.ElevatorData[
            self.type]['collRadius']
        self.elevatorSphere = CollisionSphere(0, 0, 0, collisionRadius)
        self.elevatorSphere.setTangible(1)
        self.elevatorSphereNode = CollisionNode(
            self.uniqueName('elevatorSphere'))
        self.elevatorSphereNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
        self.elevatorSphereNode.addSolid(self.elevatorSphere)
        self.elevatorSphereNodePath = self.getElevatorModel().attachNewNode(
            self.elevatorSphereNode)
        self.elevatorSphereNodePath.hide()
        self.elevatorSphereNodePath.reparentTo(self.getElevatorModel())
        self.elevatorSphereNodePath.stash()
        self.boardedAvIds = {}
        self.finishSetup()

    def setColor(self, r, g, b):
        pass

    def getElevatorModel(self):
        return self.golfKart

    def enterWaitEmpty(self, ts):
        DistributedElevatorExt.DistributedElevatorExt.enterWaitEmpty(self, ts)

    def exitWaitEmpty(self):
        DistributedElevatorExt.DistributedElevatorExt.exitWaitEmpty(self)

    def forceDoorsOpen(self):
        pass

    def forceDoorsClosed(self):
        pass

    def setPosHpr(self, x, y, z, h, p, r):
        self.startingPos = Vec3(x, y, z)
        self.enteringPos = Vec3(x, y, z - 10)
        self.startingHpr = Vec3(h, 0, 0)
        self.golfKart.setPosHpr(x, y, z, h, 0, 0)

    def enterClosing(self, ts):
        if self.localToonOnBoard:
            elevator = self.getPlaceElevator()
            if elevator:
                elevator.fsm.request('elevatorClosing')
        self.closeDoors.start(ts)

    def enterClosed(self, ts):
        self.forceDoorsClosed()
        self.kartDoorsClosed(self.getZoneId())

    def kartDoorsClosed(self, zoneId):
        if self.localToonOnBoard:
            hoodId = ZoneUtil.getHoodId(zoneId)
            doneStatus = {
                'loader': 'suitInterior',
                'where': 'suitInterior',
                'hoodId': hoodId,
                'zoneId': zoneId,
                'shardId': None
            }
            elevator = self.elevatorFSM
            del self.elevatorFSM
            elevator.signalDone(doneStatus)
        return

    def setCountryClubInteriorZone(self, zoneId):
        if self.localToonOnBoard:
            hoodId = self.cr.playGame.hood.hoodId
            countryClubId = self.countryClubId
            if bboard.has('countryClubIdOverride'):
                countryClubId = bboard.get('countryClubIdOverride')
            doneStatus = {
                'loader': 'cogHQLoader',
                'where': 'countryClubInterior',
                'how': 'teleportIn',
                'zoneId': zoneId,
                'countryClubId': self.countryClubId,
                'hoodId': hoodId
            }
            self.cr.playGame.getPlace().elevator.signalDone(doneStatus)

    def setCountryClubInteriorZoneForce(self, zoneId):
        place = self.cr.playGame.getPlace()
        if place:
            place.fsm.request('elevator', [self, 1])
            hoodId = self.cr.playGame.hood.hoodId
            countryClubId = self.countryClubId
            if bboard.has('countryClubIdOverride'):
                countryClubId = bboard.get('countryClubIdOverride')
            doneStatus = {
                'loader': 'cogHQLoader',
                'where': 'countryClubInterior',
                'how': 'teleportIn',
                'zoneId': zoneId,
                'countryClubId': self.countryClubId,
                'hoodId': hoodId
            }
            if hasattr(place, 'elevator') and place.elevator:
                place.elevator.signalDone(doneStatus)
            else:
                self.notify.warning(
                    "setMintInteriorZoneForce: Couldn't find playGame.getPlace().elevator, zoneId: %s"
                    % zoneId)
        else:
            self.notify.warning(
                "setCountryClubInteriorZoneForce: Couldn't find playGame.getPlace(), zoneId: %s"
                % zoneId)

    def setCountryClubId(self, countryClubId):
        self.countryClubId = countryClubId

    def getZoneId(self):
        return 0

    def fillSlot(self, index, avId, wantBoardingShow=0):
        self.notify.debug('%s.fillSlot(%s, %s, ... %s)' %
                          (self.doId, index, avId, globalClock.getRealTime()))
        request = self.toonRequests.get(index)
        if request:
            self.cr.relatedObjectMgr.abortRequest(request)
            del self.toonRequests[index]
        if avId == 0:
            pass
        elif avId not in self.cr.doId2do:
            func = PythonUtil.Functor(self.gotToon, index, avId)
            self.toonRequests[index] = self.cr.relatedObjectMgr.requestObjects(
                [avId], allCallback=func)
        elif not self.isSetup:
            self.deferredSlots.append((index, avId, wantBoardingShow))
        else:
            if avId == base.localAvatar.getDoId():
                place = base.cr.playGame.getPlace()
                if not place:
                    return
                elevator = self.getPlaceElevator()
                if elevator == None:
                    place.fsm.request('elevator')
                    elevator = self.getPlaceElevator()
                if not elevator:
                    return
                self.localToonOnBoard = 1
                if hasattr(localAvatar,
                           'boardingParty') and localAvatar.boardingParty:
                    localAvatar.boardingParty.forceCleanupInviteePanel()
                    localAvatar.boardingParty.forceCleanupInviterPanels()
                if hasattr(base.localAvatar, 'elevatorNotifier'):
                    base.localAvatar.elevatorNotifier.cleanup()
                cameraTrack = Sequence()
                cameraTrack.append(
                    Func(elevator.fsm.request, 'boarding',
                         [self.getElevatorModel()]))
                cameraTrack.append(Func(elevator.fsm.request, 'boarded'))
            toon = self.cr.doId2do[avId]
            toon.stopSmooth()
            toon.wrtReparentTo(self.golfKart)
            sitStartDuration = toon.getDuration('sit-start')
            jumpTrack = self.generateToonJumpTrack(toon, index)
            track = Sequence(jumpTrack,
                             Func(toon.setAnimState, 'Sit', 1.0),
                             Func(self.clearToonTrack, avId),
                             name=toon.uniqueName('fillElevator'),
                             autoPause=1)
            if wantBoardingShow:
                boardingTrack, boardingTrackType = self.getBoardingTrack(
                    toon, index, True)
                track = Sequence(boardingTrack, track)
                if avId == base.localAvatar.getDoId():
                    cameraWaitTime = 2.5
                    if boardingTrackType == BoardingGroupShow.TRACK_TYPE_RUN:
                        cameraWaitTime = 0.5
                    cameraTrack = Sequence(Wait(cameraWaitTime), cameraTrack)
            if self.canHideBoardingQuitBtn(avId):
                track = Sequence(
                    Func(localAvatar.boardingParty.groupPanel.disableQuitButton
                         ), track)
            if avId == base.localAvatar.getDoId():
                track = Parallel(cameraTrack, track)
            track.delayDelete = DelayDelete.DelayDelete(
                toon, 'CogKart.fillSlot')
            self.storeToonTrack(avId, track)
            track.start()
            self.fillSlotTrack = track
            self.boardedAvIds[avId] = None
        return

    def generateToonJumpTrack(self, av, seatIndex):
        av.pose('sit', 47)
        hipOffset = av.getHipsParts()[2].getPos(av)

        def getToonJumpTrack(av, seatIndex):
            def getJumpDest(av=av, node=self.golfKart):
                dest = Point3(0, 0, 0)
                if hasattr(self, 'golfKart') and self.golfKart:
                    dest = Vec3(self.golfKart.getPos(av.getParent()))
                    seatNode = self.golfKart.find('**/seat' +
                                                  str(seatIndex + 1))
                    dest += seatNode.getPos(self.golfKart)
                    dna = av.getStyle()
                    dest -= hipOffset
                    if seatIndex < 2:
                        dest.setY(dest.getY() + 2 * hipOffset.getY())
                    dest.setZ(dest.getZ() + 0.1)
                else:
                    self.notify.warning(
                        'getJumpDestinvalid golfKart, returning (0,0,0)')
                return dest

            def getJumpHpr(av=av, node=self.golfKart):
                hpr = Point3(0, 0, 0)
                if hasattr(self, 'golfKart') and self.golfKart:
                    hpr = self.golfKart.getHpr(av.getParent())
                    if seatIndex < 2:
                        hpr.setX(hpr.getX() + 180)
                    else:
                        hpr.setX(hpr.getX())
                    angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX())
                    hpr.setX(angle)
                else:
                    self.notify.warning(
                        'getJumpHpr invalid golfKart, returning (0,0,0)')
                return hpr

            toonJumpTrack = Parallel(
                ActorInterval(av, 'jump'),
                Sequence(
                    Wait(0.43),
                    Parallel(
                        LerpHprInterval(av, hpr=getJumpHpr, duration=0.9),
                        ProjectileInterval(av,
                                           endPos=getJumpDest,
                                           duration=0.9))))
            return toonJumpTrack

        def getToonSitTrack(av):
            toonSitTrack = Sequence(ActorInterval(av, 'sit-start'),
                                    Func(av.loop, 'sit'))
            return toonSitTrack

        toonJumpTrack = getToonJumpTrack(av, seatIndex)
        toonSitTrack = getToonSitTrack(av)
        jumpTrack = Sequence(
            Parallel(toonJumpTrack, Sequence(Wait(1), toonSitTrack)))
        return jumpTrack

    def emptySlot(self, index, avId, bailFlag, timestamp, timeSent=0):
        if self.fillSlotTrack:
            self.fillSlotTrack.finish()
            self.fillSlotTrack = None
        if avId == 0:
            pass
        elif not self.isSetup:
            newSlots = []
            for slot in self.deferredSlots:
                if slot[0] != index:
                    newSlots.append(slot)

            self.deferredSlots = newSlots
        elif avId in self.cr.doId2do:
            if bailFlag == 1 and hasattr(self, 'clockNode'):
                if timestamp < self.countdownTime and timestamp >= 0:
                    self.countdown(self.countdownTime - timestamp)
                else:
                    self.countdown(self.countdownTime)
            toon = self.cr.doId2do[avId]
            toon.stopSmooth()
            sitStartDuration = toon.getDuration('sit-start')
            jumpOutTrack = self.generateToonReverseJumpTrack(toon, index)
            track = Sequence(jumpOutTrack,
                             Func(self.notifyToonOffElevator, toon),
                             Func(self.clearToonTrack, avId),
                             name=toon.uniqueName('emptyElevator'),
                             autoPause=1)
            if self.canHideBoardingQuitBtn(avId):
                track.append(
                    Func(
                        localAvatar.boardingParty.groupPanel.enableQuitButton))
                track.append(Func(localAvatar.boardingParty.enableGoButton))
            track.delayDelete = DelayDelete.DelayDelete(
                toon, 'CogKart.emptySlot')
            self.storeToonTrack(toon.doId, track)
            track.start()
            if avId == base.localAvatar.getDoId():
                messenger.send('exitElevator')
            if avId in self.boardedAvIds:
                del self.boardedAvIds[avId]
        else:
            self.notify.warning('toon: ' + str(avId) + " doesn't exist, and" +
                                ' cannot exit the elevator!')
        return

    def generateToonReverseJumpTrack(self, av, seatIndex):
        self.notify.debug('av.getH() = %s' % av.getH())

        def getToonJumpTrack(av, destNode):
            def getJumpDest(av=av, node=destNode):
                dest = node.getPos(av.getParent())
                dest += Vec3(*self.JumpOutOffsets[seatIndex])
                return dest

            def getJumpHpr(av=av, node=destNode):
                hpr = node.getHpr(av.getParent())
                hpr.setX(hpr.getX() + 180)
                angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX())
                hpr.setX(angle)
                return hpr

            toonJumpTrack = Parallel(
                ActorInterval(av, 'jump'),
                Sequence(
                    Wait(0.1),
                    Parallel(
                        ProjectileInterval(av,
                                           endPos=getJumpDest,
                                           duration=0.9))))
            return toonJumpTrack

        toonJumpTrack = getToonJumpTrack(av, self.golfKart)
        jumpTrack = Sequence(toonJumpTrack, Func(av.loop, 'neutral'),
                             Func(av.wrtReparentTo, render))
        return jumpTrack

    def startCountdownClock(self, countdownTime, ts):
        DistributedElevatorExt.DistributedElevatorExt.startCountdownClock(
            self, countdownTime, ts)
        self.clock.setH(self.clock.getH() + 180)

    def rejectBoard(self, avId, reason=0):
        print('rejectBoard %s' % reason)
        if hasattr(base.localAvatar, 'elevatorNotifier'):
            if reason == ElevatorConstants.REJECT_SHUFFLE:
                base.localAvatar.elevatorNotifier.showMe(
                    TTLocalizer.ElevatorHoppedOff)
            elif reason == ElevatorConstants.REJECT_MINLAFF:
                base.localAvatar.elevatorNotifier.showMe(
                    TTLocalizer.KartMinLaff % self.minLaff)
            elif reason == ElevatorConstants.REJECT_PROMOTION:
                base.localAvatar.elevatorNotifier.showMe(
                    TTLocalizer.BossElevatorRejectMessage)
            elif reason == ElevatorConstants.REJECT_NOT_YET_AVAILABLE:
                base.localAvatar.elevatorNotifier.showMe(
                    TTLocalizer.NotYetAvailable)
        doneStatus = {'where': 'reject'}
        elevator = self.getPlaceElevator()
        if elevator:
            elevator.signalDone(doneStatus)

    def getDestName(self):
        if self.countryClubId == ToontownGlobals.BossbotCountryClubIntA:
            return TTLocalizer.ElevatorBossBotCourse0
        elif self.countryClubId == ToontownGlobals.BossbotCountryClubIntB:
            return TTLocalizer.ElevatorBossBotCourse1
        elif self.countryClubId == ToontownGlobals.BossbotCountryClubIntC:
            return TTLocalizer.ElevatorBossBotCourse2
class CogdoFlyingLegalEagle(DirectObject, FSM):
    CollSphereName = 'CogdoFlyingLegalEagleSphere'
    CollisionEventName = 'CogdoFlyingLegalEagleCollision'
    InterestCollName = 'CogdoFlyingLegalEagleInterestCollision'
    RequestAddTargetEventName = 'CogdoFlyingLegalEagleRequestTargetEvent'
    RequestAddTargetAgainEventName = 'CogdoFlyingLegalEagleRequestTargetAgainEvent'
    RequestRemoveTargetEventName = 'CogdoFlyingLegalEagleRemoveTargetEvent'
    ForceRemoveTargetEventName = 'CogdoFlyingLegalEagleForceRemoveTargetEvent'
    EnterLegalEagle = 'CogdoFlyingLegalEagleDamageToon'
    ChargingToAttackEventName = 'LegalEagleChargingToAttack'
    LockOnToonEventName = 'LegalEagleLockOnToon'
    CooldownEventName = 'LegalEagleCooldown'
    notify = DirectNotifyGlobal.directNotify.newCategory('CogdoFlyingLegalEagle')
    
    def __init__(self, nest, index, suitDnaName = 'le'):
        FSM.__init__(self, 'CogdoFlyingLegalEagle')
        self.defaultTransitions = {
            'Off': [
                'Roost'],
            'Roost': [
                'TakeOff',
                'Off'],
            'TakeOff': [
                'LockOnToon',
                'LandOnNest',
                'Off'],
            'LockOnToon': [
                'RetreatToNest',
                'ChargeUpAttack',
                'Off'],
            'ChargeUpAttack': [
                'RetreatToNest',
                'Attack',
                'Off'],
            'Attack': [
                'RetreatToSky',
                'Off'],
            'RetreatToSky': [
                'Cooldown',
                'Off'],
            'Cooldown': [
                'LockOnToon',
                'LandOnNest',
                'Off'],
            'RetreatToNest': [
                'LandOnNest',
                'Off'],
            'LandOnNest': [
                'Roost',
                'Off'] }
        self.index = index
        self.nest = nest
        self.target = None
        self.isEagleInterested = False
        self.collSphere = None
        self.suit = Suit.Suit()
        d = SuitDNA.SuitDNA()
        d.newSuit(suitDnaName)
        self.suit.setDNA(d)
        self.suit.reparentTo(render)
        swapAvatarShadowPlacer(self.suit, 'legalEagle-%sShadowPlacer' % index)
        self.suit.setPos(self.nest.getPos(render))
        self.suit.setHpr(-180, 0, 0)
        self.suit.stash()
        self.prop = None
        self.attachPropeller()
        head = self.suit.find('**/joint_head')
        self.interestConeOrigin = self.nest.attachNewNode('fakeHeadNodePath')
        self.interestConeOrigin.setPos(render, head.getPos(render) + Vec3(0, Globals.LegalEagle.InterestConeOffset, 0))
        self.attackTargetPos = None
        self.startOfRetreatToSkyPos = None
        pathModel = CogdoUtil.loadFlyingModel('legalEaglePaths')
        self.chargeUpMotionPath = Mopath.Mopath(name = 'chargeUpMotionPath-%i' % self.index)
        self.chargeUpMotionPath.loadNodePath(pathModel.find('**/charge_path'))
        self.retreatToSkyMotionPath = Mopath.Mopath(name = 'retreatToSkyMotionPath-%i' % self.index)
        self.retreatToSkyMotionPath.loadNodePath(pathModel.find('**/retreat_path'))
        audioMgr = base.cogdoGameAudioMgr
        self._screamSfx = audioMgr.createSfx('legalEagleScream', self.suit)
        self.initIntervals()

    
    def attachPropeller(self):
        if self.prop == None:
            self.prop = BattleProps.globalPropPool.getProp('propeller')
            head = self.suit.find('**/joint_head')
            self.prop.reparentTo(head)
        

    
    def detachPropeller(self):
        if self.prop:
            self.prop.cleanup()
            self.prop.removeNode()
            self.prop = None
        

    
    def _getAnimationIval(self, animName, startFrame = 0, endFrame = None, duration = 1):
        if endFrame == None:
            pass
        1
        frames = endFrame - startFrame
        frameRate = self.suit.getFrameRate(animName)
        newRate = frames / duration
        playRate = newRate / frameRate
        ival = Sequence(ActorInterval(self.suit, animName, playRate = playRate))
        return ival

    
    def initIntervals(self):
        dur = Globals.LegalEagle.LiftOffTime
        nestPos = self.nest.getPos(render)
        airPos = nestPos + Vec3(0.0, 0.0, Globals.LegalEagle.LiftOffHeight)
        self.takeOffSeq = Sequence(Parallel(Sequence(Wait(dur * 0.59999999999999998), LerpPosInterval(self.suit, dur * 0.40000000000000002, startPos = nestPos, pos = airPos, blendType = 'easeInOut'))), Wait(1.5), Func(self.request, 'next'), name = '%s.takeOffSeq-%i' % (self.__class__.__name__, self.index))
        self.landOnNestPosLerp = LerpPosInterval(self.suit, 1.0, startPos = airPos, pos = nestPos, blendType = 'easeInOut')
        self.landingSeq = Sequence(Func(self.updateLandOnNestPosLerp), Parallel(self.landOnNestPosLerp), Func(self.request, 'next'), name = '%s.landingSeq-%i' % (self.__class__.__name__, self.index))
        dur = Globals.LegalEagle.ChargeUpTime
        self.chargeUpPosLerp = LerpFunc(self.moveAlongChargeUpMopathFunc, fromData = 0.0, toData = self.chargeUpMotionPath.getMaxT(), duration = dur, blendType = 'easeInOut')
        self.chargeUpAttackSeq = Sequence(Func(self.updateChargeUpPosLerp), self.chargeUpPosLerp, Func(self.request, 'next'), name = '%s.chargeUpAttackSeq-%i' % (self.__class__.__name__, self.index))
        dur = Globals.LegalEagle.RetreatToNestTime
        self.retreatToNestPosLerp = LerpPosInterval(self.suit, dur, startPos = Vec3(0, 0, 0), pos = airPos, blendType = 'easeInOut')
        self.retreatToNestSeq = Sequence(Func(self.updateRetreatToNestPosLerp), self.retreatToNestPosLerp, Func(self.request, 'next'), name = '%s.retreatToNestSeq-%i' % (self.__class__.__name__, self.index))
        dur = Globals.LegalEagle.RetreatToSkyTime
        self.retreatToSkyPosLerp = LerpFunc(self.moveAlongRetreatMopathFunc, fromData = 0.0, toData = self.retreatToSkyMotionPath.getMaxT(), duration = dur, blendType = 'easeOut')
        self.retreatToSkySeq = Sequence(Func(self.updateRetreatToSkyPosLerp), self.retreatToSkyPosLerp, Func(self.request, 'next'), name = '%s.retreatToSkySeq-%i' % (self.__class__.__name__, self.index))
        dur = Globals.LegalEagle.PreAttackTime
        self.preAttackLerpXY = LerpFunc(self.updateAttackXY, fromData = 0.0, toData = 1.0, duration = dur)
        self.preAttackLerpZ = LerpFunc(self.updateAttackZ, fromData = 0.0, toData = 1.0, duration = dur, blendType = 'easeOut')
        dur = Globals.LegalEagle.PostAttackTime
        self.postAttackPosLerp = LerpPosInterval(self.suit, dur, startPos = Vec3(0, 0, 0), pos = Vec3(0, 0, 0))
        self.attackSeq = Sequence(Parallel(self.preAttackLerpXY, self.preAttackLerpZ), Func(self.updatePostAttackPosLerp), self.postAttackPosLerp, Func(self.request, 'next'), name = '%s.attackSeq-%i' % (self.__class__.__name__, self.index))
        dur = Globals.LegalEagle.CooldownTime
        self.cooldownSeq = Sequence(Wait(dur), Func(self.request, 'next'), name = '%s.cooldownSeq-%i' % (self.__class__.__name__, self.index))
        self.propTrack = Sequence(ActorInterval(self.prop, 'propeller', startFrame = 0, endFrame = 14))
        self.hoverOverNestSeq = Sequence(ActorInterval(self.suit, 'landing', startFrame = 10, endFrame = 20, playRate = 0.5), ActorInterval(self.suit, 'landing', startFrame = 20, endFrame = 10, playRate = 0.5))

    
    def initCollision(self):
        self.collSphere = CollisionSphere(0, 0, 0, 0)
        self.collSphere.setTangible(0)
        self.collNode = CollisionNode('%s-%s' % (self.CollSphereName, self.index))
        self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.suit.attachNewNode(self.collNode)
        self.collNodePath.hide()
        self.accept('enter%s-%s' % (self.CollSphereName, self.index), self.handleEnterSphere)
        self.setCollSphereToNest()

    
    def getInterestConeLength(self):
        return Globals.LegalEagle.InterestConeLength + Globals.LegalEagle.InterestConeOffset

    
    def isToonInView(self, toon):
        distanceThreshold = self.getInterestConeLength()
        angleThreshold = Globals.LegalEagle.InterestConeAngle
        toonPos = toon.getPos(render)
        nestPos = self.nest.getPos(render)
        distance = toon.getDistance(self.interestConeOrigin)
        if distance > distanceThreshold:
            return False
        
        if toonPos[1] > nestPos[1]:
            return False
        
        a = toon.getPos(render) - self.interestConeOrigin.getPos(render)
        a.normalize()
        b = Vec3(0, -1, 0)
        dotProduct = a.dot(b)
        angle = math.degrees(math.acos(dotProduct))
        if angle <= angleThreshold / 2.0:
            return True
        else:
            return False

    
    def update(self, dt, localPlayer):
        if Globals.Dev.NoLegalEagleAttacks:
            return None
        
        inView = self.isToonInView(localPlayer.toon)
        if inView and not (self.isEagleInterested):
            self.handleEnterInterest()
        elif inView and self.isEagleInterested:
            self.handleAgainInterest()
        elif not inView and self.isEagleInterested:
            self.handleExitInterest()
        

    
    def updateLockOnTask(self):
        dt = globalClock.getDt()
        targetPos = self.target.getPos(render)
        suitPos = self.suit.getPos(render)
        nestPos = self.nest.getPos(render)
        attackPos = Vec3(targetPos)
        attackPos[1] = nestPos[1] + Globals.LegalEagle.LockOnDistanceFromNest
        attackPos[2] += Globals.LegalEagle.VerticalOffset
        if attackPos[2] < nestPos[2]:
            attackPos[2] = nestPos[2]
        
        attackChangeVec = (attackPos - suitPos) * Globals.LegalEagle.LockOnSpeed
        self.suit.setPos(suitPos + attackChangeVec * dt)
        return Task.cont

    
    def updateAttackXY(self, value):
        if Globals.LegalEagle.EagleAttackShouldXCorrect:
            x = self.readyToAttackPos.getX() + (self.attackTargetPos.getX() - self.readyToAttackPos.getX()) * value
            self.suit.setX(x)
        
        y = self.readyToAttackPos.getY() + (self.attackTargetPos.getY() - self.readyToAttackPos.getY()) * value
        self.suit.setY(y)

    
    def updateAttackZ(self, value):
        z = self.readyToAttackPos.getZ() + (self.attackTargetPos.getZ() - self.readyToAttackPos.getZ()) * value
        self.suit.setZ(z)

    
    def moveAlongChargeUpMopathFunc(self, value):
        self.chargeUpMotionPath.goTo(self.suit, value)
        self.suit.setPos(self.suit.getPos() + self.startOfChargeUpPos)

    
    def moveAlongRetreatMopathFunc(self, value):
        self.retreatToSkyMotionPath.goTo(self.suit, value)
        self.suit.setPos(self.suit.getPos() + self.startOfRetreatToSkyPos)

    
    def updateChargeUpPosLerp(self):
        self.startOfChargeUpPos = self.suit.getPos(render)

    
    def updateLandOnNestPosLerp(self):
        self.landOnNestPosLerp.setStartPos(self.suit.getPos())

    
    def updateRetreatToNestPosLerp(self):
        self.retreatToNestPosLerp.setStartPos(self.suit.getPos())

    
    def updateRetreatToSkyPosLerp(self):
        self.startOfRetreatToSkyPos = self.suit.getPos(render)

    
    def updatePostAttackPosLerp(self):
        suitPos = self.suit.getPos(render)
        finalPos = suitPos + Vec3(0, -(Globals.LegalEagle.PostAttackLength), 0)
        self.postAttackPosLerp.setStartPos(suitPos)
        self.postAttackPosLerp.setEndPos(finalPos)

    
    def handleEnterSphere(self, collEntry):
        self.notify.debug('handleEnterSphere:%i' % self.index)
        messenger.send(CogdoFlyingLegalEagle.EnterLegalEagle, [
            self,
            collEntry])

    
    def handleEnterInterest(self):
        self.notify.debug('handleEnterInterestColl:%i' % self.index)
        self.isEagleInterested = True
        messenger.send(CogdoFlyingLegalEagle.RequestAddTargetEventName, [
            self.index])

    
    def handleAgainInterest(self):
        self.isEagleInterested = True
        messenger.send(CogdoFlyingLegalEagle.RequestAddTargetAgainEventName, [
            self.index])

    
    def handleExitInterest(self):
        self.notify.debug('handleExitInterestSphere:%i' % self.index)
        self.isEagleInterested = False
        messenger.send(CogdoFlyingLegalEagle.RequestRemoveTargetEventName, [
            self.index])

    
    def hasTarget(self):
        if self.target != None:
            return True
        else:
            return False

    
    def setTarget(self, toon, elapsedTime = 0.0):
        self.notify.debug('Setting eagle %i to target: %s, elapsed time: %s' % (self.index, toon.getName(), elapsedTime))
        self.target = toon
        if self.state == 'Roost':
            self.request('next', elapsedTime)
        
        if self.state == 'ChargeUpAttack':
            messenger.send(CogdoFlyingLegalEagle.ChargingToAttackEventName, [
                self.target.doId])
        

    
    def clearTarget(self, elapsedTime = 0.0):
        self.notify.debug('Clearing target from eagle %i, elapsed time: %s' % (self.index, elapsedTime))
        messenger.send(CogdoFlyingLegalEagle.CooldownEventName, [
            self.target.doId])
        self.target = None
        if self.state in [
            'LockOnToon']:
            self.request('next', elapsedTime)
        

    
    def leaveCooldown(self, elapsedTime = 0.0):
        if self.state in [
            'Cooldown']:
            self.request('next', elapsedTime)
        

    
    def shouldBeInFrame(self):
        if self.state in [
            'TakeOff',
            'LockOnToon',
            'ChargeUpAttack']:
            return True
        elif self.state == 'Attack':
            distance = self.suit.getDistance(self.target)
            threshold = Globals.LegalEagle.EagleAndTargetDistCameraTrackThreshold
            suitPos = self.suit.getPos(render)
            targetPos = self.target.getPos(render)
            if distance > threshold and suitPos[1] > targetPos[1]:
                return True
            
        
        return False

    
    def getTarget(self):
        return self.target

    
    def onstage(self):
        self.suit.unstash()
        self.request('Roost')

    
    def offstage(self):
        self.suit.stash()
        self.request('Off')

    
    def gameStart(self, gameStartTime):
        self.gameStartTime = gameStartTime
        self.initCollision()

    
    def gameEnd(self):
        self.shutdownCollisions()

    
    def shutdownCollisions(self):
        self.ignoreAll()
        if self.collSphere != None:
            del self.collSphere
            self.collSphere = None
        
        if self.collNodePath != None:
            self.collNodePath.removeNode()
            del self.collNodePath
            self.collNodePath = None
        
        if self.collNode != None:
            del self.collNode
            self.collNode = None
        

    
    def destroy(self):
        self.request('Off')
        self.detachPropeller()
        del self._screamSfx
        self.suit.cleanup()
        self.suit.removeNode()
        self.suit.delete()
        self.interestConeOrigin.removeNode()
        del self.interestConeOrigin
        self.nest = None
        self.target = None
        taskMgr.remove('updateLockOnTask-%i' % self.index)
        taskMgr.remove('exitLockOnToon-%i' % self.index)
        self.propTrack.clearToInitial()
        del self.propTrack
        del self.chargeUpMotionPath
        del self.retreatToSkyMotionPath
        self.takeOffSeq.clearToInitial()
        del self.takeOffSeq
        del self.landOnNestPosLerp
        self.landingSeq.clearToInitial()
        del self.landingSeq
        del self.chargeUpPosLerp
        self.chargeUpAttackSeq.clearToInitial()
        del self.chargeUpAttackSeq
        del self.retreatToNestPosLerp
        self.retreatToNestSeq.clearToInitial()
        del self.retreatToNestSeq
        del self.retreatToSkyPosLerp
        self.retreatToSkySeq.clearToInitial()
        del self.retreatToSkySeq
        del self.postAttackPosLerp
        self.attackSeq.clearToInitial()
        del self.attackSeq
        self.cooldownSeq.clearToInitial()
        del self.cooldownSeq
        self.hoverOverNestSeq.clearToInitial()
        del self.hoverOverNestSeq
        del self.preAttackLerpXY
        del self.preAttackLerpZ

    
    def requestNext(self):
        self.request('next')

    
    def setCollSphereToNest(self):
        if hasattr(self, 'collSphere') and self.collSphere is not None:
            radius = Globals.LegalEagle.OnNestDamageSphereRadius
            self.collSphere.setCenter(Point3(0.0, -Globals.Level.LaffPowerupNestOffset[1], self.suit.getHeight() / 2.0))
            self.collSphere.setRadius(radius)
        

    
    def setCollSphereToTargeting(self):
        if hasattr(self, 'collSphere') and self.collSphere is not None:
            radius = Globals.LegalEagle.DamageSphereRadius
            self.collSphere.setCenter(Point3(0, 0, radius * 2))
            self.collSphere.setRadius(radius)
        

    
    def enterRoost(self):
        self.notify.info("enter%s: '%s' -> '%s'" % (self.newState, self.oldState, self.newState))
        self.hoverOverNestSeq.loop()
        self.propTrack.loop()
        self.setCollSphereToNest()

    
    def filterRoost(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            return 'TakeOff'
        else:
            return self.defaultFilter(request, args)

    
    def exitRoost(self):
        self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
        self.hoverOverNestSeq.pause()
        self.setCollSphereToTargeting()

    
    def enterTakeOff(self, elapsedTime = 0.0):
        self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime))
        self.takeOffSeq.start(elapsedTime)
        self.hoverOverNestSeq.loop()

    
    def filterTakeOff(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            if self.hasTarget():
                return 'LockOnToon'
            else:
                return 'LandOnNest'
        else:
            return self.defaultFilter(request, args)

    
    def exitTakeOff(self):
        self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
        self.takeOffSeq.clearToInitial()
        self.hoverOverNestSeq.pause()

    
    def enterLockOnToon(self, elapsedTime = 0.0):
        self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime))
        taskName = 'updateLockOnTask-%i' % self.index
        taskMgr.add(self.updateLockOnTask, taskName, 45, extraArgs = [])
        messenger.send(CogdoFlyingLegalEagle.LockOnToonEventName, [
            self.target.doId])
        range = self.target.getDistance(self.interestConeOrigin) / self.getInterestConeLength()
        range = clamp(range, 0.0, 1.0)
        dur = Globals.LegalEagle.LockOnTime
        if self.oldState == 'TakeOff':
            dur *= range
        else:
            dur += Globals.LegalEagle.ExtraPostCooldownTime
        taskName = 'exitLockOnToon-%i' % self.index
        taskMgr.doMethodLater(dur, self.requestNext, taskName, extraArgs = [])

    
    def filterLockOnToon(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            if self.hasTarget():
                return 'ChargeUpAttack'
            else:
                return 'RetreatToNest'
        else:
            return self.defaultFilter(request, args)

    
    def exitLockOnToon(self):
        self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
        taskMgr.remove('updateLockOnTask-%i' % self.index)
        taskMgr.remove('exitLockOnToon-%i' % self.index)

    
    def enterChargeUpAttack(self, elapsedTime = 0.0):
        self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime))
        self.chargeUpAttackSeq.start(elapsedTime)
        messenger.send(CogdoFlyingLegalEagle.ChargingToAttackEventName, [
            self.target.doId])

    
    def filterChargeUpAttack(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            if self.hasTarget():
                return 'Attack'
            else:
                return 'RetreatToNest'
        else:
            return self.defaultFilter(request, args)

    
    def exitChargeUpAttack(self):
        self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
        self.chargeUpAttackSeq.clearToInitial()

    
    def enterAttack(self, elapsedTime = 0.0):
        self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime))
        self.attackTargetPos = self.target.getPos(render)
        targetState = self.target.animFSM.getCurrentState().getName()
        self._screamSfx.play()
        if targetState == 'jumpAirborne':
            self.attackTargetPos[2] += Globals.LegalEagle.VerticalOffset
        else:
            self.attackTargetPos[2] += Globals.LegalEagle.PlatformVerticalOffset
        self.readyToAttackPos = self.suit.getPos(render)
        self.attackSeq.start(elapsedTime)

    
    def filterAttack(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            return 'RetreatToSky'
        else:
            return self.defaultFilter(request, args)

    
    def exitAttack(self):
        self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
        self.attackSeq.clearToInitial()
        taskMgr.remove('updateAttackPosTask-%i' % self.index)

    
    def enterRetreatToSky(self, elapsedTime = 0.0):
        self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime))
        self.retreatToSkySeq.start(elapsedTime)

    
    def filterRetreatToSky(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            return 'Cooldown'
        else:
            return self.defaultFilter(request, args)

    
    def exitRetreatToSky(self):
        self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
        self.retreatToSkySeq.clearToInitial()

    
    def enterCooldown(self):
        if self.target != None:
            messenger.send(CogdoFlyingLegalEagle.CooldownEventName, [
                self.target.doId])
        
        self.suit.stash()
        self.notify.info("enter%s: '%s' -> '%s'" % (self.newState, self.oldState, self.newState))

    
    def filterCooldown(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            if self.hasTarget():
                return 'LockOnToon'
            else:
                return 'LandOnNest'
        else:
            return self.defaultFilter(request, args)

    
    def exitCooldown(self):
        self.notify.debug("exit%s: '%s' -> '%s'" % (self.oldState, self.oldState, self.newState))
        self.suit.unstash()
        self.cooldownSeq.clearToInitial()
        if self.newState != 'Off':
            heightOffNest = Globals.LegalEagle.PostCooldownHeightOffNest
            nestPos = self.nest.getPos(render)
            if self.newState in [
                'LandOnNest']:
                self.suit.setPos(nestPos + Vec3(0, 0, heightOffNest))
            else:
                targetPos = self.target.getPos(render)
                attackPos = Vec3(targetPos)
                attackPos[1] = nestPos[1]
                attackPos[2] = nestPos[2] + heightOffNest
                self.suit.setPos(attackPos)
        

    
    def enterRetreatToNest(self, elapsedTime = 0.0):
        self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime))
        self.retreatToNestSeq.start(elapsedTime)

    
    def filterRetreatToNest(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            return 'LandOnNest'
        else:
            return self.defaultFilter(request, args)

    
    def exitRetreatToNest(self):
        self.retreatToNestSeq.clearToInitial()

    
    def enterLandOnNest(self, elapsedTime = 0.0):
        self.notify.info("enter%s: '%s' -> '%s', elapsedTime:%s" % (self.newState, self.oldState, self.newState, elapsedTime))
        self.landingSeq.start(elapsedTime)

    
    def filterLandOnNest(self, request, args):
        self.notify.debug("filter%s( '%s', '%s' )" % (self.state, request, args))
        if request == self.state:
            return None
        elif request == 'next':
            if self.hasTarget():
                return 'TakeOff'
            else:
                return 'Roost'
        else:
            return self.defaultFilter(request, args)

    
    def exitLandOnNest(self):
        self.landingSeq.clearToInitial()
示例#48
0
class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.debug = True
        self.statusLabel = self.makeStatusLabel(0)
        self.collisionLabel = self.makeStatusLabel(1)

        self.world = self.loader.loadModel("world.bam")
        self.world.reparentTo(self.render)

        self.maxspeed = 100.0
        # Avion à la pointe des chateaux, direction Ouest !
        self.startPos = Vec3(1200, 320, 85)
        #print (self.startPos)
        self.startHpr = Vec3(0, 0, 0)
        #self.player.setPos(1200,320,85)
        #self.player.setH(0)
        self.player = self.loader.loadModel("alliedflanker.egg")
        #self.player.setPos(640,640,85)
        self.player.setScale(0.2, 0.2, 0.2)
        self.player.reparentTo(self.render)
        self.resetPlayer()

        # load the explosion ring
        self.explosionModel = loader.loadModel('explosion')
        self.explosionModel.reparentTo(self.render)
        self.explosionModel.setScale(0.0)
        self.explosionModel.setLightOff()
        # only one explosion at a time:
        self.exploding = False

        # performance (to be masked later by fog) and view:
        self.maxdistance = 1200
        self.camLens.setFar(self.maxdistance)
        self.camLens.setFov(60)

        self.taskMgr.add(self.updateTask, "update")
        self.keyboardSetup()

        # relevant for world boundaries
        self.worldsize = 1024

        self.createEnvironment()

        self.setupCollisions()
        self.textCounter = 0

    def resetPlayer(self):
        self.player.show()
        #self.player.setPos(self.world,self.startPos)
        #self.player.setHpr(self.world,self.startHpr)
        self.player.setPos(self.startPos)
        self.player.setHpr(self.startHpr)
        self.speed = 10.0
        #self.speed = self.maxspeed/2

        #print (self.player.getPos())

    def makeStatusLabel(self, i):
        return OnscreenText(style=2, fg=(.5,1,.5,1), pos=(-1.3,0.92-(.08 * i)), \
  align=TextNode.ALeft, scale = .08, mayChange = 1)

    def updateTask(self, task):
        self.updatePlayer()
        self.updateCamera()

        self.collTrav.traverse(self.render)
        for i in range(self.playerGroundHandler.getNumEntries()):
            entry = self.playerGroundHandler.getEntry(i)
            if (self.debug == True):
                self.collisionLabel.setText("DEAD:" +
                                            str(globalClock.getFrameTime()))
            if (self.exploding == False):
                self.player.setZ(
                    entry.getSurfacePoint(self.render).getZ() + 10)
                self.explosionSequence()
            # we will later deal with 'what to do' when the player dies

        return task.cont

    def keyboardSetup(self):
        self.keyMap = {"left":0, "right":0, "climb":0, "fall":0, \
            "accelerate":0, "decelerate":0, "fire":0}

        self.accept("escape", sys.exit)

        ## Gestion Vitesse
        self.accept("a", self.setKey, ["accelerate", 1])
        self.accept("a-up", self.setKey, ["accelerate", 0])

        self.accept("q", self.setKey, ["decelerate", 1])
        self.accept("q-up", self.setKey, ["decelerate", 0])

        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 0])

        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_right-up", self.setKey, ["right", 0])

        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 0])

        self.accept("arrow_down", self.setKey, ["climb", 1])
        self.accept("arrow_down-up", self.setKey, ["climb", 0])

        self.accept("arrow_up", self.setKey, ["fall", 1])
        self.accept("arrow_up-up", self.setKey, ["fall", 0])

        # self.accept(“space”, self.setKey, [“fire”,1])
        # self.accept(“space-up”, self.setKey, [“fire”,0])
        base.disableMouse()  # or updateCamera will fail!

    def setKey(self, key, value):
        self.keyMap[key] = value

    def updateCamera(self):
        # see issue content for how we calculated these:
        self.camera.setPos(self.player, 25.6225, 3.8807, 10.2779)
        #self.camera.setPos(0, 0, 90)
        self.camera.setHpr(self.player, 94.8996, -16.6549, 1.55508)

    def updatePlayer(self):
        # Global Clock
        # by default, panda runs as fast as it can frame to frame
        scalefactor = (globalClock.getDt() * self.speed)
        #climbfactor = scalefactor * 0.5
        #bankfactor = scalefactor
        #speedfactor = scalefactor * 2.9
        climbfactor = scalefactor * 0.5 * 2
        bankfactor = scalefactor * 2.0
        speedfactor = scalefactor * 2.9

        # throttle control
        if (self.keyMap["accelerate"] != 0):
            self.speed += 1
            if (self.speed > self.maxspeed):
                self.speed = self.maxspeed

        elif (self.keyMap["decelerate"] != 0):
            self.speed -= 1
            if (self.speed < 0.0):
                self.speed = 0.0

        # Left and Right
        if (self.keyMap["left"] != 0 and self.speed > 0.0):
            self.player.setH(self.player.getH() + bankfactor)
            self.player.setP(self.player.getP() + bankfactor)
            if (self.player.getP() >= 180):
                self.player.setP(-180)

        elif (self.keyMap["right"] != 0 and self.speed > 0.0):
            self.player.setH(self.player.getH() - bankfactor)
            self.player.setP(self.player.getP() - bankfactor)
            if (self.player.getP() <= -180):
                self.player.setP(180)

        elif (self.player.getP() > 0):  # autoreturn from right
            self.player.setP(self.player.getP() - (bankfactor + 0.1))
            if (self.player.getP() < 0): self.player.setP(0)

        elif (self.player.getP() < 0):  # autoreturn from left
            self.player.setP(self.player.getP() + (bankfactor + 0.1))
            if (self.player.getP() > 0):
                self.player.setP(0)

        # Climb and Fall
        if (self.keyMap["climb"] != 0 and self.speed > 0.00):
            # faster you go, quicker you climb
            self.player.setZ(self.player.getZ() + climbfactor)
            self.player.setR(self.player.getR() + climbfactor)
            if (self.player.getR() >= 180):
                self.player.setR(-180)

        elif (self.keyMap["fall"] != 0 and self.speed > 0.00):
            self.player.setZ(self.player.getZ() - climbfactor)
            self.player.setR(self.player.getR() - climbfactor)
            if (self.player.getR() <= -180):
                self.player.setR(180)

        elif (self.player.getR() > 0):  # autoreturn from up
            self.player.setR(self.player.getR() - (climbfactor + 0.1))
            if (self.player.getR() < 0):
                self.player.setR(0)
        # avoid jitter
        elif (self.player.getR() < 0):  # autoreturn from down
            self.player.setR(self.player.getR() + (climbfactor + 0.1))
            if (self.player.getR() > 0):
                self.player.setR(0)

        # move forwards - our X/Y is inverted, see the issue
        if self.exploding == False:
            self.player.setX(self.player, -speedfactor)
            self.applyBoundaries()

    def createEnvironment(self):
        # Fog to hide a performance tweak:
        colour = (0.0, 0.0, 0.0)
        expfog = Fog("scene-wide-fog")
        expfog.setColor(*colour)
        expfog.setExpDensity(0.001)  # original : 0.004
        render.setFog(expfog)
        base.setBackgroundColor(*colour)

        # Our sky
        skydome = loader.loadModel('sky.egg')
        skydome.setEffect(CompassEffect.make(self.render))
        skydome.setScale(self.maxdistance / 2)  # bit less than "far"
        skydome.setZ(-65)  # sink it
        # NOT render - you'll fly through the sky!:
        skydome.reparentTo(self.camera)

        # Our lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.6, .6, .6, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(0, -10, -10))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def setupCollisions(self):
        self.collTrav = CollisionTraverser()

        self.playerGroundSphere = CollisionSphere(0, 1.5, -1.5, 1.5)
        self.playerGroundCol = CollisionNode('playerSphere')
        self.playerGroundCol.addSolid(self.playerGroundSphere)

        # bitmasks
        self.playerGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.playerGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.world.setCollideMask(BitMask32.bit(0))

        # and done
        self.playerGroundColNp = self.player.attachNewNode(
            self.playerGroundCol)
        self.playerGroundHandler = CollisionHandlerQueue()
        self.collTrav.addCollider(self.playerGroundColNp,
                                  self.playerGroundHandler)

        # DEBUG
        if (self.debug == True):
            self.playerGroundColNp.show()
            self.collTrav.showCollisions(self.render)

    def applyBoundaries(self):
        if (self.player.getZ() > self.maxdistance):
            self.player.setZ(self.maxdistance)
        # should never happen once we add collision, but in case:
        elif (self.player.getZ() < 0):
            self.player.setZ(0)

        # and now the X/Y world boundaries:
        boundary = False
        if (self.player.getX() < 0):
            self.player.setX(0)
            boundary = True
        elif (self.player.getX() > self.worldsize):
            self.player.setX(self.worldsize)
            boundary = True
        if (self.player.getY() < 0):
            self.player.setY(0)
            boundary = True
        elif (self.player.getY() > self.worldsize):
            self.player.setY(self.worldsize)
            boundary = True

        # lets not be doing this every frame...
        if boundary == True and self.textCounter > 30:
            self.statusLabel.setText("STATUS: MAP END; TURN AROUND")
        elif self.textCounter > 30:
            self.statusLabel.setText("STATUS: OK")

        if self.textCounter > 30:
            self.textCounter = 0
        else:
            self.textCounter = self.textCounter + 1

    def explosionSequence(self):
        self.exploding = True
        self.explosionModel.setPosHpr( Vec3(self.player.getX(),self.player.getY(), \
                               self.player.getZ()), Vec3( self.player.getH(),0,0))
        self.player.hide()
        taskMgr.add(self.expandExplosion, 'expandExplosion')

    def expandExplosion(self, Task):
        # expand the explosion rign each frame until a certain size
        if self.explosionModel.getScale() < VBase3(60.0, 60.0, 60.0):
            factor = globalClock.getDt()
            scale = self.explosionModel.getScale()
            scale = scale + VBase3(factor * 40, factor * 40, factor * 40)
            self.explosionModel.setScale(scale)
            return Task.cont
        else:
            self.explosionModel.setScale(0)
            self.exploding = False
            self.resetPlayer()
示例#49
0
class IceTreasure(DirectObject):
    """
    Treasures toons can pickup swinging from ice to ice.  Based on MazeTreasure
    """

    notify = DirectNotifyGlobal.directNotify.newCategory("IceTreasure")

    RADIUS = 1.0

    def __init__(self, model, pos, serialNum, gameId, penalty=False):
        # there are going to be MANY (~650) of these created and destroyed
        # all at once for 4-player games; make it lean
        self.serialNum = serialNum

        self.penalty = penalty

        # the fruit has a bit of height, lets recenter
        center = model.getBounds().getCenter()
        center = Point3(0, 0, 0)
        self.nodePath = model.copyTo(render)
        self.nodePath.setPos(pos[0] - center[0], pos[1] - center[1],
                             pos[2] - center[2])
        self.nodePath.setZ(0)  # real assets have bottom at zero
        self.notify.debug('newPos = %s' % self.nodePath.getPos())
        #self.nodePath.setScale(1.0)

        #if self.penalty:
        #    self.nodePath.setColorScale(0.5,0.5,0.5,1.0)

        # Make a sphere, name it uniquely, and child it
        # to the nodepath.
        if self.penalty:
            self.sphereName = "penaltySphere-%s-%s" % (gameId, self.serialNum)
        else:
            self.sphereName = "treasureSphere-%s-%s" % (gameId, self.serialNum)
        self.collSphere = CollisionSphere(center[0], center[1], center[2],
                                          self.RADIUS)
        # Make the sphere intangible
        self.collSphere.setTangible(0)
        self.collNode = CollisionNode(self.sphereName)
        self.collNode.setIntoCollideMask(ToontownGlobals.PieBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = render.attachNewNode(self.collNode)
        self.collNodePath.setPos(pos[0] - center[0], pos[1] - center[1],
                                 pos[2] - center[2])
        self.collNodePath.hide()
        self.track = None

        # Add a hook looking for collisions with localToon
        #self.accept('enter' + self.sphereName, self.__handleEnterSphere)

        # now that the treasure and sphere have been placed, flatten the
        # whole silly thing
        # self.nodePath.flattenLight()

        if self.penalty:
            #self.nodePath.setScale(1,1,0.5)
            self.tip = self.nodePath.find('**/fusetip')
            #self.tip.setX(2)
            #self.tip.setY(0.5)
            #self.tip.setZ(1.5)
            sparks = BattleParticles.createParticleEffect(file='icetnt')
            self.sparksEffect = sparks
            sparks.start(self.tip)
            self.penaltyGrabSound = loader.loadSfx(
                "phase_4/audio/sfx/MG_cannon_fire_alt.mp3")
            self.penaltyGrabSound.setVolume(0.75)
            kaboomAttachPoint = self.nodePath.attachNewNode('kaboomAttach')
            kaboomAttachPoint.setZ(3)
            self.kaboom = loader.loadModel(
                'phase_4/models/minigames/ice_game_kaboom')
            self.kaboom.reparentTo(kaboomAttachPoint)
            #self.kaboom.hide()
            self.kaboom.setScale(2.0)
            self.kaboom.setBillboardPointEye()
            #self.kaboom.setBin('fixed', serialNum)
            #self.kaboom.setDepthTest(False)
            #self.kaboom.setDepthWrite(False)

    def destroy(self):
        self.ignoreAll()
        if self.penalty:
            self.sparksEffect.cleanup()
            if self.track:
                self.track.finish()

        self.nodePath.removeNode()
        del self.nodePath
        del self.collSphere
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode

##     def __handleEnterSphere(self, collEntry):
##         self.ignoreAll()
##         # announce that this treasure was grabbed
##         self.notify.debug('treasuerGrabbed')
##         messenger.send("IceTreasureGrabbed", [self.serialNum])

    def showGrab(self):
        self.nodePath.hide()
        self.collNodePath.hide()
        # disable collisions
        self.collNode.setIntoCollideMask(BitMask32(0))
        if self.penalty:
            self.track = Parallel(
                SoundInterval(self.penaltyGrabSound),
                Sequence(
                    Func(self.kaboom.showThrough),
                    LerpScaleInterval(self.kaboom,
                                      duration=0.5,
                                      scale=Point3(10, 10, 10),
                                      blendType='easeOut'),
                    Func(self.kaboom.hide),
                ))
            self.track.start()
class DistributedExperimentBarrel(ExperimentBarrelBase, DistributedNode):
    notify = directNotify.newCategory('DistributedExperimentBarrel')
    BARREL_SCALE = 0.5
    SPHERE_RADIUS = 3.8

    def __init__(self, cr):
        ExperimentBarrelBase.__init__(self)
        DistributedNode.__init__(self, cr)

        self.barrel = None
        self.icon = None
        self.collSphere = None
        self.collNode = None
        self.collNodePath = None
        self.animTrack = None

    def announceGenerate(self):
        DistributedNode.announceGenerate(self)

        self.reparentTo(render)
        self.loadBarrel()
        self.loadIcon()
        self.loadCollisions()

        self.accept(self.uniqueName('enterBarrelSphere'), self.__handleEnterSphere)

    def delete(self):
        if self.barrel:
            self.barrel.removeNode()

        if self.icon:
            self.icon.removeNode()

        if self.animTrack:
            self.animTrack.finish()
            self.animTrack = None

        self.ignore(self.uniqueName('enterBarrelSphere'))

        DistributedNode.delete(self)

    def loadBarrel(self):
        self.barrel = loader.loadModel('phase_4/models/cogHQ/gagTank')
        self.barrel.reparentTo(self)
        self.barrel.setH(self, 180)
        self.barrel.setScale(self.BARREL_SCALE)
        self.barrel.hide()

        dustCloud = DustCloud(fBillboard=0)
        dustCloud.setBillboardAxis(2.0)
        dustCloud.setZ(3)
        dustCloud.setScale(1.2)
        dustCloud.createTrack()
        Sequence(Func(dustCloud.reparentTo, self.barrel),
                 Parallel(dustCloud.track,
                          Func(self.barrel.show)),
                 Func(dustCloud.destroy)).start()

    def loadIcon(self):
        pass # TODO

    def loadCollisions(self):
        self.collSphere = CollisionSphere(0, 0, 0, self.SPHERE_RADIUS)
        self.collSphere.setTangible(0)
        self.collNode = CollisionNode(self.uniqueName('BarrelSphere'))
        self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.barrel.attachNewNode(self.collNode)
        self.collNodePath.hide()

    def __handleEnterSphere(self, collEntry):
        self.requestGrab()

    def requestGrab(self):
        self.sendUpdate('requestGrab', [base.localAvatar.doId])

    def setGrab(self, avId):
        if avId == base.localAvatar.doId:
            self.ignore(self.uniqueName('enterBarrelSphere'))
            self.barrel.setColorScale(0.5, 0.5, 0.5, 1)
        if self.animTrack:
            self.animTrack.finish()
            self.animTrack = None
        self.animTrack = Sequence(LerpScaleInterval(self.barrel,
                                                    0.2, 1.1 * self.BARREL_SCALE,
                                                    blendType='easeInOut'),
                                  LerpScaleInterval(self.barrel,
                                                    0.2,
                                                    self.BARREL_SCALE,
                                                    blendType='easeInOut'),
                                  Func(self.barrel.setScale,
                                       self.BARREL_SCALE))
        self.animTrack.start()
示例#51
0
class thirdPerson(DirectObject):
    def __init__(self, parserClass, mainClass, mapLoaderClass,
                 modelLoaderClass):
        self.switchState = False

        #self.t = Timer()

        self.keyMap = {"left": 0, "right": 0, "forward": 0, "backward": 0}
        self.ralph = Actor(
            "data/models/units/ralph/ralph", {
                "run": "data/models/units/ralph/ralph-run",
                "walk": "data/models/units/ralph/ralph-walk"
            })
        self.ralph.reparentTo(render)
        #		self.ralph.setPos(42, 30, 0)
        self.ralph.setPos(6, 10, 0)
        self.ralph.setScale(0.1)

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("arrow_up", self.setKey, ["forward", 1])
        self.accept("arrow_up-up", self.setKey, ["forward", 0])
        self.accept("arrow_down", self.setKey, ["backward", 1])
        self.accept("arrow_down-up", self.setKey, ["backward", 0])

        self.isMoving = False

        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 1000)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)
        #self.ralphGroundCol.show()

        base.cam.reparentTo(self.ralph)
        base.cam.setPos(0, 9, 7)
        self.floater2 = NodePath(PandaNode("floater2"))
        self.floater2.reparentTo(self.ralph)
        self.floater2.setZ(self.floater2.getZ() + 6)
        base.cam.lookAt(self.floater2)

        # Uncomment this line to see the collision rays
        #		self.ralphGroundColNp.show()
        #		self.camGroundColNp.show()

        #Uncomment this line to show a visual representation of the
        #collisions occuring
        #		self.cTrav.showCollisions(render)

        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        taskMgr.add(self.move,
                    "movingTask",
                    extraArgs=[
                        mainClass, parserClass, mapLoaderClass,
                        modelLoaderClass
                    ])

    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value

    def move(self, mainClass, parserClass, mapLoaderClass, modelLoaderClass):
        # Get the time elapsed since last frame. We need this
        # for framerate-independent movement.
        elapsed = globalClock.getDt()

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.

        if (self.keyMap["left"] != 0):
            self.ralph.setH(self.ralph.getH() + elapsed * 300)
        if (self.keyMap["right"] != 0):
            self.ralph.setH(self.ralph.getH() - elapsed * 300)
        if (self.keyMap["forward"] != 0):
            self.ralph.setY(self.ralph, -(elapsed * 50))  #25))
        if (self.keyMap["backward"] != 0):
            self.ralph.setY(self.ralph, +(elapsed * 20))

        if (self.keyMap["forward"] != 0) or (self.keyMap["left"] !=
                                             0) or (self.keyMap["right"] != 0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True

        elif (self.keyMap["backward"] != 0):
            if self.isMoving is False:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk", 5)
                self.isMoving = False

        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(
            y.getSurfacePoint(render).getZ(),
            x.getSurfacePoint(render).getZ()))

        if (len(entries) > 0) and (entries[0].getIntoNode().getName()[0:4]
                                   == "tile"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())

        elif (len(entries) > 0) and (entries[0].getIntoNode().getName()[0:5]
                                     == "solid"):
            self.ralph.setPos(startpos)
            x = int(entries[0].getIntoNode().getName()
                    [len(entries[0].getIntoNode().getName()) -
                     6:len(entries[0].getIntoNode().getName()) - 4])
            y = int(entries[0].getIntoNode().getName()
                    [len(entries[0].getIntoNode().getName()) - 2:])
            if (mapLoaderClass.tileArray[y][x].drillTime != None):
                mainClass.changeTile(mapLoaderClass.tileArray[y][x], 0,
                                     parserClass, modelLoaderClass,
                                     mapLoaderClass)
        else:
            self.ralph.setPos(startpos)

        self.ralph.setP(0)
        return Task.cont
示例#52
0
class MazeSuit(DirectObject):
    COLL_SPHERE_NAME = 'MazeSuitSphere'
    COLLISION_EVENT_NAME = 'MazeSuitCollision'
    MOVE_IVAL_NAME = 'moveMazeSuit'
    DIR_UP = 0
    DIR_DOWN = 1
    DIR_LEFT = 2
    DIR_RIGHT = 3
    oppositeDirections = [DIR_DOWN, DIR_UP, DIR_RIGHT, DIR_LEFT]
    directionHs = [0, 180, 90, 270]
    DEFAULT_SPEED = 4.0
    SUIT_Z = 0.1

    def __init__(
            self,
            serialNum,
            maze,
            randomNumGen,
            cellWalkPeriod,
            difficulty,
            suitDnaName='f',
            startTile=None,
            ticFreq=MazeGameGlobals.SUIT_TIC_FREQ,
            walkSameDirectionProb=MazeGameGlobals.WALK_SAME_DIRECTION_PROB,
            walkTurnAroundProb=MazeGameGlobals.WALK_TURN_AROUND_PROB,
            uniqueRandomNumGen=True,
            walkAnimName=None):
        self.serialNum = serialNum
        self.maze = maze
        if uniqueRandomNumGen:
            self.rng = RandomNumGen(randomNumGen)
        else:
            self.rng = randomNumGen
        self.difficulty = difficulty
        self._walkSameDirectionProb = walkSameDirectionProb
        self._walkTurnAroundProb = walkTurnAroundProb
        self._walkAnimName = walkAnimName or 'walk'
        self.suit = Suit.Suit()
        d = SuitDNA.SuitDNA()
        d.newSuit(suitDnaName)
        self.suit.setDNA(d)
        self.suit.nametag3d.stash()
        self.suit.nametag.destroy()
        if startTile is None:
            defaultStartPos = MazeGameGlobals.SUIT_START_POSITIONS[
                self.serialNum]
            self.startTile = (defaultStartPos[0] * self.maze.width,
                              defaultStartPos[1] * self.maze.height)
        else:
            self.startTile = startTile
        self.ticFreq = ticFreq
        self.ticPeriod = int(cellWalkPeriod)
        self.cellWalkDuration = float(self.ticPeriod) / float(self.ticFreq)
        self.turnDuration = 0.6 * self.cellWalkDuration
        return

    def destroy(self):
        self.suit.delete()

    def uniqueName(self, str):
        return str + ` (self.serialNum) `

    def gameStart(self, gameStartTime):
        self.gameStartTime = gameStartTime
        self.initCollisions()
        self.startWalkAnim()
        self.occupiedTiles = [(self.nextTX, self.nextTY)]
        n = 20
        self.nextThinkTic = self.serialNum * self.ticFreq / n
        self.fromPos = Point3(0, 0, 0)
        self.toPos = Point3(0, 0, 0)
        self.fromHpr = Point3(0, 0, 0)
        self.toHpr = Point3(0, 0, 0)
        self.moveIval = WaitInterval(1.0)

    def gameEnd(self):
        self.moveIval.pause()
        del self.moveIval
        self.shutdownCollisions()
        self.suit.loop('neutral')

    def initCollisions(self):
        self.collSphere = CollisionSphere(0, 0, 0, 2.0)
        self.collSphere.setTangible(0)
        self.collNode = CollisionNode(self.uniqueName(self.COLL_SPHERE_NAME))
        self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.suit.attachNewNode(self.collNode)
        self.collNodePath.hide()
        self.accept(self.uniqueName('enter' + self.COLL_SPHERE_NAME),
                    self.handleEnterSphere)

    def shutdownCollisions(self):
        self.ignore(self.uniqueName('enter' + self.COLL_SPHERE_NAME))
        del self.collSphere
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode

    def handleEnterSphere(self, collEntry):
        messenger.send(self.COLLISION_EVENT_NAME, [self.serialNum])

    def __getWorldPos(self, sTX, sTY):
        wx, wy = self.maze.tile2world(sTX, sTY)
        return Point3(wx, wy, self.SUIT_Z)

    def onstage(self):
        sTX = int(self.startTile[0])
        sTY = int(self.startTile[1])
        c = 0
        lim = 0
        toggle = 0
        direction = 0
        while not self.maze.isWalkable(sTX, sTY):
            if 0 == direction:
                sTX -= 1
            elif 1 == direction:
                sTY -= 1
            elif 2 == direction:
                sTX += 1
            elif 3 == direction:
                sTY += 1
            c += 1
            if c > lim:
                c = 0
                direction = (direction + 1) % 4
                toggle += 1
                if not toggle & 1:
                    lim += 1

        self.TX = sTX
        self.TY = sTY
        self.direction = self.DIR_DOWN
        self.lastDirection = self.direction
        self.nextTX = self.TX
        self.nextTY = self.TY
        self.suit.setPos(self.__getWorldPos(self.TX, self.TY))
        self.suit.setHpr(self.directionHs[self.direction], 0, 0)
        self.suit.reparentTo(render)
        self.suit.pose(self._walkAnimName, 0)
        self.suit.loop('neutral')

    def offstage(self):
        self.suit.reparentTo(hidden)

    def startWalkAnim(self):
        self.suit.loop(self._walkAnimName)
        speed = float(self.maze.cellWidth) / self.cellWalkDuration
        self.suit.setPlayRate(speed / self.DEFAULT_SPEED, self._walkAnimName)

    def __applyDirection(self, dir, TX, TY):
        if self.DIR_UP == dir:
            TY += 1
        elif self.DIR_DOWN == dir:
            TY -= 1
        elif self.DIR_LEFT == dir:
            TX -= 1
        elif self.DIR_RIGHT == dir:
            TX += 1
        return (TX, TY)

    def __chooseNewWalkDirection(self, unwalkables):
        if not self.rng.randrange(self._walkSameDirectionProb):
            newTX, newTY = self.__applyDirection(self.direction, self.TX,
                                                 self.TY)
            if self.maze.isWalkable(newTX, newTY, unwalkables):
                return self.direction
        if self.difficulty >= 0.5:
            if not self.rng.randrange(self._walkTurnAroundProb):
                oppositeDir = self.oppositeDirections[self.direction]
                newTX, newTY = self.__applyDirection(oppositeDir, self.TX,
                                                     self.TY)
                if self.maze.isWalkable(newTX, newTY, unwalkables):
                    return oppositeDir
        candidateDirs = [
            self.DIR_UP, self.DIR_DOWN, self.DIR_LEFT, self.DIR_RIGHT
        ]
        candidateDirs.remove(self.oppositeDirections[self.direction])
        while len(candidateDirs):
            dir = self.rng.choice(candidateDirs)
            newTX, newTY = self.__applyDirection(dir, self.TX, self.TY)
            if self.maze.isWalkable(newTX, newTY, unwalkables):
                return dir
            candidateDirs.remove(dir)

        return self.oppositeDirections[self.direction]

    def getThinkTimestampTics(self, curTic):
        if curTic < self.nextThinkTic:
            return []
        else:
            r = range(self.nextThinkTic, curTic + 1, self.ticPeriod)
            self.lastTicBeforeRender = r[-1]
            return r

    def prepareToThink(self):
        self.occupiedTiles = [(self.nextTX, self.nextTY)]

    def think(self, curTic, curT, unwalkables):
        self.TX = self.nextTX
        self.TY = self.nextTY
        self.lastDirection = self.direction
        self.direction = self.__chooseNewWalkDirection(unwalkables)
        self.nextTX, self.nextTY = self.__applyDirection(
            self.direction, self.TX, self.TY)
        self.occupiedTiles = [(self.TX, self.TY), (self.nextTX, self.nextTY)]
        if curTic == self.lastTicBeforeRender:
            fromCoords = self.maze.tile2world(self.TX, self.TY)
            toCoords = self.maze.tile2world(self.nextTX, self.nextTY)
            self.fromPos.set(fromCoords[0], fromCoords[1], self.SUIT_Z)
            self.toPos.set(toCoords[0], toCoords[1], self.SUIT_Z)
            self.moveIval = LerpPosInterval(self.suit,
                                            self.cellWalkDuration,
                                            self.toPos,
                                            startPos=self.fromPos,
                                            name=self.uniqueName(
                                                self.MOVE_IVAL_NAME))
            if self.direction != self.lastDirection:
                self.fromH = self.directionHs[self.lastDirection]
                toH = self.directionHs[self.direction]
                if self.fromH == 270 and toH == 0:
                    self.fromH = -90
                elif self.fromH == 0 and toH == 270:
                    self.fromH = 360
                self.fromHpr.set(self.fromH, 0, 0)
                self.toHpr.set(toH, 0, 0)
                turnIval = LerpHprInterval(
                    self.suit,
                    self.turnDuration,
                    self.toHpr,
                    startHpr=self.fromHpr,
                    name=self.uniqueName('turnMazeSuit'))
                self.moveIval = Parallel(self.moveIval,
                                         turnIval,
                                         name=self.uniqueName(
                                             self.MOVE_IVAL_NAME))
            else:
                self.suit.setH(self.directionHs[self.direction])
            moveStartT = float(self.nextThinkTic) / float(self.ticFreq)
            self.moveIval.start(curT - (moveStartT + self.gameStartTime))
        self.nextThinkTic += self.ticPeriod

    @staticmethod
    def thinkSuits(suitList, startTime, ticFreq=MazeGameGlobals.SUIT_TIC_FREQ):
        curT = globalClock.getFrameTime() - startTime
        curTic = int(curT * float(ticFreq))
        suitUpdates = []
        for i in xrange(len(suitList)):
            updateTics = suitList[i].getThinkTimestampTics(curTic)
            suitUpdates.extend(zip(updateTics, [i] * len(updateTics)))

        suitUpdates.sort(lambda a, b: a[0] - b[0])
        if len(suitUpdates) > 0:
            curTic = 0
            for i in xrange(len(suitUpdates)):
                update = suitUpdates[i]
                tic = update[0]
                suitIndex = update[1]
                suit = suitList[suitIndex]
                if tic > curTic:
                    curTic = tic
                    j = i + 1
                    while j < len(suitUpdates):
                        if suitUpdates[j][0] > tic:
                            break
                        suitList[suitUpdates[j][1]].prepareToThink()
                        j += 1

                unwalkables = []
                for si in xrange(suitIndex):
                    unwalkables.extend(suitList[si].occupiedTiles)

                for si in xrange(suitIndex + 1, len(suitList)):
                    unwalkables.extend(suitList[si].occupiedTiles)

                suit.think(curTic, curT, unwalkables)
示例#53
0
class IceTreasure(DirectObject):
    notify = DirectNotifyGlobal.directNotify.newCategory('IceTreasure')
    RADIUS = 1.0

    def __init__(self, model, pos, serialNum, gameId, penalty=False):
        self.serialNum = serialNum
        self.penalty = penalty
        center = model.getBounds().getCenter()
        center = Point3(0, 0, 0)
        self.nodePath = model.copyTo(render)
        self.nodePath.setPos(pos[0] - center[0], pos[1] - center[1],
                             pos[2] - center[2])
        self.nodePath.setZ(0)
        self.notify.debug('newPos = %s' % self.nodePath.getPos())
        if self.penalty:
            self.sphereName = 'penaltySphere-%s-%s' % (gameId, self.serialNum)
        else:
            self.sphereName = 'treasureSphere-%s-%s' % (gameId, self.serialNum)
        self.collSphere = CollisionSphere(center[0], center[1], center[2],
                                          self.RADIUS)
        self.collSphere.setTangible(0)
        self.collNode = CollisionNode(self.sphereName)
        self.collNode.setIntoCollideMask(ToontownGlobals.PieBitmask)
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = render.attachNewNode(self.collNode)
        self.collNodePath.setPos(pos[0] - center[0], pos[1] - center[1],
                                 pos[2] - center[2])
        self.collNodePath.hide()
        self.track = None
        if self.penalty:
            self.tip = self.nodePath.find('**/fusetip')
            sparks = BattleParticles.createParticleEffect(file='icetnt')
            self.sparksEffect = sparks
            sparks.start(self.tip)
            self.penaltyGrabSound = loader.loadSfx(
                'phase_4/audio/sfx/MG_cannon_fire_alt.mp3')
            self.penaltyGrabSound.setVolume(0.75)
            kaboomAttachPoint = self.nodePath.attachNewNode('kaboomAttach')
            kaboomAttachPoint.setZ(3)
            self.kaboom = loader.loadModel(
                'phase_4/models/minigames/ice_game_kaboom')
            self.kaboom.reparentTo(kaboomAttachPoint)
            self.kaboom.setScale(2.0)
            self.kaboom.setBillboardPointEye()

    def destroy(self):
        self.ignoreAll()
        if self.penalty:
            self.sparksEffect.cleanup()
            if self.track:
                self.track.finish()

        self.nodePath.removeNode()
        del self.nodePath
        del self.collSphere
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode

    def showGrab(self):
        self.nodePath.hide()
        self.collNodePath.hide()
        self.collNode.setIntoCollideMask(BitMask32(0))
        if self.penalty:
            self.track = Parallel(
                SoundInterval(self.penaltyGrabSound),
                Sequence(
                    Func(self.kaboom.showThrough),
                    LerpScaleInterval(self.kaboom,
                                      duration=0.5,
                                      scale=Point3(10, 10, 10),
                                      blendType='easeOut'),
                    Func(self.kaboom.hide)))
            self.track.start()
示例#54
0
class DemoGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.debug = False
        self.status_label = self.makeStatusLabel(0)
        self.collision_label = self.makeCollisionLabel(1)

        # terrain = GeoMipTerrain("worldTerrain")
        # terrain.setHeightfield("models/height_map.png")
        # terrain.setColorMap("models/colour_map_flipped.png")
        # terrain.setBruteforce(True)
        # root = terrain.getRoot()
        # root.reparentTo(render)
        # root.setSz(60)
        # terrain.generate()
        # root.writeBamFile("models/world.bam")

        self.world = self.loader.loadModel("models/world.bam")
        self.world.reparentTo(self.render)
        self.world_size = 1024

        self.player = self.loader.loadModel("models/alliedflanker")    # alliedflanker.egg by default
        self.max_speed = 100.0
        self.start_pos = Vec3(200, 200, 65)
        self.start_hpr = Vec3(225, 0, 0)
        self.player.setScale(0.2, 0.2, 0.2)
        self.player.reparentTo(self.render)
        self.resetPlayer()

        self.taskMgr.add(self.updateTask, "update")
        self.keyboardSetup()

        self.max_distance = 400
        if not self.debug:
            self.camLens.setFar(self.max_distance)
        else:
            base.oobe()

        self.camLens.setFov(60)
        self.createEnvironment()
        self.setupCollisions()
        self.text_counter = 0

        # load the explosion ring
        self.explosion_model = loader.loadModel("models/explosion")    # Panda3D Defaults to '.egg'
        self.explosion_model.reparentTo(self.render)
        self.explosion_model.setScale(0.0)
        self.explosion_model.setLightOff()
        # Only one explosion at a time
        self.exploding = False

    def makeStatusLabel(self, i):
        return OnscreenText(style=2, fg=(0.5, 1, 0.5, 1), pos=(-1.3, 0.92, (-0.08 * i)),
                            align=TextNode.ALeft, scale=0.08, mayChange=1)

    def makeCollisionLabel(self, i):
        return OnscreenText(style=2, fg=(0.5, 1, 0.5, 1), pos=(-1.3, 0.92, (-0.08 * i)),
                            align=TextNode.ALeft, scale=0.08, mayChange=1)

    def resetPlayer(self):
        self.player.show()
        self.player.setPos(self.world, self.start_pos)
        self.player.setHpr(self.world, self.start_hpr)
        self.speed = self.max_speed / 2

    def keyboardSetup(self):
        self.keyMap = {"left": 0, "right": 0, "climb": 0, "fall": 0,
                       "accelerate": 0, "decelerate": 0, "fire": 0}
        self.accept("escape", sys.exit)
        self.accept("a", self.setKey, ["accelerate", 1])
        self.accept("a-up", self.setKey, ["accelerate", 0])
        self.accept("z", self.setKey, ["decelerate", 1])
        self.accept("z-up", self.setKey, ["decelerate", 0])
        self.accept("arrow_left", self.setKey, ["left", 1])
        self.accept("arrow_left-up", self.setKey, ["left", 0])
        self.accept("arrow_right", self.setKey, ["right", 1])
        self.accept("arrow_right-up", self.setKey, ["right", 0])
        self.accept("arrow_down", self.setKey, ["climb", 1])
        self.accept("arrow_down-up", self.setKey, ["climb", 0])
        self.accept("arrow_up", self.setKey, ["fall", 1])
        self.accept("arrow_up-up", self.setKey, ["fall", 0])
        self.accept("space", self.setKey, ["fire", 1])
        self.accept("space-up", self.setKey, ["fire", 0])
        base.disableMouse() # or updateCamera will fail!

    def setKey(self, key, value):
        self.keyMap[key] = value

    def updateTask(self, task):
        self.updatePlayer()
        self.updateCamera()

        self.coll_trav.traverse(self.render)
        for i in range(self.player_ground_handler.getNumEntries()):
            entry = self.player_ground_handler.getEntry(i)
            if self.debug:
                self.collision_label.setText("dead:"+str(globalClock.getFrameTime()))
            if not self.exploding:
                self.player.setZ(entry.getSurfacePoint(self.render).getZ() + 10)
                self.explosionSequence()
        return Task.cont

    def explosionSequence(self):
        self.exploding = True
        pos = Vec3(self.player.getX(), self.player.getY(), self.player.getZ())
        hpr = Vec3(self.player.getH(), 0, 0)
        self.explosion_model.setPosHpr(pos, hpr)
        self.player.hide()
        taskMgr.add(self.expandExplosion, "expandExplosion")

    def expandExplosion(self, Task):
        if self.explosion_model.getScale() < VBase3(60.0, 60.0, 60.0):
            factor = globalClock.getDt()
            scale = self.explosion_model.getScale()
            scale += VBase3(factor*40, factor*40, factor*40)
            self.explosion_model.setScale(scale)
            return Task.cont
        else:
            self.explosion_model.setScale(0)
            self.exploding = False
            self.resetPlayer()

    def updatePlayer(self):
        # Global Clock
        # by default, panda runs as fast as it can frame by frame
        scale_factor = (globalClock.getDt()*self.speed)
        climb_factor = scale_factor * 0.5
        bank_factor = scale_factor
        speed_factor = scale_factor * 2.9
        gravity_factor = 2 * (self.max_speed - self.speed) / 100

        # Climb and Fall
        if self.keyMap["climb"] != 0 and self.speed > 0.00:
            # The faster you go, the faster you climb
            self.player.setZ(self.player.getZ() + climb_factor)
            self.player.setR(self.player.getR() + climb_factor)
            # quickest return: avaoids uncoil/unwind
            if (self.player.getR() >= 180):
                self.player.setR(-180)

        elif self.keyMap["fall"] != 0 and self.speed > 0.00:
            self.player.setZ(self.player.getZ() - climb_factor)
            self.player.setR(self.player.getR() - climb_factor)
            # quickest return
            if (self.player.getR() <= -180):
                self.player.setR(180)

        # autoreturn - add a bit regardless to make sure it happens
        elif self.player.getR() > 0:
            self.player.setR(self.player.getR() - (climb_factor + 0.1))
            if self.player.getR() < 0:
                self.player.setR(0)
        elif self.player.getR() < 0:
            self.player.setR(self.player.getR() + (climb_factor + 0.1))
            if self.player.getR() > 0:
                self.player.setR(0)

        # Left and Right
        if self.keyMap["left"] != 0 and self.speed > 0.0:
            self.player.setH(self.player.getH() + bank_factor)
            self.player.setP(self.player.getP() + bank_factor)
            if self.player.getP() >= 180:
                self.player.setP(-180)
        elif self.keyMap["right"] != 0 and self.speed > 0.0:
            self.player.setH(self.player.getH() - bank_factor)
            self.player.setP(self.player.getP() - bank_factor)
            if self.player.getP() <= -180:
                self.player.setP(180)
        elif self.player.getP() > 0:
            self.player.setP(self.player.getP() - (bank_factor + 0.1))
            if self.player.getP() < 0:
                self.player.setP(0)
        elif self.player.getP() < 0:
            self.player.setP(self.player.getP() + (bank_factor + 0.1))
            if self.player.getP() > 0:
                self.player.setP(0)

        # throttle control
        if self.keyMap["accelerate"] != 0:
            self.speed += 1
            if self.speed > self.max_speed:
                self.speed = self.max_speed
        elif self.keyMap["decelerate"] != 0:
            self.speed -= 1
            if self.speed < 0.0:
                self.speed = 0.0

        # move forwards - our X/Y is inverted
        if not self.exploding:
            self.player.setX(self.player, -speed_factor)
            self.applyBoundaries()
            self.player.setZ(self.player, -gravity_factor)

    def applyBoundaries(self):
        # respet max camera distance else you
        # cannot see the floor post loop the loop
        if self.player.getZ() > self.max_distance:
            self.player.setZ(self.max_distance)
        # should never happen once we add collusion, but in case:
        elif self.player.getZ() < 0:
            self.player.setZ(0)

        boundary = False

        # and now the X/Y world boundaries:
        if self.player.getX() < 0:
            self.player.setX(0)
            boundary = True
        elif self.player.getX() > self.world_size:
            self.player.setX(self.world_size)
            boundary = True

        if self.player.getY() < 0:
            self.player.setY(0)
            boundary = True
        elif self.player.getY() > self.world_size:
            self.player.setY(self.world_size)
            boundary = True

        # Avoid doing this every frame
        if boundary and self.text_counter > 30:
            self.status_label.setText("STATUS: MAP END; TURN AROUND")
        elif self.text_counter > 30:
            self.status_label.setText("STATUS: OK")

        if self.text_counter > 30:
            self.text_counter = 0
        else:
            self.text_counter += 1

    def updateCamera(self):
        self.camera.setPos(self.player, 25.6225, 3.8807, 10.2779)
        self.camera.setHpr(self.player, 94.8996, -16.6549, 1.55508)

    def createEnvironment(self):
        # Fog to hide a performance tweak
        exp_fog = Fog("scene-wide-fog")
        exp_fog.setColor(1, 0.8, 0.8)
        exp_fog.setExpDensity(0.002)
        render.setFog(exp_fog)
        # base.setBackgroundColor(*colour)

        # Sky Dome
        '''
        sky_dome = loader.loadModel("models/sky")      # sky_sphere.egg by default
        sky_dome.setEffect(CompassEffect.make(self.render))
        sky_dome.setScale(self.max_distance / 2)
        sky_dome.setZ(-65)  # sink it
        # NOT render - you'll fly through the sky!
        sky_dome.reparentTo(self.camera)
        '''

        # Sky Sphere
        sky_sphere = self.loader.loadModel("models/sky_sphere")
        sky_sphere.setEffect(CompassEffect.make(self.render))
        sky_sphere.setScale(0.08)
        sky_sphere.reparentTo(self.camera)

        # Lighting
        ambient_light = AmbientLight("ambientLight")
        ambient_colour = Vec4(0.6, 0.6, 0.6, 1)
        ambient_light.setColor(ambient_colour)
        self.render.setLight(self.render.attachNewNode(ambient_light))

        directional_light = DirectionalLight("directionalLight")
        # direction = Vec3(0, -10, -10)
        # directional_light.setDirection(direction)
        directional_colour = Vec4(0.8, 0.8, 0.5, 1)
        directional_light.setColor(directional_colour)

        # directional_specular = Vec4(1, 1, 1, 1)
        # directional_light.setSpecularColor(directional_specular)

        dir_light_np = self.render.attachNewNode(directional_light)
        dir_light_np.setPos(0, 0, 260)
        dir_light_np.lookAt(self.player)
        self.render.setLight(dir_light_np)

        # Water
        self.water = self.loader.loadModel("models/square")
        self.water.setSx(self.world_size*2)
        self.water.setSy(self.world_size*2)
        self.water.setPos(self.world_size/2, self.world_size/2, 25)   # z is sea level
        self.water.setTransparency(TransparencyAttrib.MAlpha)
        newTS = TextureStage("1")
        self.water.setTexture(newTS, self.loader.loadTexture("models/water.png"))
        self.water.setTexScale(newTS, 4)
        self.water.reparentTo(self.render)
        LerpTexOffsetInterval(self.water, 200, (1,0), (0,0), textureStage=newTS).loop()

    def setupCollisions(self):
        self.coll_trav = CollisionTraverser()

        self.player_ground_sphere = CollisionSphere(0, 1.5, -1.5, 1.5)
        self.player_ground_col = CollisionNode('playerSphere')
        self.player_ground_col.addSolid(self.player_ground_sphere)

        # bitmasks
        self.player_ground_col.setFromCollideMask(BitMask32.bit(0))
        self.player_ground_col.setIntoCollideMask(BitMask32.allOff())
        self.world.setCollideMask(BitMask32.bit(0))
        self.water.setCollideMask(BitMask32.bit(0))

        # and done
        self.player_ground_col_np = self.player.attachNewNode(self.player_ground_col)
        self.player_ground_handler = CollisionHandlerQueue()
        self.coll_trav.addCollider(self.player_ground_col_np, self.player_ground_handler)

        # DEBUG
        if self.debug:
            self.player_ground_col_np.show()
            self.coll_trav.showCollisions(self.render)
示例#55
0
class cameraCollisionClass:
  def __init__( self ):
    self.collisionCheckSetup()
    
  def collisionCheckSetup( self ):
    print "setting up collision check"
    #No we create a ray to start above the ball and cast down. This is to
    #Determine the height the ball should be at and the angle the floor is
    #tilting. We could have used the sphere around the ball itself, but it
    #would not be as reliable
    self.cameraGroundRay = CollisionRay()     #Create the ray
    self.cameraGroundRay.setOrigin(0,0,0.0)    #Set its origin
    self.cameraGroundRay.setDirection(0,0,-1.0) #And its direction
    #Collision solids go in CollisionNode
    self.cameraGroundCol = CollisionNode('cameraGroundRay') #Create and name the node
    self.cameraGroundCol.addSolid(self.cameraGroundRay) #Add the ray
    self.cameraGroundCol.setFromCollideMask(bitMaskOr([GROUND])) #Set its bitmasks
    self.cameraGroundCol.setIntoCollideMask(bitMaskOr([]))
    #Attach the node to the ballRoot so that the ray is relative to the ball
    #(it will always be 10 feet over the ball and point down)
#    self.cameraGroundColNp = base.camera.attachNewNode(self.cameraGroundCol)
    ### the ground controller is allways looking down NOT ACTIVE
    self.horizontalCameraNode = base.camera.attachNewNode('horizontalCameraNode')
    self.horizontalCameraNode.reparentTo( base.camera )
    self.cameraGroundColNp = self.horizontalCameraNode.attachNewNode(self.cameraGroundCol)
    
    #Uncomment this line to see the ray
    #self.cameraGroundColNp.show()
    '''
    # the camera forward rays look in the direction of the camera
    self.cameraFrontRay = CollisionRay()     #Create the ray
    self.cameraFrontRay.setOrigin   (0,-1,0)    #Set its origin
    self.cameraFrontRay.setDirection(0, 5,0) #And its direction
    self.cameraFrontCol = CollisionNode('cameraFrontRay') #Create and name the node
    self.cameraFrontCol.addSolid(self.cameraFrontRay) #Add the ray
    self.cameraFrontCol.setFromCollideMask(bitMaskOr([WALLS])) #Set its bitmasks
    self.cameraFrontCol.setIntoCollideMask(bitMaskOr([]))
    self.cameraFrontColNp = base.camera.attachNewNode(self.cameraFrontCol)
    #self.cameraFrontColNp.show()
    
    self.cameraBackRay = CollisionRay()     #Create the ray
    self.cameraBackRay.setOrigin   (0, 1,0)    #Set its origin
    self.cameraBackRay.setDirection(0,-5,0) #And its direction
    self.cameraBackCol = CollisionNode('cameraBackRay') #Create and name the node
    self.cameraBackCol.addSolid(self.cameraBackRay) #Add the ray
    self.cameraBackCol.setFromCollideMask(bitMaskOr([WALLS])) #Set its bitmasks
    self.cameraBackCol.setIntoCollideMask(bitMaskOr([]))
    self.cameraBackColNp = base.camera.attachNewNode(self.cameraBackCol)
    #self.cameraBackColNp.show()
    
    # the camera left/right rays
    self.cameraLeftRay = CollisionRay()     #Create the ray
    self.cameraLeftRay.setOrigin   (-1,0,0)    #Set its origin
    self.cameraLeftRay.setDirection( 5,0,0) #And its direction
    self.cameraLeftCol = CollisionNode('cameraLeftRay') #Create and name the node
    self.cameraLeftCol.addSolid(self.cameraLeftRay) #Add the ray
    self.cameraLeftCol.setFromCollideMask(bitMaskOr([WALLS])) #Set its bitmasks
    self.cameraLeftCol.setIntoCollideMask(bitMaskOr([]))
    self.cameraLeftColNp = base.camera.attachNewNode(self.cameraLeftCol)
    #self.cameraLeftColNp.show()
    
    self.cameraRightRay = CollisionRay()     #Create the ray
    self.cameraRightRay.setOrigin   ( 1,0,0)    #Set its origin
    self.cameraRightRay.setDirection(-5,0,0) #And its direction
    self.cameraRightCol = CollisionNode('cameraRightRay') #Create and name the node
    self.cameraRightCol.addSolid(self.cameraRightRay) #Add the ray
    self.cameraRightCol.setFromCollideMask(bitMaskOr([WALLS])) #Set its bitmasks
    self.cameraRightCol.setIntoCollideMask(bitMaskOr([]))
    self.cameraRightColNp = base.camera.attachNewNode(self.cameraRightCol)
    #self.cameraRightColNp.show()
    '''
    
    #Finally, we create a CollisionTraverser. CollisionTraversers are what
    #do the job of calculating collisions
    self.cTrav = CollisionTraverser()
    #Collision traverservs tell collision handlers about collisions, and then
    #the handler decides what to do with the information. We are using a
    #CollisionHandlerQueue, which simply creates a list of all of the
    #collisions in a given pass. There are more sophisticated handlers like
    #one that sends events and another that tries to keep collided objects
    #apart, but the results are often better with a simple queue
    self.cGroundHandler = CollisionHandlerQueue()
    self.cWallHandler = CollisionHandlerQueue()
    #Now we add the collision nodes that can create a collision to the
    #traverser. The traverser will compare these to all others nodes in the
    #scene. There is a limit of 32 CollisionNodes per traverser
    #We add the collider, and the handler to use as a pair
    #self.cTrav.addCollider(self.cameraBallSphere, self.cHandler)
    self.cTrav.addCollider(self.cameraGroundColNp, self.cGroundHandler)
    '''
    self.cTrav.addCollider(self.cameraBackColNp, self.cWallHandler)
    self.cTrav.addCollider(self.cameraFrontColNp, self.cWallHandler)
    self.cTrav.addCollider(self.cameraLeftColNp, self.cWallHandler)
    self.cTrav.addCollider(self.cameraRightColNp, self.cWallHandler)
    '''
    # we dont want this to be automatically executed
    #base.cTrav = self.cTrav
    
    #Collision traversers have a built in tool to help visualize collisions.
    #Uncomment the next line to see it.
    #self.cTrav.showCollisions(render)
    
    #self.cTrav.traverse( render )
    
    # add a task to check for collisions
    taskMgr.add(self.collisionCheckTask, 'collisionCheckTask')
  
  def collisionCheckTask( self, task ):
    # make the parent of the groundCollideHandler be horizontal relative to render
    self.horizontalCameraNode.setHpr( render, Vec3(0,0,0))
    
    self.cTrav.traverse( render )
    
    #The collision handler collects the collisions. We dispatch which function
    #to handle the collision based on the name of what was collided into
    for i in range(self.cGroundHandler.getNumEntries()):
      self.cGroundHandler.sortEntries()
      entry = self.cGroundHandler.getEntry(i)
      object = entry.getIntoNode()
      self.groundCollideHandler(entry)
      # stop after first one
      break
    for i in range(self.cWallHandler.getNumEntries()):
      self.cWallHandler.sortEntries()
      entry = self.cWallHandler.getEntry(i)
      object = entry.getIntoNode()
      self.wallCollideHandler(entry)
      # stop after first one
      break
    return Task.cont
  
  def groundCollideHandler( self, colEntry ):
    # get Z position of collision
    newZ = colEntry.getSurfacePoint(render).getZ()
    # set position node of camera above collision point
    base.camera.setZ(newZ+GROUNDDISTANCE)
  
  def wallCollideHandler( self, colEntry ):
    # get position of collision
    collisionPos = colEntry.getSurfacePoint(render)
    # get position of camera
    cameraPos = base.camera.getPos(render)
    # distance from collisionpoint to camera
    distance = collisionPos - cameraPos
    # length of the distance
    distanceLength = distance.length()
    # if distance to collision point smaller then defined
    if distanceLength < MINDISTANCEWALL:
      # move camera backwand to be at correct distance
      base.camera.setPos( base.camera.getPos() - (distance * (MINDISTANCEWALL - distanceLength)))
示例#56
0
class DistributedPartyTrampolineActivity(DistributedPartyActivity):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        "DistributedPartyTrampolineActivity")

    def __init__(self, cr, doJellyBeans=True, doTricks=False, texture=None):
        DistributedPartyTrampolineActivity.notify.debug("__init__")
        DistributedPartyActivity.__init__(
            self,
            cr,
            PartyGlobals.ActivityIds.PartyTrampoline,
            PartyGlobals.ActivityTypes.GuestInitiated,
            wantLever=False,
            wantRewardGui=True,
        )

        self.doJellyBeans = doJellyBeans
        self.doTricks = doTricks
        self.texture = texture

        self.toon = None
        self.trampHeight = 3.6
        self.trampK = 400.0  # spring constant
        self.normalTrampB = 2.5  # spring damping
        self.leavingTrampB = 8.0  # increase damping to slow toon faster when leaving
        self.trampB = self.normalTrampB
        self.g = -32.0  # acceleration due to gravity
        self.jumpBoost = 330.0
        self.beginningBoost = 500.0
        self.beginningBoostThreshold = self.trampHeight + 1.5
        self.earlyJumpThreshold = 75.0
        self.boingThreshold = 300.0
        self.turnFactor = 120.0
        self.stepDT = 0.001
        self.targetCameraPos = Point3(0.0, 40.0, 10.0)  # relative to toon
        self.cameraSpeed = 2.0
        self.hopOffPos = Point3(16.0, 0.0, 0.0)  # relative to tramp
        self.indicatorFactor = 0.0095
        self.dropShadowCutoff = 15.0
        self.minHeightForText = 15.0
        self.heightTextOffset = -0.065
        self.beanOffset = 0.5
        self.guiBeanOffset = -0.02

        self.jumpTextShown = False
        self.toonJumped = False
        self.turnLeft = False
        self.turnRight = False
        self.leavingTrampoline = False
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.lastPeak = 0.0
        self.beginRoundInterval = None
        self.hopOnAnim = None
        self.hopOffAnim = None
        self.flashTextInterval = None

        # Jelly Beans
        self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans  # These are in PartyGlobals so they can be available to the AI.
        self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus
        self.jellyBeanStartHeight = 20.0
        self.jellyBeanStopHeight = 90.0
        self.jellyBeanColors = [
            VBase4(1.0, 0.5, 0.5, 1.0),
            VBase4(0.5, 1.0, 0.5, 1.0),
            VBase4(0.5, 1.0, 1.0, 1.0),
            VBase4(1.0, 1.0, 0.4, 1.0),
            VBase4(0.4, 0.4, 1.0, 1.0),
            VBase4(1.0, 0.5, 1.0, 1.0),
        ]
        delta = (self.jellyBeanStopHeight -
                 self.jellyBeanStartHeight) / (self.numJellyBeans - 1)
        self.jellyBeanPositions = [
            self.jellyBeanStartHeight + n * delta
            for n in range(self.numJellyBeans)
        ]
        self.doSimulateStep = False

#        import sys
#        sys.path.append( "C:\\pratt\\SchellGames\\perforce\\depot\\Tools\\PandaMisc" )
#        from Reloader import Reloader
#        self.reloader = Reloader( "C:\\cygwin\\home\\pratt\\player_working\\toontown\\src\\parties" )

#---------------------------------------------------
# Loading
#---------------------------------------------------

    def load(self):
        DistributedPartyTrampolineActivity.notify.debug("load")
        DistributedPartyActivity.load(self)

        self.loadModels()
        self.loadCollision()
        self.loadGUI()
        self.loadSounds()
        self.loadIntervals()

        self.activityFSM = TrampolineActivityFSM(self)
        self.activityFSM.request("Idle")

        self.animFSM = TrampolineAnimFSM(self)

        self.setBestHeightInfo("", 0)

    def loadModels(self):
        self.tramp = self.root.attachNewNode(self.uniqueName("tramp"))

        self.screenPlaneElements = NodePath(self.uniqueName("screenPlane"))

        self.trampActor = Actor(
            "phase_13/models/parties/trampoline_model",
            {"emptyAnim": "phase_13/models/parties/trampoline_anim"},
        )
        self.trampActor.reparentTo(self.tramp)

        # Allow reskinning.
        if self.texture:
            reskinNode = self.tramp.find(
                "**/trampoline/__Actor_modelRoot/-GeomNode")
            reskinNode.setTexture(loader.loadTexture(self.texture), 100)

        self.surface = NodePath(self.uniqueName("trampSurface"))
        self.surface.reparentTo(self.tramp)
        self.surface.setZ(self.trampHeight)
        self.trampActor.controlJoint(self.surface, "modelRoot",
                                     "trampoline_joint1")

        self.sign.setPos(PartyGlobals.TrampolineSignOffset)

        self.beans = [
            loader.loadModelCopy("phase_4/models/props/jellybean4")
            for i in range(self.numJellyBeans)
        ]
        for bean in self.beans:
            bean.find("**/jellybean").setP(-35.0)
            bean.setScale(3.0)
            bean.setTransparency(True)
            bean.reparentTo(self.tramp)
            bean.stash()
        self.beans[-1].setScale(8.0)

    def loadCollision(self):
        collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4)
        collTube.setTangible(True)
        self.trampolineCollision = CollisionNode(
            self.uniqueName("TrampolineCollision"))
        self.trampolineCollision.addSolid(collTube)
        self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask
                                                | OTPGlobals.WallBitmask)
        self.trampolineCollisionNP = self.tramp.attachNewNode(
            self.trampolineCollision)

        collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0)
        collSphere.setTangible(False)
        self.trampolineTrigger = CollisionNode(
            self.uniqueName("TrampolineTrigger"))
        self.trampolineTrigger.addSolid(collSphere)
        self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask)
        self.trampolineTriggerNP = self.tramp.attachNewNode(
            self.trampolineTrigger)
        self.accept("enter%s" % self.uniqueName("TrampolineTrigger"),
                    self.onTrampolineTrigger)

    def loadGUI(self):
        self.gui = loader.loadModel("phase_13/models/parties/trampolineGUI")
        self.gui.setX(-1.15)
        self.gui.reparentTo(self.screenPlaneElements)

        self.toonIndicator = self.gui.find("**/trampolineGUI_MovingBar")
        jumpLineLocator = self.gui.find("**/jumpLine_locator")
        guiBean = self.gui.find("**/trampolineGUI_GreenJellyBean")

        self.gui.find("**/trampolineGUI_GreenJellyBean").stash(
        )  # sadly, the white jelly bean is named GreenJellyBean

        self.guiBeans = [
            guiBean.instanceUnderNode(jumpLineLocator,
                                      self.uniqueName("guiBean%d" % i))
            for i in range(self.numJellyBeans)
        ]
        self.guiBeans[-1].setScale(1.5)

        heightTextNode = TextNode(
            self.uniqueName("TrampolineActivity.heightTextNode"))
        heightTextNode.setFont(ToontownGlobals.getSignFont())
        heightTextNode.setAlign(TextNode.ALeft)
        heightTextNode.setText("0.0")
        heightTextNode.setShadow(0.05, 0.05)
        heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0)
        heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0)
        self.heightText = jumpLineLocator.attachNewNode(heightTextNode)
        self.heightText.setX(0.15)
        self.heightText.setScale(0.1)
        self.heightText.setAlphaScale(0.0)

        self.quitEarlyButtonModels = loader.loadModel(
            "phase_3.5/models/gui/inventory_gui")
        quitEarlyUp = self.quitEarlyButtonModels.find("**//InventoryButtonUp")
        quitEarlyDown = self.quitEarlyButtonModels.find(
            "**/InventoryButtonDown")
        quitEarlyRollover = self.quitEarlyButtonModels.find(
            "**/InventoryButtonRollover")
        self.quitEarlyButton = DirectButton(
            parent=self.screenPlaneElements,
            relief=None,
            text=TTLocalizer.PartyTrampolineQuitEarlyButton,
            text_fg=(1, 1, 0.65, 1),
            text_pos=(0, -0.23),
            text_scale=0.7,
            image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover),
            image_color=(1, 0, 0, 1),
            image_scale=(20, 1, 11),
            pos=(1.15, 0, 0.6),
            scale=0.09,
            command=self.leaveTrampoline,
        )
        self.quitEarlyButton.stash()

        self.flashText = OnscreenText(
            text="",
            pos=(0.0, -0.45),
            scale=0.2,
            fg=(1.0, 1.0, 0.65, 1.0),
            align=TextNode.ACenter,
            font=ToontownGlobals.getSignFont(),
            mayChange=True,
        )

        self.timer = PartyUtils.getNewToontownTimer()
        self.timer.reparentTo(self.screenPlaneElements)

    def loadSounds(self):
        self.jellyBeanSound = base.loadSfx("phase_4/audio/sfx/sparkly.mp3")
        self.boingSound = base.loadSfx(
            "phase_4/audio/sfx/target_trampoline_2.mp3")
        self.whistleSound = base.loadSfx(
            "phase_4/audio/sfx/AA_sound_whistle.mp3")

    def loadIntervals(self):
        def prepareHeightText():
            self.heightText.node().setText(
                TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ()))
            self.heightText.setZ(self.indicatorFactor * self.toon.getZ() +
                                 self.heightTextOffset)

        self.heightTextInterval = Sequence(
            Func(prepareHeightText),
            LerpFunc(self.heightText.setAlphaScale,
                     fromData=1.0,
                     toData=0.0,
                     duration=1.0),
        )

    def unload(self):
        DistributedPartyTrampolineActivity.notify.debug("unload")
        if self.hopOnAnim and self.hopOnAnim.isPlaying():
            self.hopOnAnim.finish()
        if self.hopOffAnim and self.hopOffAnim.isPlaying():
            self.hopOffAnim.finish()
        if self.beginRoundInterval and self.beginRoundInterval.isPlaying():
            self.beginRoundInterval.finish()
        if self.flashTextInterval and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        if self.heightTextInterval and self.heightTextInterval.isPlaying():
            self.heightTextInterval.finish()
        self.timer.stop()
        DistributedPartyActivity.unload(self)

        # Unload tasks
        taskMgr.remove(self.uniqueName("TrampolineActivity.updateTask"))
        taskMgr.remove(self.uniqueName("TrampolineActivity.remoteUpdateTask"))

        # Unload events
        self.ignoreAll()

        # Unload intervals
        del self.heightTextInterval
        del self.beginRoundInterval
        del self.hopOnAnim
        del self.hopOffAnim
        del self.flashTextInterval

        if hasattr(self, 'beanAnims'):
            # we need to cleanup the jelly bean interval
            self.cleanupJellyBeans()

        # Unload gui stuff
        self.quitEarlyButton.destroy()
        del self.quitEarlyButton
        if self.screenPlaneElements:
            self.screenPlaneElements.removeNode()
            self.screenPlaneElements = None

        # Unload fsms
        del self.activityFSM
        del self.animFSM

    #---------------------------------------------------
    # Distributed
    #---------------------------------------------------
    def setBestHeightInfo(self, toonName, height):

        if GMUtils.testGMIdentity(toonName):
            toonName = GMUtils.handleGMName(toonName)

        self.bestHeightInfo = (toonName, height)
        DistributedPartyTrampolineActivity.notify.debug(
            "%s has the best height of %d" % (toonName, height))

        if height > 0:
            self.setSignNote(TTLocalizer.PartyTrampolineBestHeight %
                             self.bestHeightInfo)
        else:
            self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet)

    def leaveTrampoline(self):
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp)
            self.leavingTrampoline = True
            self.timer.reset()
            self.trampB = self.leavingTrampB
            self.ignore("control")
            self.quitEarlyButton.stash()

    def requestAnim(self, request):
        self.animFSM.request(request)

    def b_requestAnim(self, request):
        self.requestAnim(request)
        self.sendUpdate("requestAnim", [request])

    def requestAnimEcho(self, request):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.requestAnim(request)

    def removeBeans(self, beansToRemove):
        for i in beansToRemove:
            height, bean, guiBean, beanAnim = self.beanDetails[i]
            guiBean.stash()
            if i in self.beansToCollect:
                self.beansToCollect.remove(i)
            else:
                self.notify.warning(
                    "removeBeans avoided a crash, %d not in self.beansToCollect"
                    % i)
            self.poofBean(bean, beanAnim)
#            bean.stash()
#            beanAnim.finish()

    def b_removeBeans(self, beansToRemove):
        self.removeBeans(beansToRemove)
        self.sendUpdate("removeBeans", [beansToRemove])

    def removeBeansEcho(self, beansToRemove):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.removeBeans(beansToRemove)

    def joinRequestDenied(self, reason):
        DistributedPartyActivity.joinRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny)
        base.cr.playGame.getPlace().fsm.request("walk")

    def exitRequestDenied(self, reason):
        DistributedPartyActivity.exitRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny)

    def setState(self, newState, timestamp):
        DistributedPartyTrampolineActivity.notify.debug(
            "setState( newState=%s, ... )" % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        self.activityFSM.request(newState)

    #---------------------------------------------------
    # FSM handling
    #---------------------------------------------------
    def startIdle(self):
        DistributedPartyTrampolineActivity.notify.debug("startIdle")

    def finishIdle(self):
        DistributedPartyTrampolineActivity.notify.debug("finishIdle")

    def startRules(self):
        DistributedPartyTrampolineActivity.notify.debug("startRules")
        if self.doJellyBeans:
            self.setupJellyBeans()
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self.acquireToon()

    def startActive(self):
        DistributedPartyTrampolineActivity.notify.debug("startActive")
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            base.setCellsAvailable(base.bottomCells, True)

            self.accept("arrow_left", self.onLeft)
            self.accept("arrow_left-up", self.onLeftUp)
            self.accept("arrow_right", self.onRight)
            self.accept("arrow_right-up", self.onRightUp)

            self.beginRoundInterval = Sequence(
                Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady),
                Wait(1.2),
                Func(self.flashMessage, TTLocalizer.PartyTrampolineGo),
                Func(self.beginRound))
            self.beginRoundInterval.start()

    def finishActive(self):
        DistributedPartyTrampolineActivity.notify.debug("finishActive")
        if self.doJellyBeans:
            self.cleanupJellyBeans()

    #---------------------------------------------------
    # FSM extras
    #---------------------------------------------------
    def setupJellyBeans(self):
        self.beanAnims = []
        self.beansToCollect = []
        self.beanDetails = []
        self.numBeansCollected = 0
        for i in range(self.numJellyBeans):
            bean = self.beans[i]
            guiBean = self.guiBeans[i]
            height = self.jellyBeanPositions[i]
            color = random.choice(self.jellyBeanColors)
            bean.find("**/jellybean").setColor(color)
            if self.toon.doId == base.localAvatar.doId:
                bean.setAlphaScale(1.0)
            else:
                bean.setAlphaScale(0.5)
            guiBean.setColor(color)
            bean.setZ(height + self.toon.getHeight() + self.beanOffset)
            guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset)
            bean.setH(0.0)
            bean.unstash()
            guiBean.unstash()
            beanAnim = bean.hprInterval(
                1.5, VBase3((((i % 2) * 2) - 1) * 360.0, 0.0, 0.0)
            )  # the (((i % 2)*2) - 1) makes adjacent beans spin opposite directions
            beanAnim.loop()
            self.beanAnims.append(beanAnim)
            self.beanDetails.append((height, bean, guiBean, beanAnim))
        self.beansToCollect = range(self.numJellyBeans)

    def cleanupJellyBeans(self):
        for bean in self.beans:
            bean.stash()
        for guiBean in self.guiBeans:
            guiBean.stash()
        # If handleToonJoined hasn't been sent toonId on some clients
        if hasattr(self, 'beanAnims'):
            for beanAnim in self.beanAnims:
                beanAnim.finish()
            del self.beanAnims
            del self.beansToCollect

    def beginRound(self):
        base.playSfx(self.whistleSound)

        self.timer.setTime(PartyGlobals.TrampolineDuration)
        self.timer.countdown(PartyGlobals.TrampolineDuration)
        self.timer.show()

        self.quitEarlyButton.unstash()

        self.notify.debug("Accepting contorl")
        self.accept("control", self.onJump)
        self.notify.debug("setting simulate step to true")
        self.doSimulateStep = True

    def acquireToon(self):
        #        self.dataLog = open( "dataLog.txt", "w" )

        self.toon.disableSmartCameraViews()
        self.toon.stopUpdateSmartCamera()
        camera.wrtReparentTo(render)

        self.toon.dropShadow.reparentTo(hidden)
        self.toon.startPosHprBroadcast(period=0.2)

        self.toonAcceleration = 0.0
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.trampB = self.normalTrampB
        self.leavingTrampoline = False
        self.hopOnAnim = Sequence(
            Func(self.toon.b_setAnimState, "jump", 1.0),
            Wait(0.4),
            PartyUtils.arcPosInterval(0.75, self.toon,
                                      Point3(0.0, 0.0, self.trampHeight), 5.0,
                                      self.tramp),
            Func(self.postHopOn),
        )
        self.hopOnAnim.start()

    def postHopOn(self):
        self.toon.setH(self.toon.getH() +
                       90.0)  # makes camera adjustment less jarring
        self.toon.dropShadow.reparentTo(self.surface)
        self.screenPlaneElements.reparentTo(aspect2d)
        self.timeLeftToSimulate = 0.0
        self.doSimulateStep = False
        taskMgr.add(self.updateTask,
                    self.uniqueName("TrampolineActivity.updateTask"))
        base.setCellsAvailable(base.leftCells, False)
        base.setCellsAvailable(base.bottomCells, False)
        DistributedPartyActivity.startRules(self)

    def releaseToon(self):
        self._hideFlashMessage()

        self.ignore("arrow_left")
        self.ignore("arrow_left-up")
        self.ignore("arrow_right")
        self.ignore("arrow_right-up")

        taskMgr.remove(self.uniqueName("TrampolineActivity.updateTask"))
        self.hopOffAnim = Sequence(
            self.toon.hprInterval(0.5,
                                  VBase3(-90.0, 0.0, 0.0),
                                  other=self.tramp),
            Func(self.toon.b_setAnimState, "jump", 1.0),
            Func(self.toon.dropShadow.reparentTo, hidden),
            Wait(0.4),
            PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0,
                                      self.tramp),
            Func(self.postHopOff),
        )
        self.hopOffAnim.start()

    def postHopOff(self):
        self.screenPlaneElements.reparentTo(hidden)
        base.setCellsAvailable(base.leftCells, True)
        self.timer.stop()
        self.timer.hide()

        self.toon.dropShadow.reparentTo(self.toon.getShadowJoint())
        self.toon.dropShadow.setAlphaScale(1.0)
        self.toon.dropShadow.setScale(1.0)

        # Continue broadcasting so remote toons see us reach the final hop off position.
        #self.toon.stopPosHprBroadcast()
        self.b_requestAnim("Off")

        camera.reparentTo(base.localAvatar)
        base.localAvatar.startUpdateSmartCamera()
        base.localAvatar.enableSmartCameraViews()
        base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex)
        place = base.cr.playGame.getPlace()

        if self.doJellyBeans:
            self.sendUpdate("awardBeans",
                            [self.numBeansCollected,
                             int(self.topHeight)])
            if int(self.topHeight) > self.bestHeightInfo[1]:
                self.sendUpdate("reportHeightInformation",
                                [int(self.topHeight)])

        self.d_toonExitDemand()

    #---------------------------------------------------
    # Event Handling
    #---------------------------------------------------
    def onTrampolineTrigger(self, collEntry):
        if (self.activityFSM.state == "Idle") and (self.toon == None) and (
                base.cr.playGame.getPlace().fsm.getCurrentState().getName()
                == "walk"):
            base.cr.playGame.getPlace().fsm.request("activity")
            self.d_toonJoinRequest()
        else:
            self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied,
                              duration=2.0)

    def onJump(self):
        self.notify.debug("got onJump")
        if self.toon != None and self.toon.getZ() < self.trampHeight:
            # Have to be on the trampoline
            self.toonJumped = True
            self.b_requestAnim("Jump")
        else:
            self.notify.debug("z is less than tramp height")

    def onLeft(self):
        self.turnLeft = True

    def onLeftUp(self):
        self.turnLeft = False

    def onRight(self):
        self.turnRight = True

    def onRightUp(self):
        self.turnRight = False

    #---------------------------------------------------
    # Super class functionality
    #---------------------------------------------------
    def handleToonJoined(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug("handleToonJoined")
        self.toon = self.getAvatar(toonId)
        if self.toon != None and not self.toon.isEmpty():
            self.oldJumpSquatPlayRate = self.toon.getPlayRate("jump-squat")
            self.oldJumpLandPlayRate = self.toon.getPlayRate("jump-land")
            self.toon.setPlayRate(2.5, "jump-squat")
            self.toon.setPlayRate(2.0, "jump-land")

            self.turnLeft = False
            self.turnRight = False

            self.activityFSM.request("Rules")

            if self.toon.doId != base.localAvatar.doId:
                taskMgr.add(
                    self.remoteUpdateTask,
                    self.uniqueName("TrampolineActivity.remoteUpdateTask"))
        else:
            self.notify.warning("handleToonJoined could not get toon %d" %
                                toonId)

    def handleToonExited(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug("handleToonExited")

        if self.toon != None:
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.remove(
                    self.uniqueName("TrampolineActivity.remoteUpdateTask"))

            self.surface.setZ(self.trampHeight)

            self.toon.setPlayRate(self.oldJumpSquatPlayRate, "jump-squat")
            self.toon.setPlayRate(self.oldJumpLandPlayRate, "jump-land")

            self.toon = None

    def handleToonDisabled(self, toonId):
        """
        A toon dropped unexpectedly from the game. Handle it!
        """
        DistributedPartyTrampolineActivity.notify.debug("handleToonDisabled")
        DistributedPartyTrampolineActivity.notify.debug("avatar " +
                                                        str(toonId) +
                                                        " disabled")

        if base.localAvatar.doId == toonId:
            self.releaseToon()

    def handleRulesDone(self):
        self.sendUpdate("toonReady")
        self.finishRules()

    def getTitle(self):
        if self.doJellyBeans:
            return TTLocalizer.PartyTrampolineJellyBeanTitle
        elif self.doTricks:
            return TTLocalizer.PartyTrampolineTricksTitle
        else:
            return DistributedPartyActivity.getTitle(self)

    def getInstructions(self):
        return TTLocalizer.PartyTrampolineActivityInstructions

    #---------------------------------------------------
    # Simulation
    #---------------------------------------------------
    def updateTask(self, task):
        # Only run on local client
        z = self.toon.getZ()
        dt = globalClock.getDt()
        if self.doSimulateStep:
            self.timeLeftToSimulate += dt
            while self.timeLeftToSimulate >= self.stepDT:
                z, a = self.simulateStep(z)
                self.timeLeftToSimulate -= self.stepDT

        self.toon.setZ(z)

        # Move tramp surface
        if z <= self.trampHeight:
            self.surface.setZ(z)
        else:
            self.surface.setZ(self.trampHeight)

        # Move toon indicator
        self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor)

        # Turn left or right
        if self.turnLeft:
            self.toon.setH(self.toon.getH() + self.turnFactor * dt)
        if self.turnRight:
            self.toon.setH(self.toon.getH() - self.turnFactor * dt)

        # Update camera
        currentPos = base.camera.getPos(self.toon)
        vec = self.targetCameraPos - currentPos
        newPos = currentPos + vec * (dt * self.cameraSpeed)
        base.camera.setPos(self.toon, newPos)
        base.camera.lookAt(self.toon)

        # Fade and scale drop shadow
        if z > self.trampHeight:
            heightFactor = 1.0 - min(
                1.0, (z - self.trampHeight) / self.dropShadowCutoff)
            self.toon.dropShadow.setAlphaScale(heightFactor)
            self.toon.dropShadow.setScale(max(0.1, heightFactor))
        else:
            self.toon.dropShadow.setAlphaScale(1.0)
            self.toon.dropShadow.setScale(1.0)

        # Leave trampoline if necessary
        if self.leavingTrampoline and (z < self.trampHeight) and (abs(a) <
                                                                  0.1):
            self.releaseToon()

# Simulate poor framerate
#        time.sleep( 0.03 )

        return Task.cont

    def simulateStep(self, z):
        # Calculate acceleration
        if z >= self.trampHeight:
            # Above the trampoline; only use gravity.
            a = self.g
            # Clear jumped flag
            self.toonJumped = False
        else:
            # On the trampoline; use gravity + spring + damping
            a = self.g + self.trampK * (self.trampHeight -
                                        z) - self.trampB * self.toonVelocity
            # Add jump acceleration if necessary
            if self.toonJumped:
                # Don't penalize early jumps.
                # If we're above the earlyJumpThreshold, go ahead and add jump
                # acceleration, even if the toon hasn't bottomed out (which
                # will reduce the effectiveness of the jump).
                # Otherwise, only add jump acceleration, if the toon has
                # bottomed out (toonVelocity >= 0.0).
                #self.notify.debug("self.lastPeak=%s earlyJumpThreshold=%s toonVelocity=%s" %(self.lastPeak, self.earlyJumpThreshold, self.toonVelocity ))
                if (self.lastPeak > self.earlyJumpThreshold) or (
                        self.toonVelocity >= -3E5):
                    a += self.jumpBoost
                    # Add beginning boost if necessary.
                    if self.lastPeak < self.beginningBoostThreshold:
                        a += self.beginningBoost

        # Calculate velocity
        #import pdb; pdb.set_trace()
        lastVelocity = self.toonVelocity
        self.toonVelocity += a * self.stepDT

        if (lastVelocity > 0.0) and (self.toonVelocity <= 0.0):
            topOfJump = True
            bottomOfJump = False
        elif (lastVelocity < 0.0) and (self.toonVelocity >= 0.0):
            topOfJump = False
            bottomOfJump = True
        else:
            topOfJump = False
            bottomOfJump = False

        # optimal jumping


#        if bottomOfJump and self.isAccepting( "control" ):
#            self.toonJumped = True
#            print z

# Calculate position
        newZ = z + self.toonVelocity * self.stepDT
        if newZ > self.topHeight:
            self.topHeight = newZ
            if self.doJellyBeans:
                self.collectJellyBeans(newZ)

        if topOfJump:
            # Set lastPeak
            self.lastPeak = newZ

            # Show height text if necessary
            if newZ >= self.minHeightForText:
                self.heightTextInterval.start()

        # Set anim state
        if topOfJump:
            if newZ > (self.trampHeight + 20.0):
                self.b_requestAnim("Falling")
            elif self.animFSM.state == "Jump":
                self.b_requestAnim("Falling")
        if (newZ <= self.trampHeight) and (z > self.trampHeight):
            if self.animFSM.state == "Falling":
                self.b_requestAnim("Land")
            elif self.animFSM.state != "Neutral":
                self.b_requestAnim("Neutral")

        # Play "boing" sound.
        if bottomOfJump and (a > self.boingThreshold):
            base.playSfx(self.boingSound)

        return newZ, a

    def collectJellyBeans(self, z):
        beansToRemove = []
        for i in self.beansToCollect:
            height = self.beanDetails[i][0]
            if height <= z:
                beansToRemove.append(i)

        if len(beansToRemove) > 0:
            base.playSfx(self.jellyBeanSound)
            self.numBeansCollected += len(beansToRemove)
            self.b_removeBeans(beansToRemove)

    def remoteUpdateTask(self, task):
        # Only run on remote clients

        # Move tramp surface
        if self.toon != None and not self.toon.isEmpty():
            z = self.toon.getZ()
            if z <= self.trampHeight:
                self.surface.setZ(z)
            else:
                self.surface.setZ(self.trampHeight)

        return Task.cont

    #---------------------------------------------------
    # Misc
    #---------------------------------------------------
    def poofBean(self, bean, beanAnim):
        if bean == None:
            self.notify.warning(
                "poofBean, returning immediately as bean is None")
            return
        if bean.isEmpty():
            self.notify.warning(
                "poofBean, returning immediately as bean is empty")
            return
        currentAlpha = bean.getColorScale()[3]
        currentScale = bean.getScale()
        poofAnim = Sequence(
            Parallel(
                LerpFunc(bean.setAlphaScale,
                         fromData=currentAlpha,
                         toData=0.0,
                         duration=0.25),
                LerpFunc(bean.setScale,
                         fromData=currentScale,
                         toData=currentScale * 5.0,
                         duration=0.25),
            ),
            Func(bean.stash),
            Func(beanAnim.finish),
            Func(bean.setAlphaScale, currentAlpha),
            Func(bean.setScale, currentScale),
        )
        poofAnim.start()

    def _showFlashMessage(self, message):
        if self.isDisabled():
            assert self.notify.debug(
                "_showFlasMessage disabled, not showing %s" % message)
            return

        if (self.flashTextInterval
                is not None) and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        self.flashText.setText(message)
        self.flashText.setAlphaScale(1.0)
        self.flashText.unstash()

    def _hideFlashMessage(self, duration=0.0):
        if self.isDisabled():
            assert self.notify.debug(
                "_hideFlashMessage we're disabled, but still hiding self.flashText"
            )
            # return

        self.flashTextInterval = Sequence(
            Wait(duration),
            LerpFunc(self.flashText.setAlphaScale,
                     fromData=1.0,
                     toData=0.0,
                     duration=1.0),
            Func(self.flashText.stash),
        )
        self.flashTextInterval.start()

    def flashMessage(self, message, duration=0.5):
        self._showFlashMessage(message)
        self._hideFlashMessage(duration)
示例#57
0
class CogdoGameGatherable(NodePath, DirectObject):
    EnterEventName = 'CogdoGameGatherable_Enter'

    def __init__(self,
                 serialNum,
                 model,
                 triggerRadius,
                 triggerOffset=(0, 0, 0),
                 animate=True,
                 animDuration=0.2,
                 instanceModel=True,
                 name='CogdoGameGatherable'):
        NodePath.__init__(self, '%s-%d' % (name, serialNum))
        self.serialNum = serialNum
        self._animate = animate
        if instanceModel:
            model.instanceTo(self)
            self._model = self
        else:
            self._model = model
            self._model.reparentTo(self)
            self._model.setPosHpr(0, 0, 0, 0, 0, 0)
        self._animDuration = animDuration
        self._animSeq = None
        self._initCollisions(triggerRadius, triggerOffset)
        self._update = None
        self._wasPickedUp = False
        return

    def _initCollisions(self, triggerRadius, triggerOffset):
        self.collSphere = CollisionSphere(triggerOffset[0], triggerOffset[1],
                                          triggerOffset[2], triggerRadius)
        self.collSphere.setTangible(0)
        self.collNode = CollisionNode(self.getName())
        self.collNode.addSolid(self.collSphere)
        self.collNodePath = self.attachNewNode(self.collNode)

    def destroy(self):
        self.disable()
        del self._model
        if self._animSeq is not None:
            self._animSeq.finish()
            self._animSeq = None
        self.collNodePath.removeNode()
        self.removeNode()
        return

    def enable(self):
        self.accept('enter' + self.getName(), self._handleEnterCollision)
        self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)

    def disable(self):
        self.ignoreAll()
        self.collNode.setIntoCollideMask(BitMask32(0))

    def show(self):
        if not self.wasPickedUp():
            NodePath.show(self)
            self.enable()

    def hide(self):
        self.disable()
        NodePath.hide(self)

    def _handleEnterCollision(self, collEntry):
        messenger.send(CogdoGameGatherable.EnterEventName, [self])

    def wasPickedUp(self):
        return self._wasPickedUp

    def wasPickedUpByToon(self):
        pass

    def update(self, dt):
        pass

    def getModel(self):
        return self._model

    def pickUp(self, toon, elapsedSeconds=0.0):
        self._wasPickedUp = True
        if self._animSeq is not None:
            self._animSeq.finish()
            self._animSeq = None
        if self._animate:

            def lerpFlyToToon(t):
                vec = toon.getPos(render) - self.getPos(render)
                vec[2] += toon.getHeight()
                self.setPos(self.getPos() + vec * t)
                self.setScale(1.0 - t * 0.8)

            self._animSeq = Sequence(
                LerpFunc(lerpFlyToToon,
                         fromData=0.0,
                         toData=1.0,
                         duration=self._animDuration), Wait(0.1),
                Func(self.hide))
            self._animSeq.start(elapsedSeconds)
        else:
            self.hide()
        return
示例#58
0
class CogdoMazeDrop(NodePath, DirectObject):
    def __init__(self, game, id, x, y):
        NodePath.__init__(self, 'dropNode%s' % id)
        self.game = game
        self.id = id
        self.reparentTo(hidden)
        self.setPos(x, y, 0)
        shadow = loader.loadModel('phase_3/models/props/square_drop_shadow')
        shadow.setZ(0.2)
        shadow.setBin('ground', 10)
        shadow.setColor(1, 1, 1, 1)
        shadow.reparentTo(self)
        self.shadow = shadow
        drop = CogdoUtil.loadMazeModel('cabinetSmFalling')
        roll = random.randint(-15, 15)
        drop.setHpr(0, 0, roll)
        drop.setZ(Globals.DropHeight)
        self.collTube = CollisionTube(0, 0, 0, 0, 0, 4,
                                      Globals.DropCollisionRadius)
        self.collTube.setTangible(0)
        name = Globals.DropCollisionName
        self.collNode = CollisionNode(name)
        self.collNode.addSolid(self.collTube)
        self.collNodePath = drop.attachNewNode(self.collNode)
        self.collNodePath.hide()
        self.collNodePath.setTag('isFalling', str('True'))
        drop.reparentTo(self)
        self.drop = drop
        self._dropSfx = base.cogdoGameAudioMgr.createSfxIval('drop',
                                                             volume=0.6)

    def disableCollisionDamage(self):
        self.collTube.setTangible(1)
        self.collTube.setRadius(Globals.DroppedCollisionRadius)
        self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
        self.collNodePath.setTag('isFalling', str('False'))

    def getDropIval(self):
        shadow = self.shadow
        drop = self.drop
        id = self.id
        hangTime = Globals.ShadowTime
        dropTime = Globals.DropTime
        dropHeight = Globals.DropHeight
        targetShadowScale = 0.5
        targetShadowAlpha = 0.4
        shadowScaleIval = LerpScaleInterval(shadow,
                                            dropTime,
                                            targetShadowScale,
                                            startScale=0)
        shadowAlphaIval = LerpColorScaleInterval(
            shadow,
            hangTime,
            Point4(1, 1, 1, targetShadowAlpha),
            startColorScale=Point4(1, 1, 1, 0))
        shadowIval = Parallel(shadowScaleIval, shadowAlphaIval)
        startPos = Point3(0, 0, dropHeight)
        drop.setPos(startPos)
        dropIval = LerpPosInterval(drop,
                                   dropTime,
                                   Point3(0, 0, 0),
                                   startPos=startPos,
                                   blendType='easeIn')
        dropSoundIval = self._dropSfx
        dropSoundIval.node = self
        self.drop.setTransparency(1)

        def _setRandScale(t):
            self.drop.setScale(self, 1 - random.random() / 16,
                               1 - random.random() / 16,
                               1 - random.random() / 4)

        scaleChange = 0.4 + random.random() / 4
        dropShakeSeq = Sequence(
            LerpScaleInterval(self.drop,
                              0.25,
                              Vec3(1.0 + scaleChange, 1.0 + scaleChange / 2,
                                   1.0 - scaleChange),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.25,
                              Vec3(1.0, 1.0, 1.0),
                              blendType='easeInOut'),
            Func(self.disableCollisionDamage),
            LerpScaleInterval(self.drop,
                              0.2,
                              Vec3(1.0 + scaleChange / 8,
                                   1.0 + scaleChange / 8,
                                   1.0 - scaleChange / 8),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.2,
                              Vec3(1.0, 1.0, 1.0),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.15,
                              Vec3(1.0 + scaleChange / 16,
                                   1.0 + scaleChange / 16,
                                   1.0 - scaleChange / 16),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.15,
                              Vec3(1.0, 1.0, 1.0),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.1,
                              Vec3(1.0 + scaleChange / 16,
                                   1.0 + scaleChange / 8,
                                   1.0 - scaleChange / 16),
                              blendType='easeInOut'),
            LerpColorScaleInterval(self.drop, Globals.DropFadeTime,
                                   Vec4(1.0, 1.0, 1.0, 0.0)))
        ival = Sequence(Func(self.reparentTo, render),
                        Parallel(Sequence(WaitInterval(hangTime), dropIval),
                                 shadowIval),
                        Parallel(Func(self.game.dropHit, self, id),
                                 dropSoundIval, dropShakeSeq),
                        Func(self.game.cleanupDrop, id),
                        name='drop%s' % id)
        self.ival = ival
        return ival

    def destroy(self):
        self.ival.pause()
        self.ival = None
        self._dropSfx.pause()
        self._dropSfx = None
        self.collTube = None
        self.collNode = None
        self.collNodePath.removeNode()
        self.collNodePath = None
        self.removeNode()
        return
示例#59
0
class DistributedPartyTrampolineActivity(DistributedPartyActivity):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyTrampolineActivity')

    def __init__(self, cr, doJellyBeans = True, doTricks = False, texture = None):
        DistributedPartyTrampolineActivity.notify.debug('__init__')
        DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityTypes.GuestInitiated, wantLever=False, wantRewardGui=True)
        self.doJellyBeans = doJellyBeans
        self.doTricks = doTricks
        self.texture = texture
        self.toon = None
        self.trampHeight = 3.6
        self.trampK = 400.0
        self.normalTrampB = 2.5
        self.leavingTrampB = 8.0
        self.trampB = self.normalTrampB
        self.g = -32.0
        self.jumpBoost = 330.0
        self.beginningBoost = 500.0
        self.beginningBoostThreshold = self.trampHeight + 1.5
        self.earlyJumpThreshold = 75.0
        self.boingThreshold = 300.0
        self.turnFactor = 120.0
        self.stepDT = 0.001
        self.targetCameraPos = Point3(0.0, 40.0, 10.0)
        self.cameraSpeed = 2.0
        self.hopOffPos = Point3(16.0, 0.0, 0.0)
        self.indicatorFactor = 0.0095
        self.dropShadowCutoff = 15.0
        self.minHeightForText = 15.0
        self.heightTextOffset = -0.065
        self.beanOffset = 0.5
        self.guiBeanOffset = -0.02
        self.jumpTextShown = False
        self.toonJumped = False
        self.turnLeft = False
        self.turnRight = False
        self.leavingTrampoline = False
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.lastPeak = 0.0
        self.beginRoundInterval = None
        self.hopOnAnim = None
        self.hopOffAnim = None
        self.flashTextInterval = None
        self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans
        self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus
        self.jellyBeanStartHeight = 20.0
        self.jellyBeanStopHeight = 90.0
        self.jellyBeanColors = [VBase4(1.0, 0.5, 0.5, 1.0),
         VBase4(0.5, 1.0, 0.5, 1.0),
         VBase4(0.5, 1.0, 1.0, 1.0),
         VBase4(1.0, 1.0, 0.4, 1.0),
         VBase4(0.4, 0.4, 1.0, 1.0),
         VBase4(1.0, 0.5, 1.0, 1.0)]
        delta = (self.jellyBeanStopHeight - self.jellyBeanStartHeight) / (self.numJellyBeans - 1)
        self.jellyBeanPositions = [ self.jellyBeanStartHeight + n * delta for n in xrange(self.numJellyBeans) ]
        self.doSimulateStep = False
        return

    def load(self):
        DistributedPartyTrampolineActivity.notify.debug('load')
        DistributedPartyActivity.load(self)
        self.loadModels()
        self.loadCollision()
        self.loadGUI()
        self.loadSounds()
        self.loadIntervals()
        self.activityFSM = TrampolineActivityFSM(self)
        self.activityFSM.request('Idle')
        self.animFSM = TrampolineAnimFSM(self)
        self.setBestHeightInfo('', 0)

    def loadModels(self):
        self.tramp = self.root.attachNewNode(self.uniqueName('tramp'))
        self.trampActor = Actor('phase_13/models/parties/trampoline_model', {'emptyAnim': 'phase_13/models/parties/trampoline_anim'})
        self.trampActor.reparentTo(self.tramp)
        if self.texture:
            reskinNode = self.tramp.find('**/trampoline/__Actor_modelRoot/-GeomNode')
            reskinNode.setTexture(loader.loadTexture(self.texture), 100)
        self.surface = NodePath(self.uniqueName('trampSurface'))
        self.surface.reparentTo(self.tramp)
        self.surface.setZ(self.trampHeight)
        self.trampActor.controlJoint(self.surface, 'modelRoot', 'trampoline_joint1')
        self.sign.setPos(PartyGlobals.TrampolineSignOffset)
        self.beans = [ loader.loadModelCopy('phase_4/models/props/jellybean4') for i in xrange(self.numJellyBeans) ]
        for bean in self.beans:
            bean.find('**/jellybean').setP(-35.0)
            bean.setScale(3.0)
            bean.setTransparency(True)
            bean.reparentTo(self.tramp)
            bean.stash()

        self.beans[-1].setScale(8.0)

    def loadCollision(self):
        collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4)
        collTube.setTangible(True)
        self.trampolineCollision = CollisionNode(self.uniqueName('TrampolineCollision'))
        self.trampolineCollision.addSolid(collTube)
        self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask | OTPGlobals.WallBitmask)
        self.trampolineCollisionNP = self.tramp.attachNewNode(self.trampolineCollision)
        collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0)
        collSphere.setTangible(False)
        self.trampolineTrigger = CollisionNode(self.uniqueName('TrampolineTrigger'))
        self.trampolineTrigger.addSolid(collSphere)
        self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask)
        self.trampolineTriggerNP = self.tramp.attachNewNode(self.trampolineTrigger)
        self.accept('enter%s' % self.uniqueName('TrampolineTrigger'), self.onTrampolineTrigger)

    def loadGUI(self):
        self.gui = loader.loadModel('phase_13/models/parties/trampolineGUI')
        self.gui.reparentTo(base.a2dTopLeft)
        self.gui.setPos(0.115, 0, -1)
        self.gui.hide()
        self.toonIndicator = self.gui.find('**/trampolineGUI_MovingBar')
        jumpLineLocator = self.gui.find('**/jumpLine_locator')
        guiBean = self.gui.find('**/trampolineGUI_GreenJellyBean')
        self.gui.find('**/trampolineGUI_GreenJellyBean').stash()
        self.guiBeans = [ guiBean.instanceUnderNode(jumpLineLocator, self.uniqueName('guiBean%d' % i)) for i in xrange(self.numJellyBeans) ]
        self.guiBeans[-1].setScale(1.5)
        heightTextNode = TextNode(self.uniqueName('TrampolineActivity.heightTextNode'))
        heightTextNode.setFont(ToontownGlobals.getSignFont())
        heightTextNode.setAlign(TextNode.ALeft)
        heightTextNode.setText('0.0')
        heightTextNode.setShadow(0.05, 0.05)
        heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0)
        heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0)
        self.heightText = jumpLineLocator.attachNewNode(heightTextNode)
        self.heightText.setX(0.15)
        self.heightText.setScale(0.1)
        self.heightText.setAlphaScale(0.0)
        self.quitEarlyButtonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui')
        quitEarlyUp = self.quitEarlyButtonModels.find('**//InventoryButtonUp')
        quitEarlyDown = self.quitEarlyButtonModels.find('**/InventoryButtonDown')
        quitEarlyRollover = self.quitEarlyButtonModels.find('**/InventoryButtonRollover')
        self.quitEarlyButton = DirectButton(parent=base.a2dTopRight, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-0.183, 0, -0.4), scale=0.09, command=self.leaveTrampoline)
        self.quitEarlyButton.stash()
        self.flashText = OnscreenText(text='', pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True)
        self.timer = PartyUtils.getNewToontownTimer()
        self.timer.posInTopRightCorner()
        return

    def loadSounds(self):
        self.jellyBeanSound = base.loader.loadSfx('phase_4/audio/sfx/sparkly.ogg')
        self.boingSound = base.loader.loadSfx('phase_4/audio/sfx/target_trampoline_2.ogg')
        self.whistleSound = base.loader.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg')

    def loadIntervals(self):

        def prepareHeightText():
            self.heightText.node().setText(TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ()))
            self.heightText.setZ(self.indicatorFactor * self.toon.getZ() + self.heightTextOffset)

        self.heightTextInterval = Sequence(Func(prepareHeightText), LerpFunc(self.heightText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0))

    def unload(self):
        DistributedPartyTrampolineActivity.notify.debug('unload')
        if self.hopOnAnim and self.hopOnAnim.isPlaying():
            self.hopOnAnim.finish()
        if self.hopOffAnim and self.hopOffAnim.isPlaying():
            self.hopOffAnim.finish()
        if self.beginRoundInterval and self.beginRoundInterval.isPlaying():
            self.beginRoundInterval.finish()
        if self.flashTextInterval and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        if self.heightTextInterval and self.heightTextInterval.isPlaying():
            self.heightTextInterval.finish()
        self.timer.stop()
        DistributedPartyActivity.unload(self)
        taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask'))
        taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask'))
        self.ignoreAll()
        del self.heightTextInterval
        del self.beginRoundInterval
        del self.hopOnAnim
        del self.hopOffAnim
        del self.flashTextInterval
        if hasattr(self, 'beanAnims'):
            self.cleanupJellyBeans()
        self.quitEarlyButton.destroy()
        del self.quitEarlyButton
        del self.gui
        del self.activityFSM
        del self.animFSM
        return

    def setBestHeightInfo(self, toonName, height):
        self.bestHeightInfo = (toonName, height)
        DistributedPartyTrampolineActivity.notify.debug('%s has the best height of %d' % (toonName, height))
        if height > 0:
            self.setSignNote(TTLocalizer.PartyTrampolineBestHeight % self.bestHeightInfo)
        else:
            self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet)

    def leaveTrampoline(self):
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp)
            self.leavingTrampoline = True
            self.timer.reset()
            self.trampB = self.leavingTrampB
            self.ignore('control')
            self.quitEarlyButton.stash()
            self.gui.hide()
        return

    def requestAnim(self, request):
        self.animFSM.request(request)

    def b_requestAnim(self, request):
        self.requestAnim(request)
        self.sendUpdate('requestAnim', [request])

    def requestAnimEcho(self, request):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.requestAnim(request)
        return

    def removeBeans(self, beansToRemove):
        for i in beansToRemove:
            height, bean, guiBean, beanAnim = self.beanDetails[i]
            guiBean.stash()
            if i in self.beansToCollect:
                self.beansToCollect.remove(i)
            else:
                self.notify.warning('removeBeans avoided a crash, %d not in self.beansToCollect' % i)
            self.poofBean(bean, beanAnim)

    def b_removeBeans(self, beansToRemove):
        self.removeBeans(beansToRemove)
        self.sendUpdate('removeBeans', [beansToRemove])

    def removeBeansEcho(self, beansToRemove):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.removeBeans(beansToRemove)
        return

    def joinRequestDenied(self, reason):
        DistributedPartyActivity.joinRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny)
        base.cr.playGame.getPlace().fsm.request('walk')

    def exitRequestDenied(self, reason):
        DistributedPartyActivity.exitRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny)

    def setState(self, newState, timestamp):
        DistributedPartyTrampolineActivity.notify.debug('setState( newState=%s, ... )' % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        self.activityFSM.request(newState)

    def startIdle(self):
        DistributedPartyTrampolineActivity.notify.debug('startIdle')

    def finishIdle(self):
        DistributedPartyTrampolineActivity.notify.debug('finishIdle')

    def startRules(self):
        DistributedPartyTrampolineActivity.notify.debug('startRules')
        if self.doJellyBeans:
            self.setupJellyBeans()
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self.acquireToon()
        return

    def startActive(self):
        DistributedPartyTrampolineActivity.notify.debug('startActive')
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            base.setCellsActive(base.bottomCells, True)
            self.accept('arrow_left', self.onLeft)
            self.accept('arrow_left-up', self.onLeftUp)
            self.accept('arrow_right', self.onRight)
            self.accept('arrow_right-up', self.onRightUp)
            self.beginRoundInterval = Sequence(Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady), Wait(1.2), Func(self.flashMessage, TTLocalizer.PartyTrampolineGo), Func(self.beginRound))
            self.beginRoundInterval.start()
        return

    def finishActive(self):
        DistributedPartyTrampolineActivity.notify.debug('finishActive')
        if self.doJellyBeans:
            self.cleanupJellyBeans()

    def setupJellyBeans(self):
        self.beanAnims = []
        self.beansToCollect = []
        self.beanDetails = []
        self.numBeansCollected = 0
        for i in xrange(self.numJellyBeans):
            bean = self.beans[i]
            guiBean = self.guiBeans[i]
            height = self.jellyBeanPositions[i]
            color = random.choice(self.jellyBeanColors)
            bean.find('**/jellybean').setColor(color)
            if self.toon.doId == base.localAvatar.doId:
                bean.setAlphaScale(1.0)
            else:
                bean.setAlphaScale(0.5)
            guiBean.setColor(color)
            bean.setZ(height + self.toon.getHeight() + self.beanOffset)
            guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset)
            bean.setH(0.0)
            bean.unstash()
            guiBean.unstash()
            beanAnim = bean.hprInterval(1.5, VBase3((i % 2 * 2 - 1) * 360.0, 0.0, 0.0))
            beanAnim.loop()
            self.beanAnims.append(beanAnim)
            self.beanDetails.append((height,
             bean,
             guiBean,
             beanAnim))

        self.beansToCollect = range(self.numJellyBeans)

    def cleanupJellyBeans(self):
        for bean in self.beans:
            bean.stash()

        for guiBean in self.guiBeans:
            guiBean.stash()

        if hasattr(self, 'beanAnims'):
            for beanAnim in self.beanAnims:
                beanAnim.finish()

            del self.beanAnims
            del self.beansToCollect

    def beginRound(self):
        base.playSfx(self.whistleSound)
        self.timer.setTime(PartyGlobals.TrampolineDuration)
        self.timer.countdown(PartyGlobals.TrampolineDuration)
        self.timer.show()
        self.gui.show()
        self.quitEarlyButton.unstash()
        self.notify.debug('Accepting contorl')
        self.accept('control', self.onJump)
        self.notify.debug('setting simulate step to true')
        self.doSimulateStep = True

    def acquireToon(self):
        self.toon.disableSmartCameraViews()
        self.toon.stopUpdateSmartCamera()
        camera.wrtReparentTo(render)
        self.toon.dropShadow.reparentTo(hidden)
        self.toon.startPosHprBroadcast(period=0.2)
        self.toonAcceleration = 0.0
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.trampB = self.normalTrampB
        self.leavingTrampoline = False
        self.hopOnAnim = Sequence(Func(self.toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, Point3(0.0, 0.0, self.trampHeight), 5.0, self.tramp), Func(self.postHopOn))
        self.hopOnAnim.start()

    def postHopOn(self):
        self.toon.setH(self.toon.getH() + 90.0)
        self.toon.dropShadow.reparentTo(self.surface)
        self.timeLeftToSimulate = 0.0
        self.doSimulateStep = False
        taskMgr.add(self.updateTask, self.uniqueName('TrampolineActivity.updateTask'))
        base.setCellsActive(base.leftCells, False)
        base.setCellsActive(base.bottomCells, False)
        DistributedPartyActivity.startRules(self)

    def releaseToon(self):
        self._hideFlashMessage()
        self.ignore('arrow_left')
        self.ignore('arrow_left-up')
        self.ignore('arrow_right')
        self.ignore('arrow_right-up')
        taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask'))
        self.hopOffAnim = Sequence(self.toon.hprInterval(0.5, VBase3(-90.0, 0.0, 0.0), other=self.tramp), Func(self.toon.b_setAnimState, 'jump', 1.0), Func(self.toon.dropShadow.reparentTo, hidden), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0, self.tramp), Func(self.postHopOff))
        self.hopOffAnim.start()

    def postHopOff(self):
        base.setCellsActive(base.leftCells, True)
        self.timer.stop()
        self.timer.hide()
        self.toon.dropShadow.reparentTo(self.toon.getShadowJoint())
        self.toon.dropShadow.setAlphaScale(1.0)
        self.toon.dropShadow.setScale(1.0)
        self.b_requestAnim('Off')
        camera.reparentTo(base.localAvatar)
        base.localAvatar.startUpdateSmartCamera()
        base.localAvatar.enableSmartCameraViews()
        base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex)
        place = base.cr.playGame.getPlace()
        if self.doJellyBeans:
            self.sendUpdate('awardBeans', [self.numBeansCollected, int(self.topHeight)])
            if int(self.topHeight) > self.bestHeightInfo[1]:
                self.sendUpdate('reportHeightInformation', [int(self.topHeight)])
        self.d_toonExitDemand()

    def onTrampolineTrigger(self, collEntry):
        if self.activityFSM.state == 'Idle' and self.toon == None and base.cr.playGame.getPlace().fsm.getCurrentState().getName() == 'walk':
            base.cr.playGame.getPlace().fsm.request('activity')
            self.d_toonJoinRequest()
        else:
            self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied, duration=2.0)
        return

    def onJump(self):
        self.notify.debug('got onJump')
        if self.toon != None and self.toon.getZ() < self.trampHeight:
            self.toonJumped = True
            self.b_requestAnim('Jump')
        else:
            self.notify.debug('z is less than tramp height')
        return

    def onLeft(self):
        self.turnLeft = True

    def onLeftUp(self):
        self.turnLeft = False

    def onRight(self):
        self.turnRight = True

    def onRightUp(self):
        self.turnRight = False

    def handleToonJoined(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonJoined')
        self.toon = self.getAvatar(toonId)
        if self.toon != None and not self.toon.isEmpty():
            self.oldJumpSquatPlayRate = self.toon.getPlayRate('jump-squat')
            self.oldJumpLandPlayRate = self.toon.getPlayRate('jump-land')
            self.toon.setPlayRate(2.5, 'jump-squat')
            self.toon.setPlayRate(2.0, 'jump-land')
            self.turnLeft = False
            self.turnRight = False
            self.activityFSM.request('Rules')
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.add(self.remoteUpdateTask, self.uniqueName('TrampolineActivity.remoteUpdateTask'))
        else:
            self.notify.warning('handleToonJoined could not get toon %d' % toonId)
        return

    def handleToonExited(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonExited')
        if self.toon != None:
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask'))
            self.surface.setZ(self.trampHeight)
            self.toon.setPlayRate(self.oldJumpSquatPlayRate, 'jump-squat')
            self.toon.setPlayRate(self.oldJumpLandPlayRate, 'jump-land')
            self.toon = None
        return

    def handleToonDisabled(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonDisabled')
        DistributedPartyTrampolineActivity.notify.debug('avatar ' + str(toonId) + ' disabled')
        if base.localAvatar.doId == toonId:
            self.releaseToon()

    def handleRulesDone(self):
        self.sendUpdate('toonReady')
        self.finishRules()

    def getTitle(self):
        if self.doJellyBeans:
            return TTLocalizer.PartyTrampolineJellyBeanTitle
        elif self.doTricks:
            return TTLocalizer.PartyTrampolineTricksTitle
        else:
            return DistributedPartyActivity.getTitle(self)

    def getInstructions(self):
        return TTLocalizer.PartyTrampolineActivityInstructions

    def updateTask(self, task):
        z = self.toon.getZ()
        dt = globalClock.getDt()
        if self.doSimulateStep:
            self.timeLeftToSimulate += dt
            while self.timeLeftToSimulate >= self.stepDT:
                z, a = self.simulateStep(z)
                self.timeLeftToSimulate -= self.stepDT

        self.toon.setZ(z)
        if z <= self.trampHeight:
            self.surface.setZ(z)
        else:
            self.surface.setZ(self.trampHeight)
        self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor)
        if self.turnLeft:
            self.toon.setH(self.toon.getH() + self.turnFactor * dt)
        if self.turnRight:
            self.toon.setH(self.toon.getH() - self.turnFactor * dt)
        currentPos = base.camera.getPos(self.toon)
        vec = self.targetCameraPos - currentPos
        newPos = currentPos + vec * (dt * self.cameraSpeed)
        base.camera.setPos(self.toon, newPos)
        base.camera.lookAt(self.toon)
        #if z > self.trampHeight:
        #    heightFactor = 1.0 - min(1.0, (z - self.trampHeight) / self.dropShadowCutoff)
        #    self.toon.dropShadow.setAlphaScale(heightFactor)
        #    self.toon.dropShadow.setScale(max(0.1, heightFactor))
        #else:
        #    self.toon.dropShadow.setAlphaScale(1.0)
        #    self.toon.dropShadow.setScale(1.0)
        if self.leavingTrampoline and z < self.trampHeight and abs(a) < 0.1:
            self.releaseToon()
        return Task.cont

    def simulateStep(self, z):
        if z >= self.trampHeight:
            a = self.g
            self.toonJumped = False
        else:
            a = self.g + self.trampK * (self.trampHeight - z) - self.trampB * self.toonVelocity
            if self.toonJumped:
                if self.lastPeak > self.earlyJumpThreshold or self.toonVelocity >= -300000.0:
                    a += self.jumpBoost
                    if self.lastPeak < self.beginningBoostThreshold:
                        a += self.beginningBoost
        lastVelocity = self.toonVelocity
        self.toonVelocity += a * self.stepDT
        if lastVelocity > 0.0 and self.toonVelocity <= 0.0:
            topOfJump = True
            bottomOfJump = False
        elif lastVelocity < 0.0 and self.toonVelocity >= 0.0:
            topOfJump = False
            bottomOfJump = True
        else:
            topOfJump = False
            bottomOfJump = False
        newZ = z + self.toonVelocity * self.stepDT
        if newZ > self.topHeight:
            self.topHeight = newZ
            if self.doJellyBeans:
                self.collectJellyBeans(newZ)
        if topOfJump:
            self.lastPeak = newZ
            if newZ >= self.minHeightForText:
                self.heightTextInterval.start()
        if topOfJump:
            if newZ > self.trampHeight + 20.0:
                self.b_requestAnim('Falling')
            elif self.animFSM.state == 'Jump':
                self.b_requestAnim('Falling')
        if newZ <= self.trampHeight and z > self.trampHeight:
            if self.animFSM.state == 'Falling':
                self.b_requestAnim('Land')
            elif self.animFSM.state != 'Neutral':
                self.b_requestAnim('Neutral')
        if bottomOfJump and a > self.boingThreshold:
            base.playSfx(self.boingSound)
        return (newZ, a)

    def collectJellyBeans(self, z):
        beansToRemove = []
        for i in self.beansToCollect:
            height = self.beanDetails[i][0]
            if height <= z:
                beansToRemove.append(i)

        if len(beansToRemove) > 0:
            base.playSfx(self.jellyBeanSound)
            self.numBeansCollected += len(beansToRemove)
            self.b_removeBeans(beansToRemove)

    def remoteUpdateTask(self, task):
        if self.toon != None and not self.toon.isEmpty():
            z = self.toon.getZ()
            if z <= self.trampHeight:
                self.surface.setZ(z)
            else:
                self.surface.setZ(self.trampHeight)
        return Task.cont

    def poofBean(self, bean, beanAnim):
        if bean == None:
            self.notify.warning('poofBean, returning immediately as bean is None')
            return
        if bean.isEmpty():
            self.notify.warning('poofBean, returning immediately as bean is empty')
            return
        currentAlpha = bean.getColorScale()[3]
        currentScale = bean.getScale()
        poofAnim = Sequence(Parallel(LerpFunc(bean.setAlphaScale, fromData=currentAlpha, toData=0.0, duration=0.25), LerpFunc(bean.setScale, fromData=currentScale, toData=currentScale * 5.0, duration=0.25)), Func(bean.stash), Func(beanAnim.finish), Func(bean.setAlphaScale, currentAlpha), Func(bean.setScale, currentScale))
        poofAnim.start()
        return

    def _showFlashMessage(self, message):
        if self.isDisabled():
            return
        if self.flashTextInterval is not None and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        self.flashText.setText(message)
        self.flashText.setAlphaScale(1.0)
        self.flashText.unstash()
        return

    def _hideFlashMessage(self, duration = 0.0):
        if self.isDisabled():
            pass
        self.flashTextInterval = Sequence(Wait(duration), LerpFunc(self.flashText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), Func(self.flashText.stash))
        self.flashTextInterval.start()

    def flashMessage(self, message, duration = 0.5):
        self._showFlashMessage(message)
        self._hideFlashMessage(duration)
示例#60
0
class World(DirectObject):
    #class World, extends DirectObject, builds the world to play the game

###################### INITIALIZATIONS #########################################
    def __init__(self):

        mySplashScreen = SplashScreen()
        mySplashScreen.loading()
        mySplashScreen.introduction()
        self.promptMode()

        self.turnWallNotification()

        ##### Creating Scene #####
        self.createBackground()
        self.loadWallModel()
        self.loadBallModel()
        self.setCamera()
        self.createLighting()

        ##### Create Controls #####
        self.createKeyControls()
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "drop":0}

        ##### Task Manager #####
        timer = 0.2
        taskMgr.doMethodLater(timer, self.traverseTask, "tsk_traverse")
            #scans for collisions every 0.2 seconds
        taskMgr.add(self.move,"moveTask")
            #constant smooth movement

        ##### Collisions #####
        self.createBallColliderModel()
        self.disableForwardMovement = False
        self.disableBackwardMovement = False
        self.disableLeftMovement = False
        self.disableRightMovement = False

        ##### Game state variables #####
        self.isMoving = False
        self.isDropping = False 
        self.camAngle = math.pi/2
        self.direction = "W" #constant; does not change with relativity
        self.drop = False

        self.levelHeight = 2.1
        self.level = 0
        self.maxLevel = 6
        self.currentHeight = 13.302
        self.cameraHeight = 0.2
        self.mode = None
        self.timer = ""

        ##### Views #####
        self.xray_mode = False
        self.collision_mode = False
        self.wireframe = False

        ##### On-Screen Text #####
        self.title = addTitle("aMAZEing")
        self.instructions = OnscreenText(text="[ i ]: Toggle Instructions", 
                style=1, fg=(0, 0, 0, 1), pos=(1.3, 0.95), 
                align=TextNode.ARight, scale=0.05)
        self.instr = []
        self.messages = []
        self.levelText = OnscreenText(text= "Level = " + str(self.level), 
                style=1, fg=(0, 0, 0, 1), pos=(-1.3, -0.95), 
                align=TextNode.ALeft, scale=0.07)
        self.directionText = OnscreenText(text="Direction = " + self.direction,
                style=1, fg=(0, 0, 0, 1), pos=(-1.3, -0.85),
                align=TextNode.ALeft, scale=0.07)

        self.timerText = OnscreenText(text= self.timer, 
                style=1, fg=(1, 1, 1, 1), pos=(1.3, 0.85), 
                align=TextNode.ARight, scale=0.07)
    
    def setKey(self, key, value):
        #records the state of the arrow keys
        self.keyMap[key] = value

    ###################### Onscreen Text #######################################

    def postInstructions(self):
        #posts the instructions onto the screen

        inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.instr.append(inst1)
        inst2 = addInstructions(0.90,  "[Left Arrow]: Turn Left")
        self.instr.append(inst2)
                               
        inst3 = addInstructions(0.85, "[Right Arrow]: Turn Right")
        self.instr.append(inst3)
                                
        inst4 = addInstructions(0.80, "[Up Arrow]: Move Ball Forward")
        self.instr.append(inst4)
                                
        inst5 = addInstructions(0.75,  "[Down Arrow]: Move Ball Backwards")
        self.instr.append(inst5)
                               
        inst6 = addInstructions(0.70,
                            "[Space]: Drop Levels (if level drop is availale)")
        self.instr.append(inst6)
                               
        inst7 = addInstructions(0.60,  "[x]: Toggle XRay Mode")
        self.instr.append(inst7)
                               
        inst8 = addInstructions(0.55, "[c]: Toggle Collision Mode")
        self.instr.append(inst8)
                                
        inst9 = addInstructions(0.50, "[z]: Toggle Wireframe")
        self.instr.append(inst9)

        inst10 = OnscreenText(text='''Hello!
        Welcome to aMAZEing!
        You are this sphere,
        and your goal is to find the exit of the maze! Each level
        of the maze has a hole you can drop through, to move on to the
        next level. This maze has six levels and each maze is a 12x12.
        If you chose timer mode, you have 5 minutes to finish the maze,
        or else you lose.
        Good luck! You're aMAZEing :)''', style = 1, 
                fg=(0, 0, 0, 1), pos=(0, -.1), align=TextNode.ACenter, scale=0.07)
        self.instr.append(inst10)

    def deleteInstructions(self):
        #deletes onscreen instructions
        for instr in self.instr:
            instr.destroy()

    def addNotification(self, txt):
        #adds a notification to the screen
        y = 0.9
        tex = OnscreenText(text=txt, style=1, fg= (0, 0, 0, 1), pos=(0, y))
        self.messages.append(tex)

    def deleteNotifications(self):
        #deletes all on-screen notifications
        for msg in self.messages:
            msg.destroy()

    def updateLevelText(self):
        #updates the level text
        self.levelText.destroy()

        levelTextPos = (-1.3, -0.95)
        levelScale = 0.07

        self.levelText = OnscreenText(text= "Level = " + str(self.level), 
                style=1, fg=(0, 0, 0, 1), pos=levelTextPos, 
                align=TextNode.ALeft, scale=levelScale)

    def updateDirectionText(self):
        #updates the direction text on the screen
        self.directionText.destroy()

        directionTextPos = (-1.3, -0.85)
        directionScale = 0.07

        self.directionText = OnscreenText(text="Direction = " + self.direction,
                style=1, fg=(0, 0, 0, 1), pos=directionTextPos,
                align=TextNode.ALeft, scale=directionScale)

    def updateTimerText(self):
        #updates timer on screen
        self.timerText.destroy()

        timerTextPos = (1.3, 0.85)
        timerScale = 0.07

        if self.mode == "timer":
            self.timerText = OnscreenText(text= self.timer, 
                style=1, fg=(1, 1, 1, 1), pos=timerTextPos, 
                align=TextNode.ARight, scale=timerScale)

    def turnWallNotification(self):
        #give a notification sequence at the beginning
        notificationSeq = Sequence()
        notificationSeq.append(Func(addNotification,"""
        If you just see a blank color,
        it means you are facing a wall :)"""))
        notificationSeq.append(Wait(8))
        notificationSeq.append(Func(deleteNotifications))
        notificationSeq.start()

    def promptMode(self):
        #prompts for the mode
        modeScreen = SplashScreen()
        modeScreen.mode()

    def setMode(self, mode):
        #sets the mode of the game
        self.mode = mode
        
        if self.mode == "timer":
            self.setTimer()

    ###################### Initialization Helper Functions #####################

    def createBackground(self):
        #black feautureless space
        base.win.setClearColor(Vec4(0,0,0,1))

    def loadWallModel(self):
        #loads the wall model (the maze) 
        wallScale = 0.3
        wallModelName = self.randomWallModel()
            #randomly select a maze

        self.wallModel = loader.loadModel(wallModelName)
        self.wallModel.setScale(wallScale)
        self.wallModel.setPos(0, 0, 0)
        self.wallModel.setCollideMask(BitMask32.allOff())
        self.wallModel.reparentTo(render)

        ### Setting Texture ###
        texScale = 0.08
        self.wallModel.setTexGen(TextureStage.getDefault(),
                                   TexGenAttrib.MWorldNormal)
        self.wallModel.setTexProjector(TextureStage.getDefault(),
                                         render, self.wallModel)
        self.wallModel.setTexScale(TextureStage.getDefault(), texScale)
        tex = loader.load3DTexture('/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/wallTex/wallTex_#.png')
        self.wallModel.setTexture(tex)

        #creating visual geometry collision
        self.wallModel.setCollideMask(BitMask32.bit(0))

    def randomWallModel(self):
        #generates a random wall in the library of mazes that were 
        #randomly generated by the Blender script "mazeGenerator"
        #and exported to this computer
        numMazes = 10

        name = str(random.randint(0, numMazes))
            #randomly selects a number saved in the computer

        path = "/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/mazeModels/maze"

        path += name 

        return path
        
    def loadBallModel(self):
        #loads the character, a ball model

        #ballModelStartPos = (-8, -8, 0.701) #THIS IS THE END
        ballModelStartPos = (8, 8, 13.301) #level 0 
        ballScale = 0.01
        self.ballModel = loader.loadModel("/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/ball")
        self.ballModel.reparentTo(render)
        self.ballModel.setScale(ballScale)
        self.ballModel.setPos(ballModelStartPos)


        ### Setting ball texture ###
        texScale = 0.08
        self.ballModel.setTexGen(TextureStage.getDefault(),
                                   TexGenAttrib.MWorldPosition)
        self.ballModel.setTexProjector(TextureStage.getDefault(), 
                                         render, self.ballModel)
        self.ballModel.setTexScale(TextureStage.getDefault(), texScale)
        tex = loader.load3DTexture('/Users/jianwei/Documents/School/Freshman/Semester1/15-112/TERMPROJECT/Project/ballTex/ballTex_#.png')
        self.ballModel.setTexture(tex)

    def setCamera(self):
        #sets up the initial camera location
        #camera will follow the sphere 
        followLength = 2
        camHeight = 0.2

        base.disableMouse()
        base.camera.setPos(self.ballModel.getX(),
                                self.ballModel.getY() - followLength,
                                self.ballModel.getZ() + camHeight)
        base.camLens.setNear(0.4)

        #creates a floater object - will look at the floater object 
        #above the sphere, so you can get a better view
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

    def createKeyControls(self):
        #creates the controllers for the keys
        #event handler
        #describes what each key does when pressed and unpressed

        self.accept("escape", sys.exit)

        self.accept("arrow_left", self.turnLeft)
        self.accept("arrow_right", self.turnRight)
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_down", self.setKey, ["backward",1])
        self.accept("space", self.nowDropping)

        #unpressed event handlers
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("arrow_down-up", self.setKey, ["backward",0])
        self.accept("space_up", self.setKey, ["drop", 0])

        #views
        self.accept('x', self.toggle_xray_mode)
        self.accept('c', self.toggle_collision_mode)
        self.accept('z', self.toggle_wireframe)

        #information
        self.accept('i', self.postInstructions)
        self.accept('i-up', self.deleteInstructions)

        #restart
        self.accept('r', self.restart)

        #modes
        self.accept("t", self.setMode, ["timer"])
        self.accept("m", self.setMode, ["marathon"])

    def createBallColliderModel(self):
        #creates the collider sphere around the ball
        cSphereRad = 9.9
        self.cTrav = CollisionTraverser() #moves over all possible collisions

        self.ballModelSphere = CollisionSphere(0, 0, 0, cSphereRad)
            #collision mesh around ball is a simple sphere
        self.ballModelCol = CollisionNode('ballModelSphere')
        self.ballModelCol.addSolid(self.ballModelSphere)
        self.ballModelCol.setFromCollideMask(BitMask32.bit(0))
        self.ballModelCol.setIntoCollideMask(BitMask32.allOff())
        self.ballModelColNp = self.ballModel.attachNewNode(self.ballModelCol)
        self.ballModelGroundHandler = CollisionHandlerQueue()
            #collision handler queue stores all collision points
        self.cTrav.addCollider(self.ballModelColNp, self.ballModelGroundHandler)

    def createLighting(self):
        #creates lighting for the scene
        aLightVal = 0.3
        dLightVal1 = -5
        dLightVal2 = 5

        #set up the ambient light
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1))
        ambientLight1 = AmbientLight("ambientLight1")
        ambientLight1.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1))
        ambientLight2 = AmbientLight("ambientLight2")
        ambientLight2.setColor(Vec4(aLightVal, aLightVal, aLightVal, 1))

        #sets a directional light
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(dLightVal1, dLightVal1, dLightVal1))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(0, 0, 0, 1))

        #sets a directional light
        directionalLight1 = DirectionalLight("directionalLight2")
        directionalLight1.setDirection(Vec3(dLightVal2, dLightVal1, dLightVal1))
        directionalLight1.setColor(Vec4(1, 1, 1, 1))
        directionalLight1.setSpecularColor(Vec4(1, 1, 1, 1))


        #attaches lights to scene
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(ambientLight1))
        render.setLight(render.attachNewNode(ambientLight1))
        render.setLight(render.attachNewNode(directionalLight))
        render.setLight(render.attachNewNode(directionalLight1))

###################### COLLISION DETECTION #####################################

    def traverseTask(self, task=None):
        # handles collisions with collision handers and a 
        # collision queue
        # essentially checks region of potential collision for collisions
        # and stops the ball if a collision is triggered
        # called by task manager
        self.ballModelGroundHandler.sortEntries()
        for i in range(self.ballModelGroundHandler.getNumEntries()):
            entry = self.ballModelGroundHandler.getEntry(i)

            if self.drop == True:
                #we cant drop in this situation
                self.ballModel.setZ(self.currentHeight)

                dropFailWait = 4
                dropFailSeq = Sequence()
                dropFailSeq.append(Func(addNotification,"Whoops! You can't drop here!"))
                dropFailSeq.append(Wait(dropFailWait))
                dropFailSeq.append(Func(deleteNotifications))
                dropFailSeq.start()

                self.drop = False

            elif self.direction == "N":
                self.northDisableMovements()

            elif self.direction == "S":
                self.southDisableMovements()

            elif self.direction == "E":
                self.eastDisableMovements()

            elif self.direction == "W":
                self.westDisableMovements()

            if task: return task.cont #exit task

        # If there are no collisions
        
        if task: return task.cont

    def northDisableMovements(self):
        #disables movements when direction is north
        if self.keyMap["forward"] != 0: #if the ball was moving foward
            self.disableForwardMovement = True #disable forward movement
        if self.keyMap["backward"] != 0:
            self.disableBackwardMovement = True

    def southDisableMovements(self):
        #disables movements when direction is south
        if self.keyMap["forward"] != 0: 
            self.disableBackwardMovement = True 
        if self.keyMap["backward"] != 0:
            self.disableForwardMovement = True

    def eastDisableMovements(self):
        #disables movements when direction is east
        if self.keyMap["forward"] != 0: 
            self.disableRightMovement = True 
        if self.keyMap["backward"] != 0:
            self.disableLeftMovement = True

    def westDisableMovements(self):
        #disables movements when direction is west
        if self.keyMap["forward"] != 0: 
            self.disableLeftMovement = True 
        if self.keyMap["backward"] != 0:
            self.disableRightMovement = True

    def checkCollisions(self):
        #checks for collisions
        self.cTrav.traverse(render)

    def enableAllWalls(self):
        #enables all walls by disabling all the disable wall functions
        self.disableLeftMovement = False
        self.disableRightMovement = False 
        self.disableForwardMovement = False
        self.disableBackwardMovement = False

    def inCollision(self):
        #return true if we are in a collision right now, false otherwise
        if (self.disableForwardMovement == True
            or self.disableBackwardMovement == True 
            or self.disableRightMovement == True 
            or self.disableLeftMovement):
            return True
        return False

    def checkForWin(self):
        #checks for a win, toggles win splash sceen if we win
        yLoc = self.ballModel.getY()
        exitBound = -9.1

        if yLoc < exitBound: 
            winScreen = SplashScreen()
            winScreen.win()

        if self.mode == "timer":
            self.checkForTimerLoss()

    def checkForTimerLoss(self):
        #checks to see the time, will lose if past 5 minutes
        
        if self.timer == "0:05:00":
            loseScreen = SplashScreen()
            loseScreen.lose()

###################### MOVEMENTS ###############################################

    def move(self, task):
        # Accepts arrow keys to move the player front and back
        # Also deals with grid checking and collision detection

        step = 0.03

        #movement animation
        self.movementAnimation(step)
        #rotation animation
        self.rotationAnimation()

        base.camera.setX(self.ballModel.getX() + math.sin(self.camAngle))
        base.camera.setY(self.ballModel.getY() + math.cos(self.camAngle))

        self.resetCamDist()
        self.checkCollisions()
        self.lookAtFloater()

        self.checkForWin()

        return task.cont

    def resetCamDist(self):
        #resets the camera distance to a specific distance
        #keeps distance relatively constant
        camFarDist = 0.75
        camCloseDist = 0.7

        camvec = self.ballModel.getPos() - base.camera.getPos()
            #vector between ball and camera
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()

        if (camdist > camFarDist):
            base.camera.setPos(base.camera.getPos() + 
                                    camvec*(camdist-camFarDist))
            camdist = camFarDist

        if (camdist < camCloseDist):
            base.camera.setPos(base.camera.getPos() -
                                    camvec*(camCloseDist-camdist))
            camdist = camCloseDist

        base.camera.lookAt(self.ballModel)

    def lookAtFloater(self):
        #looks at the floater above the sphere
        floaterHeight = 0.23
        self.floater.setPos(self.ballModel.getPos())
        self.floater.setZ(self.ballModel.getZ() + floaterHeight)
        base.camera.lookAt(self.floater)

    ####################### Movement Animation #################################

    def ballIsMoving(self):
        #notes if the ball is moving or not with self.isMoving variable
        if (self.keyMap["forward"]!=0) or (self.keyMap["backward"]!=0):
            if self.isMoving == False:
                self.isMoving = True

        elif self.keyMap["forward"] == 0 and self.keyMap["backward"] == 0:
            self.isMoving = False

    def movementAnimation(self, step):
        #describes the movement animation
        if self.drop == True:
            self.dropMovementAnimation(step)
        elif self.direction == "N":
            self.northMovementAnimation(step)

        elif self.direction == "S":
            self.southMovementAnimation(step)

        elif self.direction == "E":
            self.eastMovementAnimation(step)

        elif self.direction == "W":
            self.westMovementAnimation(step)

    def northMovementAnimation(self, step):
        #describes animation when direction is north
        if (self.keyMap["forward"]!=0):
            #if you are pressing forward
            if self.disableForwardMovement == False:
                #if you are just moving through space...
                self.ballModel.setY(self.ballModel.getY() + step)
            if self.disableBackwardMovement == True:
                #if you had moved backwards into a wall
                #and you want to move forward again
                self.ballModel.setY(self.ballModel.getY() + step)
                self.disableBackwardMovement = False
                

        if (self.keyMap["backward"]!=0):
            #if you are pressing backwards
            if self.disableBackwardMovement == False:
                #if you are just moving backwards through space...
                self.ballModel.setY(self.ballModel.getY() - step)
            if self.disableForwardMovement == True:
                #if you had moved forward into a wall
                #and want to back away from the wall
                self.ballModel.setY(self.ballModel.getY() - step)
                self.disableForwardMovement = False        

    def southMovementAnimation(self, step):
        #describes animation when direction is north
        #same relative set of animations to northMovementAnimation
        #but opposite
        if (self.keyMap["forward"]!=0):
            if self.disableBackwardMovement == False:
                self.ballModel.setY(self.ballModel.getY() - step)
            if self.disableForwardMovement == True:
                self.ballModel.setY(self.ballModel.getY() - step)
                self.disableForwardMovement = False

        if (self.keyMap["backward"]!=0):
            if self.disableForwardMovement == False:
                self.ballModel.setY(self.ballModel.getY() + step)
            if self.disableBackwardMovement == True:
                self.ballModel.setY(self.ballModel.getY() + step)
                self.disableBackwardMovement = False        

    def eastMovementAnimation(self, step):
        #describes animation when direction is east
        #same relative as north and south movement animations
        #but relative to the x axis
        #and disabling/enabling right and left movement at collisions
        if (self.keyMap["forward"]!=0):
            if self.disableRightMovement == False:
                self.ballModel.setX(self.ballModel.getX() + step)
            if self.disableLeftMovement == True:
                self.ballModel.setX(self.ballModel.getX() + step)
                self.disableLeftMovement = False

        if (self.keyMap["backward"]!=0):
            if self.disableLeftMovement == False:
                self.ballModel.setX(self.ballModel.getX() - step)
            if self.disableRightMovement == True:
                self.ballModel.setX(self.ballModel.getX() - step)
                self.disableRightMovement = False

    def westMovementAnimation(self, step):
        #describes animation when direction is west
        #relatively same animations as the east movement animations
        #exact opposite
        if (self.keyMap["forward"]!=0):
            if self.disableLeftMovement == False:
                self.ballModel.setX(self.ballModel.getX() - step)
            if self.disableRightMovement == True:
                self.ballModel.setX(self.ballModel.getX() - step)
                self.disableRightMovement = False

        if (self.keyMap["backward"]!=0):
            if self.disableRightMovement == False:
                self.ballModel.setX(self.ballModel.getX() + step)
            if self.disableLeftMovement == True:
                self.ballModel.setX(self.ballModel.getX() + step)
                self.disableLeftMovement = False

    def turnRight(self):
        #turns right in the animation

        #uses an interval to slowly rotate camera around
        initial = self.camAngle
        final = self.camAngle + math.pi/2

        #turn animation
        turnTime = 0.2
        turnRightSeq = Sequence()
        turnRightSeq.append(LerpFunc(self.changeCamAngle, turnTime, initial,
                                                         final, 'easeInOut'))
        turnRightSeq.start()

        self.setKey("right", 1) #notes that the right key is pressed

        #changes the direction right, based on current direction
        if self.direction == "N":
            self.direction = "E"
        elif self.direction == "E":
            self.direction = "S"
        elif self.direction == "S":
            self.direction = "W"
        else:
            self.direction = "N"

        #when you turn, all the collision disablements should be True
        #just checking
        #self.enableAllWalls()

        #update the label
        self.updateDirectionText()

    def turnLeft(self):
        #turns left

        initial = self.camAngle
        final = self.camAngle - math.pi/2

        #turn animation
        turnTime = 0.2
        turnRightSeq = Sequence()
        turnRightSeq.append(LerpFunc(self.changeCamAngle, turnTime, initial,
                                                         final, 'easeInOut'))
        turnRightSeq.start()


        self.setKey("left", 1) #notes that left key is pressed

        #changes the direction left, based on current direction
        if self.direction == "N":
            self.direction = "W"
        elif self.direction == "W":
            self.direction = "S"
        elif self.direction == "S":
            self.direction = "E"
        else:
            self.direction = "N"

        #when you turn, all the collision disablements should be True
        #just checking
        #self.enableAllWalls()

        #update the label
        self.updateDirectionText()

    def changeCamAngle(self, angle):
        #changes the camAngle to angle
        self.camAngle = angle

    def dropMovementAnimation(self, step):
        #describes movement when drop is hit

        a = 0.1

        if self.keyMap["drop"] != 0:
            if self.ballModel.getZ() > self.currentHeight - self.levelHeight+ a:
                self.ballModel.setZ(self.ballModel.getZ() - step)
            else:
                self.currentHeight -= self.levelHeight
                self.level += 1
                self.updateLevelText()
                self.drop = False
                base.camera.setZ(self.ballModel.getZ() + self.cameraHeight)

    def nowDropping(self):
        #toggles isDropping boolean
        self.drop = True
        self.setKey("drop", 1)
        
    ################## Ball Rotation Animation #################################

    def rotationAnimation(self):
        #describes the rotation movement of sphere
        self.ballIsMoving()
        speed=300
        inCollision = self.inCollision()

        if self.isMoving and not inCollision:
            if self.direction == "N":
                self.northRotationAnimation(speed)
            if self.direction == "S":
                self.southRotationAnimation(speed)
            if self.direction == "E":
                self.eastRotationAnimation(speed)
            if self.direction == "W":
                self.westRotationAnimation(speed)

    def northRotationAnimation(self, speed):
        #describes the rotation animation if direction is north
        if self.keyMap["forward"] != 0:
            self.ballModel.setP(self.ballModel.getP()-speed*globalClock.getDt())
        elif self.keyMap["backward"] != 0:
            self.ballModel.setP(self.ballModel.getP()+speed*globalClock.getDt())

    def southRotationAnimation(self, speed):
        #describes the rotaiton animation if the direction is south
        if self.keyMap["backward"] != 0:
            self.ballModel.setP(self.ballModel.getP()-speed*globalClock.getDt())
        elif self.keyMap["forward"] != 0:
            self.ballModel.setP(self.ballModel.getP()+speed*globalClock.getDt())

    def eastRotationAnimation(self, speed):
        #describes the rotation animation if the direction is east
        if self.keyMap["backward"] != 0:
            self.ballModel.setR(self.ballModel.getR()-speed*globalClock.getDt())
        elif self.keyMap["forward"] != 0:
            self.ballModel.setR(self.ballModel.getR()+speed*globalClock.getDt())

    def westRotationAnimation(self, speed):
        #describes the rotation animation if the direction is west
        if self.keyMap["forward"] != 0:
            self.ballModel.setR(self.ballModel.getR()-speed*globalClock.getDt())
        elif self.keyMap["backward"] != 0:
            self.ballModel.setR(self.ballModel.getR()+speed*globalClock.getDt())

###################### VIEWS ###################################################

    def toggle_xray_mode(self):
        #Toggle X-ray mode on and off.
        #Note: slows down program considerably
        xRayA = 0.5
        self.xray_mode = not self.xray_mode
        if self.xray_mode:
            self.wallModel.setColorScale((1, 1, 1, xRayA))
            self.wallModel.setTransparency(TransparencyAttrib.MDual)
        else:
            self.wallModel.setColorScaleOff()
            self.wallModel.setTransparency(TransparencyAttrib.MNone)

    def toggle_collision_mode(self):
        #Toggle collision mode on and off
        #Shows visual representation of the collisions occuring
        self.collision_mode = not self.collision_mode
        if self.collision_mode == True:
            # Note: Slows the program down considerably
            self.cTrav.showCollisions(render)
        else:
            self.cTrav.hideCollisions()

    def toggle_wireframe(self):
        #toggles wireframe view
        self.wireframe = not self.wireframe
        if self.wireframe:
            self.wallModel.setRenderModeWireframe()
        else:
            self.wallModel.setRenderModeFilled()

##################### RESTART ##################################################
    
    def restart(self):
        #restarts the game
        loading = SplashScreen()
        loading.loading()
        self.reset()

    def reset(self):
        #resets the maze, resets the location of the character

        #removes all notes
        self.wallModel.removeNode()
        self.ballModel.removeNode()

        #resets notes
        self.loadWallModel()
        self.loadBallModel()
        self.createBallColliderModel()
        self.resetCamDist()

        #resets timers
        taskMgr.remove("timerTask")
        self.timer = ""
        self.timerText.destroy()

        self.promptMode()

#################### TIMER #####################################################

    def setTimer(self):
        #code from panda.egg user on Panda3D, 
        #"How to use Timer, a small example maybe?" forum
        #creates a timer
        self.timer = DirectLabel(pos=Vec3(1, 0.85),scale=0.08)

        taskMgr.add(self.timerTask, "timerTask")

    def dCharstr(self, theString):
        #code from panda.egg user on Panda3D, 
        #"How to use Timer, a small example maybe?" forum
        #turns time string into a readable clock string
        if len(theString) != 2:
            theString = '0' + theString
        return theString

    def timerTask(self, task):
        #code from panda.egg user on Panda3D, 
        #"How to use Timer, a small example maybe?" forum
        #task for resetting timer in timer mode
        secondsTime = int(task.time)
        minutesTime = int(secondsTime/60)
        hoursTime = int(minutesTime/60)
        self.timer = (str(hoursTime) + ':' 
                            + self.dCharstr(str(minutesTime%60)) + ':' 
                            + self.dCharstr(str(secondsTime%60)))

        self.updateTimerText()
        
        return Task.cont