def _loadAndBuildMazeModel(self, flatten = False):
        self.getMazeData()
        self._model = NodePath('CogdoMazeModel')
        levelModel = CogdoUtil.loadMazeModel('level')
        self.quadrants = []
        quadrantUnitSize = int(self.quadrantSize * self.cellWidth)
        frameActualSize = self.frameWallThickness * self.cellWidth
        size = quadrantUnitSize + frameActualSize
        halfWidth = int(self.width / 2)
        halfHeight = int(self.height / 2)
        i = 0
        for y in range(self.height):
            for x in range(self.width):
                ax = (x - halfWidth) * size
                ay = (y - halfHeight) * size
                extension = ''
                if hasattr(getBase(), 'air'):
                    extension = '.bam'
                filepath = self.quadrantData[i][0] + extension
                angle = self.quadrantData[i][2]
                m = self._createQuadrant(filepath, i, angle, quadrantUnitSize)
                m.setPos(ax, ay, 0)
                m.reparentTo(self._model)
                self.quadrants.append(m)
                i += 1

        quadrantHalfUnitSize = quadrantUnitSize * 0.5
        barrierModel = CogdoUtil.loadMazeModel('grouping_blockerDivider').find('**/divider')
        y = 3
        for x in range(self.width):
            if x == (self.width - 1) / 2:
                continue
            ax = (x - halfWidth) * size
            ay = (y - halfHeight) * size - quadrantHalfUnitSize - (self.cellWidth - 0.5)
            b = NodePath('barrier')
            barrierModel.instanceTo(b)
            b.setPos(ax, ay, 0)
            b.reparentTo(self._model)

        offset = self.cellWidth - 0.5
        for x in (0, 3):
            for y in range(self.height):
                ax = (x - halfWidth) * size - quadrantHalfUnitSize - frameActualSize + offset
                ay = (y - halfHeight) * size
                b = NodePath('barrier')
                barrierModel.instanceTo(b)
                b.setPos(ax, ay, 0)
                b.setH(90)
                b.reparentTo(self._model)

            offset -= 2.0

        barrierModel.removeNode()
        levelModel.getChildren().reparentTo(self._model)
        for np in self._model.findAllMatches('**/*lightCone*'):
            CogdoUtil.initializeLightCone(np, 'fixed', 3)

        if flatten:
            self._model.flattenStrong()
        return self._model
    def _loadAndBuildMazeModel(self, flatten = False):
        self.getMazeData()
        self._model = NodePath('CogdoMazeModel')
        levelModel = CogdoUtil.loadMazeModel('level')
        self.quadrants = []
        quadrantUnitSize = int(self.quadrantSize * self.cellWidth)
        frameActualSize = self.frameWallThickness * self.cellWidth
        size = quadrantUnitSize + frameActualSize
        halfWidth = int(self.width / 2)
        halfHeight = int(self.height / 2)
        i = 0
        for y in range(self.height):
            for x in range(self.width):
                ax = (x - halfWidth) * size
                ay = (y - halfHeight) * size
                extension = ''
                if hasattr(getBase(), 'air'):
                    extension = '.bam'
                filepath = self.quadrantData[i][0] + extension
                angle = self.quadrantData[i][2]
                m = self._createQuadrant(filepath, i, angle, quadrantUnitSize)
                m.setPos(ax, ay, 0)
                m.reparentTo(self._model)
                self.quadrants.append(m)
                i += 1

        quadrantHalfUnitSize = quadrantUnitSize * 0.5
        barrierModel = CogdoUtil.loadMazeModel('grouping_blockerDivider').find('**/divider')
        y = 3
        for x in range(self.width):
            if x == (self.width - 1) / 2:
                continue
            ax = (x - halfWidth) * size
            ay = (y - halfHeight) * size - quadrantHalfUnitSize - (self.cellWidth - 0.5)
            b = NodePath('barrier')
            barrierModel.instanceTo(b)
            b.setPos(ax, ay, 0)
            b.reparentTo(self._model)

        offset = self.cellWidth - 0.5
        for x in (0, 3):
            for y in range(self.height):
                ax = (x - halfWidth) * size - quadrantHalfUnitSize - frameActualSize + offset
                ay = (y - halfHeight) * size
                b = NodePath('barrier')
                barrierModel.instanceTo(b)
                b.setPos(ax, ay, 0)
                b.setH(90)
                b.reparentTo(self._model)

            offset -= 2.0

        barrierModel.removeNode()
        levelModel.getChildren().reparentTo(self._model)
        for np in self._model.findAllMatches('**/*lightCone*'):
            CogdoUtil.initializeLightCone(np, 'fixed', 3)

        if flatten:
            self._model.flattenStrong()
        return self._model
예제 #3
0
    def test_blocks(self):
        store = DNAStorage()
        block1 = (
            4269,  # block_number
            "libpandadna",  # title
            "",  # article
            "",  # bldg_type
            1337  # zone_id
        )
        block2 = (
            1337,  # block_number
            "Visual Studio 2010",  # title
            "",  # article
            "",  # bldg_type
            4269  # zone_id
        )
        block3 = (
            1000,  # block_number
            "C++ reader",  # title
            "",  # article
            "",  # bldg_type
            4269  # zone_id
        )

        store.storeBlock(*block1)
        store.storeBlock(*block2)
        store.storeBlock(*block3)

        door1 = NodePath('block-1000')
        door1.setPos(5, 5, 10)
        door1.setH(180)
        store.storeBlockDoor(1000, door1)

        self.assertEqual(store.getNumBlockNumbers(), 3)

        # Test an invalid block number
        self.assertEqual(store.getZoneFromBlockNumber(100), 0)
        self.assertEqual(store.getZoneFromBlockNumber(1000), 4269)
        self.assertEqual(store.getZoneFromBlockNumber(1337), 4269)
        self.assertEqual(store.getZoneFromBlockNumber(4269), 1337)
        self.assertEqual(store.getTitleFromBlockNumber(1000), "C++ reader")
        self.assertEqual(store.getTitleFromBlockNumber(1337),
                         "Visual Studio 2010")
        self.assertEqual(store.getTitleFromBlockNumber(4269), "libpandadna")
        self.assertEqual(store.getBlockNumberAt(0), 4269)
        self.assertEqual(store.getBlockNumberAt(1), 1337)
        self.assertEqual(store.getBlockNumberAt(2), 1000)
        self.assertEqual(store.getDoorPosHprFromBlockNumber(1000), door1)
        self.assertTrue(store.getDoorPosHprFromBlockNumber(1337).isEmpty())

        store.resetBlockNumbers()
        store.resetBlockZones()

        self.assertEqual(store.getTitleFromBlockNumber(1000), "")
        self.assertEqual(store.getTitleFromBlockNumber(1337), "")
        self.assertEqual(store.getTitleFromBlockNumber(4269), "")
예제 #4
0
    def test_blocks(self):
        store = DNAStorage()
        block1 = (
                  4269,                   # block_number
                  "libpandadna",          # title
                  "",                     # article
                  "",                     # bldg_type
                  1337                    # zone_id
        )
        block2 = (
                  1337,                   # block_number
                  "Visual Studio 2010",   # title
                  "",                     # article
                  "",                     # bldg_type
                  4269                    # zone_id
        )
        block3 = (
                  1000,                   # block_number
                  "C++ reader",           # title
                  "",                     # article
                  "",                     # bldg_type
                  4269                    # zone_id
        )

        store.storeBlock(*block1)
        store.storeBlock(*block2)
        store.storeBlock(*block3)

        door1 = NodePath('block-1000')
        door1.setPos(5, 5, 10)
        door1.setH(180)
        store.storeBlockDoor(1000, door1)

        self.assertEqual(store.getNumBlockNumbers(), 3)

        # Test an invalid block number
        self.assertEqual(store.getZoneFromBlockNumber(100), 0)
        self.assertEqual(store.getZoneFromBlockNumber(1000), 4269)
        self.assertEqual(store.getZoneFromBlockNumber(1337), 4269)
        self.assertEqual(store.getZoneFromBlockNumber(4269), 1337)
        self.assertEqual(store.getTitleFromBlockNumber(1000), "C++ reader")
        self.assertEqual(store.getTitleFromBlockNumber(1337), "Visual Studio 2010")
        self.assertEqual(store.getTitleFromBlockNumber(4269), "libpandadna")
        self.assertEqual(store.getBlockNumberAt(0), 4269)
        self.assertEqual(store.getBlockNumberAt(1), 1337)
        self.assertEqual(store.getBlockNumberAt(2), 1000)
        self.assertEqual(store.getDoorPosHprFromBlockNumber(1000), door1)
        self.assertTrue(store.getDoorPosHprFromBlockNumber(1337).isEmpty())

        store.resetBlockNumbers()
        store.resetBlockZones()

        self.assertEqual(store.getTitleFromBlockNumber(1000), "")
        self.assertEqual(store.getTitleFromBlockNumber(1337), "")
        self.assertEqual(store.getTitleFromBlockNumber(4269), "")
 def setupFoodNodes(self):
     for i in xrange(self.NumFoodNodes):
         newPosIndex = self.NumFoodNodes - 1 - i
         yPos = -(self.beltLength / 2.0) + newPosIndex * self.distBetweenFoodNodes
         newFoodNode = NodePath('foodNode-%d-%d' % (self.index, i))
         newFoodNode.reparentTo(self.beltModel)
         newFoodNode.setPos(0, yPos, self.beltHeight)
         debugFood = None
         if debugFood:
             debugFood.setScale(0.10000000000000001)
             debugFood.reparentTo(newFoodNode)
         
         newFoodNode.setH(180)
         self.foodNodes.append(newFoodNode)
예제 #6
0
 def setupFoodNodes(self):
     for i in xrange(self.NumFoodNodes):
         newPosIndex = self.NumFoodNodes - 1 - i
         yPos = -(self.beltLength /
                  2.0) + newPosIndex * self.distBetweenFoodNodes
         newFoodNode = NodePath('foodNode-%d-%d' % (self.index, i))
         newFoodNode.reparentTo(self.beltModel)
         newFoodNode.setPos(0, yPos, self.beltHeight)
         debugFood = None
         if debugFood:
             debugFood.setScale(0.1)
             debugFood.reparentTo(newFoodNode)
         newFoodNode.setH(180)
         self.foodNodes.append(newFoodNode)
예제 #7
0
 def setupFoodNodes(self):
     """Create the node paths the food will be parented to."""
     assert self.notify.debugStateCall(self)
     # we may later just load this from the belt model
     for i in xrange(self.NumFoodNodes):
         # we want index 0 to be the first one out
         newPosIndex = self.NumFoodNodes - 1 - i
         yPos = -(self.beltLength / 2.0) + (newPosIndex *
                                            self.distBetweenFoodNodes)
         newFoodNode = NodePath('foodNode-%d-%d' % (self.index, i))
         newFoodNode.reparentTo(self.beltModel)
         newFoodNode.setPos(0, yPos, self.beltHeight)
         debugFood = None  # loader.loadModel('models/misc/xyzAxis')
         if debugFood:
             debugFood.setScale(0.1)
             debugFood.reparentTo(newFoodNode)
         # to make the front side of the cans come out of the belt
         newFoodNode.setH(180)
         self.foodNodes.append(newFoodNode)
    def load(self):
        self.arena = loader.loadModel(self.arenaModel)
        self.arena.reparentTo(self.root)
        ground = self.arena.find('**/ground')
        ground.setBin('ground', 1)
        entranceArrows = self.arena.findAllMatches('**/arrowFlat*')
        for arrow in entranceArrows:
            arrow.setBin('ground', 5)

        self.leftEntranceLocator = self.arena.find('**/leftEntrance_locator')
        self.rightEntranceLocator = self.arena.find('**/rightEntrance_locator')
        self.leftExitLocator = self.arena.find('**/leftExit_locator')
        self.rightExitLocator = self.arena.find('**/rightExit_locator')
        self.teamCamPosLocators = (self.arena.find('**/team0CamPos_locator'),
                                   self.arena.find('**/team1CamPos_locator'))
        self.teamCamAimLocators = (self.arena.find('**/team0CamAim_locator'),
                                   self.arena.find('**/team1CamAim_locator'))
        leftTeamLocator = NodePath('TeamLocator-%d' %
                                   PartyGlobals.TeamActivityTeams.LeftTeam)
        leftTeamLocator.reparentTo(self.root)
        leftTeamLocator.setH(90)
        rightTeamLocator = NodePath('TeamLocator-%d' %
                                    PartyGlobals.TeamActivityTeams.RightTeam)
        rightTeamLocator.reparentTo(self.root)
        rightTeamLocator.setH(-90)
        self.teamLocators = (leftTeamLocator, rightTeamLocator)
        self._lengthBetweenEntrances = self.leftEntranceLocator.getY(
        ) - self.rightExitLocator.getY()
        self._skyCollisionsCollection = self.arena.findAllMatches(
            '**/cogPieArena_sky*_collision')
        if len(self._skyCollisionsCollection) > 0:
            self._skyCollisionParent = self._skyCollisionsCollection[
                0].getParent()
        else:
            self._skyCollisionParent = self.arena
        self._wallCollisionsCollection = self.arena.findAllMatches(
            '**/cogPieArena_wall*_collision')
        self._arenaFlagGroups = (self.arena.find('**/flagsL_grp'),
                                 self.arena.find('**/flagsR_grp'))
        self._initArenaDoors()
        self.cogManager = PartyCogManager()
        self.arrows = []
        self.distanceLabels = []
        self.teamColors = list(PartyGlobals.CogActivityColors) + [
            PartyGlobals.TeamActivityStatusColor
        ]
        for i in range(3):
            start = self.arena.find('**/cog%d_start_locator' % (i + 1))
            end = self.arena.find('**/cog%d_end_locator' % (i + 1))
            cog = self.cogManager.generateCog(self.arena)
            cog.setEndPoints(start.getPos(), end.getPos())
            arrow1 = StretchingArrow(self.arena, useColor='orange')
            arrow2 = StretchingArrow(self.arena, useColor='blue')
            arrow1.setZ(0.1)
            arrow2.setZ(0.1)
            self.arrows.append([arrow1, arrow2])
            distanceLabel = self.createDistanceLabel(0, self.teamColors[1])
            distanceLabel[0].stash()
            distanceLabel2 = self.createDistanceLabel(0, self.teamColors[0])
            distanceLabel2[0].stash()
            self.distanceLabels.append([distanceLabel, distanceLabel2])

        self.winText = []
        text1 = self.createText(0, Point3(-0.5, 0.0, -0.5), self.teamColors[1])
        text2 = self.createText(1, Point3(0.5, 0.0, -0.5), self.teamColors[0])
        self.winText.append(text1)
        self.winText.append(text2)
        self.winStatus = self.createText(2, Point3(0.0, 0.0, -0.8),
                                         self.teamColors[0])
        signLocator = self.arena.find('**/eventSign_locator')
        self.activity.sign.setPos(signLocator.getPos(self.root))
        if self.texture:
            textureAlpha = self.texture[:-4] + '_a.rgb'
            reskinTexture = loader.loadTexture(self.texture, textureAlpha)
            self.arena.find('**/center_grp').setTexture(reskinTexture, 100)
            self.arena.find('**/leftSide_grp').setTexture(reskinTexture, 100)
            self.arena.find('**/rightSide_grp').setTexture(reskinTexture, 100)
        self.enable()
예제 #9
0
class PartyCog(FSM):
    notify = directNotify.newCategory("PartyCog")

    HpTextGenerator = TextNode("HpTextGenerator")
    hpText = None
    height = 7

    def __init__(self,
                 parentNode,
                 id,
                 bounceSpeed=3,
                 bounceHeight=1,
                 rotateSpeed=1,
                 heightShift=1,
                 xMoveSpeed=0,
                 xMoveDistance=0,
                 bounceOffset=0):
        self.id = id

        FSM.__init__(self, "PartyCogFSM-%d" % self.id)

        self.showFacingStatus = False
        self.xMoveSpeed = xMoveSpeed
        self.xMoveDistance = xMoveDistance
        self.heightShift = heightShift
        self.bounceSpeed = bounceSpeed
        self.bounceHeight = bounceHeight
        self.rotateSpeed = rotateSpeed
        self.parentNode = parentNode
        self.bounceOffset = bounceOffset
        self.hitInterval = None
        self.kaboomTrack = None
        self.resetRollIval = None
        self.netTimeSentToStartByHit = 0

        self.load()
        self.request("Down")

    def load(self):
        self.root = NodePath("PartyCog-%d" % self.id)
        self.root.reparentTo(self.parentNode)

        path = "phase_13/models/parties/cogPinata_"
        self.actor = Actor(
            path + "actor", {
                "idle": path + "idle_anim",
                "down": path + "down_anim",
                "up": path + "up_anim",
                "bodyHitBack": path + "bodyHitBack_anim",
                "bodyHitFront": path + "bodyHitFront_anim",
                "headHitBack": path + "headHitBack_anim",
                "headHitFront": path + "headHitFront_anim",
            })
        self.actor.reparentTo(self.root)

        self.temp_transform = Mat4()
        self.head_locator = self.actor.attachNewNode("temphead")

        self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75)
        self.bodyColl.setTangible(1)
        self.bodyCollNode = CollisionNode("PartyCog-%d-Body-Collision" %
                                          self.id)
        self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.bodyCollNode.addSolid(self.bodyColl)
        self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode)

        self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5)
        self.headColl.setTangible(1)
        self.headCollNode = CollisionNode("PartyCog-%d-Head-Collision" %
                                          self.id)
        self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.headCollNode.addSolid(self.headColl)
        self.headCollNodePath = self.root.attachNewNode(self.headCollNode)

        # Cog's Left Arm
        self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0)
        self.arm1Coll.setTangible(1)
        self.arm1CollNode = CollisionNode("PartyCog-%d-Arm1-Collision" %
                                          self.id)
        self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.arm1CollNode.addSolid(self.arm1Coll)
        self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode)

        # Cog's Right Arm
        self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0)
        self.arm2Coll.setTangible(1)
        self.arm2CollNode = CollisionNode("PartyCog-%d-Arm2-Collision" %
                                          self.id)
        self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.arm2CollNode.addSolid(self.arm2Coll)
        self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode)

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

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

        self.hole = loader.loadModel("phase_13/models/parties/cogPinataHole")
        self.hole.setTransparency(True)
        self.hole.setP(-90.0)
        self.hole.setScale(3)
        self.hole.setBin("ground", 3)
        self.hole.reparentTo(self.parentNode)

    def unload(self):
        self.request("Off")
        self.clearHitInterval()

        if self.hole is not None:
            self.hole.removeNode()
            self.hole = None

        if self.actor is not None:
            self.actor.cleanup()
            self.actor.removeNode()
            self.actor = None

        if self.root is not None:
            self.root.removeNode()
            self.root = None

        if self.kaboomTrack is not None and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()
        self.kaboomTrack = None

        if self.resetRollIval is not None and self.resetRollIval.isPlaying():
            self.resetRollIval.finish()
        self.resetRollIval = None

        if self.hitInterval is not None and self.hitInterval.isPlaying():
            self.hitInterval.finish()
        self.hitInterval = None

        del self.upSound
        del self.pieHitSound

#===============================================================================
# FSM States
#===============================================================================

    def enterStatic(self):
        pass

    def exitStatic(self):
        pass

    def enterActive(self, startTime):
        self.root.setR(0.0)

        updateTask = Task.Task(self.updateTask)
        updateTask.startTime = startTime

        taskMgr.add(updateTask, "PartyCog.update-%d" % self.id)

    def exitActive(self):
        taskMgr.remove("PartyCog.update-%d" % self.id)
        taskMgr.remove("PartyCog.bounceTask-%d" % self.id)

        self.clearHitInterval()
        self.resetRollIval = self.root.hprInterval(0.5,
                                                   Point3(
                                                       self.root.getH(), 0.0,
                                                       0.0),
                                                   blendType="easeInOut")
        self.resetRollIval.start()

        self.actor.stop()

    def enterDown(self):
        if self.oldState == "Off":
            downAnimControl = self.actor.getAnimControl("down")
            self.actor.pose("down", downAnimControl.getNumFrames() - 1)
            return

        self.clearHitInterval()
        startScale = self.hole.getScale()
        endScale = Point3(5, 5, 5)
        self.hitInterval = Sequence(
            LerpFunc(self.setAlongSpline,
                     duration=1.0,
                     fromData=self.currentT,
                     toData=0.0),
            LerpScaleInterval(self.hole,
                              duration=0.175,
                              scale=endScale,
                              startScale=startScale,
                              blendType="easeIn"),
            Parallel(
                SoundInterval(self.upSound,
                              volume=0.6,
                              node=self.actor,
                              cutOff=PartyGlobals.PARTY_COG_CUTOFF),
                ActorInterval(self.actor, "down", loop=0),
            ),
            LerpScaleInterval(self.hole,
                              duration=0.175,
                              scale=Point3(3, 3, 3),
                              startScale=endScale,
                              blendType="easeOut"),
        )
        self.hitInterval.start()

    def exitDown(self):
        self.root.setR(0.0)
        self.root.setH(0.0)
        self.targetDistance = 0.0
        self.targetFacing = 0.0
        self.currentT = 0.0
        self.setAlongSpline(0.0)
        self.clearHitInterval()
        startScale = self.hole.getScale()
        endScale = Point3(5, 5, 5)
        self.hitInterval = Sequence(
            LerpScaleInterval(self.hole,
                              duration=0.175,
                              scale=endScale,
                              startScale=startScale,
                              blendType="easeIn"),
            Parallel(
                SoundInterval(self.upSound,
                              volume=0.6,
                              node=self.actor,
                              cutOff=PartyGlobals.PARTY_COG_CUTOFF),
                ActorInterval(self.actor, "up", loop=0),
            ),
            Func(self.actor.loop, "idle"),
            LerpScaleInterval(self.hole,
                              duration=0.175,
                              scale=Point3(3, 3, 3),
                              startScale=endScale,
                              blendType="easeOut"),
        )
        self.hitInterval.start()

    def filterDown(self, request, args):
        if request == "Down":
            return None
        else:
            return self.defaultFilter(request, args)

#------------------------------------------------------------------------------

    def setEndPoints(self, start, end, amplitude=1.7):
        self.sinAmplitude = amplitude
        self.sinPeriod = (end.getX() - start.getX()) / 2
        self.sinDisplacement = start.getY()
        self.startPoint = start
        self.endPoint = end
        self.currentT = 0.0
        self.targetDistance = 0.0
        self.currentFacing = 0.0
        self.targetFacing = 0.0
        self.setAlongSpline(self.currentT)
        self.hole.setPos(self.root.getPos())
        self.hole.setZ(0.02)

    def rockBackAndForth(self, task):
        t = task.startTime + task.time
        angle = math.sin(t) * 20.0

        self.root.setR(angle)

        #        if self.id == 0:
        #            print angle

        return task.cont

    def updateDistance(self, distance):
        self.targetDistance = clamp(distance, -1.0, 1.0)

    def updateTask(self, task):
        self.rockBackAndForth(task)

        if self.targetDistance > self.currentT:
            self.currentT += min(0.01, self.targetDistance - self.currentT)
            self.setAlongSpline(self.currentT)
        elif self.targetDistance < self.currentT:
            self.currentT += max(-0.01, self.targetDistance - self.currentT)
            self.setAlongSpline(self.currentT)

        if self.currentT < 0.0:
            self.targetFacing = -90.0
        elif self.currentT > 0.0:
            self.targetFacing = 90.0
        else:
            self.targetFacing = 0.0

        if self.targetFacing > self.currentFacing:
            self.currentFacing += min(10,
                                      self.targetFacing - self.currentFacing)
        elif self.targetFacing < self.currentFacing:
            self.currentFacing += max(-10,
                                      self.targetFacing - self.currentFacing)

        self.root.setH(self.currentFacing)

        return task.cont

    def setAlongSpline(self, t):
        t = t + 1.0
        dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0
        x = self.startPoint.getX() + t * dist
        y = self.startPoint.getY() - math.sin(
            t * 2 * math.pi) * self.sinAmplitude
        self.root.setPos(x, y, 0)

    def startBounce(self):
        taskMgr.add(self.bounce, "PartyCog.bounceTask-%d" % self.id)

    def bounce(self, task):
        #self.root.setH(self.root.getH() - self.rotateSpeed)
        self.root.setZ((math.sin((self.bounceOffset + task.time) *
                                 self.bounceSpeed) * self.bounceHeight) +
                       self.heightShift)

        return task.cont

    def setPos(self, position):
        self.root.setPos(position)

    def respondToPieHit(self, timestamp, position, hot=False, direction=1.0):
        """The toon hit us, react appropriately."""
        assert (self.notify.debugStateCall(self))

        if self.netTimeSentToStartByHit < timestamp:
            self.__showSplat(position, direction, hot)

            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 clearHitInterval(self):
        if self.hitInterval is not None and self.hitInterval.isPlaying():
            self.hitInterval.clearToInitial()

    def __showSplat(self, position, direction, hot=False):
        """Show the splat graphic and sound."""
        if self.kaboomTrack is not None and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()

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

        self.splat.reparentTo(render)
        self.splat.setPos(self.root, position)
        self.splat.setAlphaScale(1.0)

        if not direction == 1.0:
            #self.splat.setColorScale(Vec4(0.0, 0.0, 50.0, 1.0))
            self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0])
            if self.currentFacing > 0.0:
                facing = "HitFront"
            else:
                facing = "HitBack"
        else:
            self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1])
            #self.splat.setColorScale(Vec4(1.0, 0.6, 0.08, 1.0))
            if self.currentFacing > 0.0:
                facing = "HitBack"
            else:
                facing = "HitFront"

        if hot:
            targetscale = 0.75
            part = "head"
        else:
            targetscale = 0.5
            part = "body"

        def setSplatAlpha(amount):
            self.splat.setAlphaScale(amount)

        self.hitInterval = Sequence(
            ActorInterval(self.actor, part + facing, loop=0),
            Func(self.actor.loop, "idle"),
        )
        self.hitInterval.start()

        self.kaboomTrack = Parallel(
            SoundInterval(self.pieHitSound,
                          volume=1.0,
                          node=self.actor,
                          cutOff=PartyGlobals.PARTY_COG_CUTOFF),
            Sequence(
                Func(self.splat.showThrough),
                Parallel(
                    Sequence(
                        LerpScaleInterval(self.splat,
                                          duration=0.175,
                                          scale=targetscale,
                                          startScale=Point3(0.1, 0.1, 0.1),
                                          blendType="easeOut"),
                        Wait(0.175),
                    ),
                    Sequence(
                        Wait(0.1),
                        LerpFunc(
                            setSplatAlpha,
                            duration=1.0,  #0.4,
                            fromData=1.0,
                            toData=0.0,
                            blendType="easeOut"))),
                Func(self.splat.cleanup),
                Func(self.splat.removeNode),
            ))
        self.kaboomTrack.start()

    def showHitScore(self, number, scale=1):
        """
        Shows the hit score.
        Borrowed from otp.avatar.DistributedAvatar.showHpText
        """
        if number <= 0:
            return

        # Get rid of the number if it is already there.
        if self.hpText:
            self.hideHitScore()

        # Set the font
        self.HpTextGenerator.setFont(ToontownGlobals.getSignFont())

        # Show both negative and positive signs
        if number < 0:
            self.HpTextGenerator.setText(str(number))
        else:
            self.HpTextGenerator.setText("+" + str(number))

        # No shadow
        self.HpTextGenerator.clearShadow()

        # Center the number
        self.HpTextGenerator.setAlign(TextNode.ACenter)

        # Red, always
        #if number < 0:
        r = 1  #0.9
        g = 1  #0
        b = 0
        a = 1

        self.HpTextGenerator.setTextColor(r, g, b, a)

        self.hpTextNode = self.HpTextGenerator.generate()

        # Put the hpText over the head of the avatar
        self.hpText = render.attachNewNode(self.hpTextNode)
        self.hpText.setScale(scale)
        # Make sure it is a billboard
        self.hpText.setBillboardPointEye()
        # Render it after other things in the scene.
        self.hpText.setBin('fixed', 100)

        # Initial position ... Center of the body... the "tan tien"
        self.hpText.setPos(self.root, 0, 0, self.height / 2)

        # Black magic from the early days of Panda3D, later replaced by a Sequence
        seq = Task.sequence(
            # Fly the number out of the character
            self.hpText.lerpPos(Point3(
                self.root.getX(render), self.root.getY(render),
                self.root.getZ(render) + self.height + 1.0),
                                0.25,
                                blendType='easeOut'),
            Task.pause(0.25),
            # Fade the number
            self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1),
            # Get rid of the number
            Task.Task(self.__hideHitScoreTask))

        taskMgr.add(seq, "PartyCogHpText" + str(self.id))

    def __hideHitScoreTask(self, task):
        self.hideHitScore()

        return Task.done

    def hideHitScore(self):
        if self.hpText:
            taskMgr.remove("PartyCogHpText" + str(self.id))
            self.hpText.removeNode()
            self.hpText = None

    def getHeadLocation(self):
        (self.actor.getJoints(jointName="head")[0]).getNetTransform(
            self.temp_transform)
        self.head_locator.setMat(self.temp_transform)
        #print self.head_locator.getZ()

        return self.head_locator.getZ(self.root)
예제 #10
0
class CogdoFlyingCameraManager:
    def __init__(self, cam, parent, player, level):
        self._toon = player.toon
        self._camera = cam
        self._parent = parent
        self._player = player
        self._level = level
        self._enabled = False

    def enable(self):
        if self._enabled:
            return
        self._toon.detachCamera()
        self._prevToonY = 0.0
        levelBounds = self._level.getBounds()
        l = Globals.Camera.LevelBoundsFactor
        self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]),
                        (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]),
                        (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]))
        self._lookAtZ = self._toon.getHeight(
        ) + Globals.Camera.LookAtToonHeightOffset
        self._camParent = NodePath('CamParent')
        self._camParent.reparentTo(self._parent)
        self._camParent.setPos(self._toon, 0, 0, 0)
        self._camParent.setHpr(180, Globals.Camera.Angle, 0)
        self._camera.reparentTo(self._camParent)
        self._camera.setPos(0, Globals.Camera.Distance, 0)
        self._camera.lookAt(self._toon, 0, 0, self._lookAtZ)
        self._cameraLookAtNP = NodePath('CameraLookAt')
        self._cameraLookAtNP.reparentTo(self._camera.getParent())
        self._cameraLookAtNP.setPosHpr(self._camera.getPos(),
                                       self._camera.getHpr())
        self._levelBounds = self._level.getBounds()
        self._enabled = True
        self._frozen = False
        self._initCollisions()

    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)

    def _destroyCollisions(self):
        self._collTrav.removeCollider(self._camCollNP)
        self._camCollNP.removeNode()
        del self._camCollNP
        del self._camCollRay
        del self._collHandler
        del self._collOffset
        del self._betweenCamAndToon
        self._transNP.removeNode()
        del self._transNP

    def freeze(self):
        self._frozen = True

    def unfreeze(self):
        self._frozen = False

    def disable(self):
        if not self._enabled:
            return
        self._destroyCollisions()
        self._camera.wrtReparentTo(render)
        self._cameraLookAtNP.removeNode()
        del self._cameraLookAtNP
        self._camParent.removeNode()
        del self._camParent
        del self._prevToonY
        del self._lookAtZ
        del self._bounds
        del self._frozen
        self._enabled = False

    def update(self, dt=0.0):
        self._updateCam(dt)
        self._updateCollisions()

    def _updateCam(self, dt):
        toonPos = self._toon.getPos()
        camPos = self._camParent.getPos()
        x = camPos[0]
        z = camPos[2]
        toonWorldX = self._toon.getX(render)
        maxX = Globals.Camera.MaxSpinX
        toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX)
        spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (
            maxX * maxX)
        newH = 180.0 + spinAngle
        self._camParent.setH(newH)
        spinAngle = spinAngle * (pi / 180.0)
        distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle)
        distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle)
        d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0])
        if abs(d) > Globals.Camera.LeewayX:
            if d > Globals.Camera.LeewayX:
                x = toonPos[0] + Globals.Camera.LeewayX
            else:
                x = toonPos[0] - Globals.Camera.LeewayX
        x = self._toon.getX(render) + distToRightOfToon
        boundToonZ = min(toonPos[2], self._bounds[2][1])
        d = z - boundToonZ
        if d > Globals.Camera.MinLeewayZ:
            if self._player.velocity[2] >= 0 and toonPos[
                    1] != self._prevToonY or self._player.velocity[2] > 0:
                z = boundToonZ + d * INVERSE_E**(dt *
                                                 Globals.Camera.CatchUpRateZ)
            elif d > Globals.Camera.MaxLeewayZ:
                z = boundToonZ + Globals.Camera.MaxLeewayZ
        elif d < -Globals.Camera.MinLeewayZ:
            z = boundToonZ - Globals.Camera.MinLeewayZ
        if self._frozen:
            y = camPos[1]
        else:
            y = self._toon.getY(render) - distBehindToon
        self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z))
        if toonPos[2] < self._bounds[2][1]:
            h = self._cameraLookAtNP.getH()
            if d >= Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ)
            elif d <= -Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._camParent, 0, 0,
                                            self._lookAtZ)
            self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0)
            self._camera.setHpr(
                smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr()))
        self._prevToonY = toonPos[1]

    def _updateCollisions(self):
        pos = self._toon.getPos(self._camera) + self._collOffset
        self._camCollRay.setOrigin(pos)
        direction = -Vec3(pos)
        direction.normalize()
        self._camCollRay.setDirection(direction)
        self._collTrav.traverse(render)
        nodesInBetween = {}
        if self._collHandler.getNumEntries() > 0:
            self._collHandler.sortEntries()
            for entry in self._collHandler.getEntries():
                name = entry.getIntoNode().getName()
                if name.find('col_') >= 0:
                    np = entry.getIntoNodePath().getParent()
                    if not np in nodesInBetween:
                        nodesInBetween[np] = np.getParent()

        for np in nodesInBetween.keys():
            if np in self._betweenCamAndToon:
                del self._betweenCamAndToon[np]
            else:
                np.setTransparency(True)
                np.wrtReparentTo(self._transNP)
                if np.getName().find('lightFixture') >= 0:
                    if not np.find('**/*floor_mesh').isEmpty():
                        np.find('**/*floor_mesh').hide()
                elif np.getName().find('platform') >= 0:
                    if not np.find('**/*Floor').isEmpty():
                        np.find('**/*Floor').hide()

        for np, parent in self._betweenCamAndToon.items():
            np.wrtReparentTo(parent)
            np.setTransparency(False)
            if np.getName().find('lightFixture') >= 0:
                if not np.find('**/*floor_mesh').isEmpty():
                    np.find('**/*floor_mesh').show()
            elif np.getName().find('platform') >= 0:
                if not np.find('**/*Floor').isEmpty():
                    np.find('**/*Floor').show()

        self._betweenCamAndToon = nodesInBetween
예제 #11
0
class PlaneView(FSM, DirectObject):
    """Give this class a plane as argument and it will create
    some nodes around it which you can parent the camera to (if there are no
    such nodes yet).

    Usage:
    plane_camera = PlaneCamera(aeroplane, camera)
    plane_camera.setView("ThirdPerson")
    plane_camera.setView("Next")
    """
    def __init__(self, camera, parent):
        """Arguments:
        camera -- Camera to be used
        parent -- Aeroplane which the camera should follow
        """

        self.notifier = DirectNotify().newCategory("azure-camera")
        self.camera = camera
        self.parent = parent
        # This gets replaced by a NodePath with all available cameras as
        # children and plane node as parent in createCamNodes()
        self.cameras = None

        #if parent.__class__.__name__ is not "Aeroplane":
        if not isinstance(self.parent, Aeroplane):
            raise ParamError, "Parent must be an Aeroplane instance, " + \
                              "but is %s" % type(self.parent)

        FSM.__init__(self, "PlaneCamera: %s" % self.parent.name)
        DirectObject.__init__(self)

        self.cameras = self.parent.node.find("cameras")
        if self.cameras.isEmpty():
            self.createCamNodes()
        self.updateCamArray()

        self.sideview_direction = 0

        # Set up the default camera
        self.setView("ThirdPerson")

    def createCamNodes(self):
        """Creates a few empty nodes around a plane which the camera might be
        parented to. It looks if there are cameras inside the model file and
        uses those if possible. Where everything named "camera CamType" is
        considered a camera. At least ThirdPerson, FirstPerson and Cockpit
        should be defined inside the egg file, otherwise some guessed defaults
        are taken.
        """

        # Look for cameras inside the model (loaded egg file)
        self.cameras = NodePath("cameras")
        found_cams = self.parent.node.findAllMatches("**/camera ?*")
        found_cams.removeDuplicatePaths()
        found_cams.reparentTo(self.cameras)

        if not found_cams.isEmpty():
            self.notifier.info("Cameras found under model:\n%s"
                               % found_cams)
        else:
            self.notifier.info("No cameras found under model.")

        # FirstPerson camera is a must-have. Set up a guessed one if none
        # defined yet.
        if self.cameras.find("camera FirstPerson").isEmpty():
            assert self.notifier.debug("No first person camera found in %s. "
                                  "Guessing best position." % self.parent.name)
            first_person = NodePath("camera FirstPerson")
            # TODO: Guess best position based on bounding box.
            first_person.setY(5)
            first_person.reparentTo(cameras)

        # ThirdPerson camera is a must-have. Set up a guessed one if none
        # defined yet.
        if self.cameras.find("camera ThirdPerson").isEmpty():
            assert self.notifier.debug("No third person camera found in %s. "
                                  "Guessing best position." % self.parent.name)
            third_person = NodePath("camera ThirdPerson")
            # TODO: Guess best position based on bounding box.
            third_person.setPos(0, -30, 5)
            #third_person.setP(-80)
            third_person.reparentTo(cameras)

        # Cockpit needs to be accurate. Don't try to guess it.
        if self.cameras.find("camera Cockpit").isEmpty():
            assert self.notifier.debug("No cockpit camera found in "
                                       "%s. Cockpit camera disabled."
                                       % self.parent.name)
        self.sideview_cam = NodePath("camera Sideview")
        self.sideview_cam.reparentTo(render)

        # Store the cams at parent node..
        # You can edit the camera nodes from outside as well.
        # If you attach new camera nodes, though, you'll have to call this
        # function again.
        self.cameras.reparentTo(self.parent.node)

    def updateCamArray(self, cameramodes=None):
        """Set the cameras which next and previous will switch to. Expects a
        list or tuple. Defaults to all available cameras."""
        a = []
        if not cameramodes:
            for c in self.cameras.getChildren():
                if c.getName().startswith("camera "):
                    a.append(c.getName().strip("camera "))
            self.setStateArray(a)
        else:
            self.setStateArray(cameramodes)

    def getView(self):
        """Returns the current view mode."""
        return self.getCurrentOrNextState()

    def setView(self, mode, *args):
        """Convenience function."""
        return self.request(mode, args)

    def defaultEnter(self, *args):
        """Executed by the FSM every time an undefined state is entered.
        Note: this function is called AFTER the responsible filter."""

        assert self.notifier.debug("Changing state from %s to %s with args: %s."
                                   % (self.oldState, self.newState, args))
        request = self.newState

        target_cam = self.cameras.find("camera " + request)
        if not target_cam.isEmpty():
            try:
                self.camera.reparentTo(target_cam)
                self.camera.setPosHpr(0, 0, 0, 0, 0, 0)
            except:
                self.notifier.warning(
                        "Ok, now this really shouldn't happen! Filter said the "
                        "camera is there and enter can't find it...")



    def defaultFilter(self, request, args):
        """Executed by the FSM every time an undefined state is requested."""
        assert self.notifier.debug("Requested %s with args: %s"
                                   % (request, args))

        self.camera.setPosHpr(0, 0, 0, 0, 0, 0)

        # Always available.
        if request == "Off":   # implemented in FSM.py
            return (request,) + args
        if request == "Next":  # implemented in FSM.py
            return self.requestNext(args)
        if request == "Prev":  # implemented in FSM.py
            return self.requestPrev(args)
        if request == "Detached":
            return (request,) + args
        if request == "Sideview":
            return (request,) + args
        
        # Depending on airplane.
        if not self.cameras.find("camera " + request).isEmpty():
            return (request,) + args
        assert self.notifier.info("Sorry, no %s camera found." % request)
        return None


    def enterOff(self, *args):
        """Clean up everything by reparenting the camera to the airplane."""
        self.camera.reparentTo(self.parent.node)
        self.camera.setPosHpr(0, 0, 0, 0, 0, 0)

    def enterSideview(self, *args):
        self.sideview_direction += 90
        self.camera.reparentTo(self.sideview_cam)
        self.camera.setY(-30)
        self.sideview_cam.setH(self.sideview_direction)
        #self.addTask(self.updateSideview, "sideview camera", taskChain="world")
        self.task = self.updateSideview

    def exitSideview(self, *args):
        #self.removeTask("sideview camera")
        self.task = lambda x: Task.cont

    def updateSideview(self, task):
        self.sideview_cam.setPos(self.parent.node.getPos())
        return Task.cont

    def enterDetached(self, *args):
        """Lets the camera view the plane from far away."""
        self.camera.reparentTo(render)
        self.camera.setPosHpr(0, 0, 10, 0, 0, 0)
        #self.addTask(self.updateDetachedCam, "detached camera",
        #             taskChain="world")
        self.task = self.updateDetachedCam

    def exitDetached(self, *args):
        #self.removeTask("detached camera")
        self.task = lambda x: Task.cont

    def updateDetachedCam(self, task):
        """Updates camera position and rotation for Detached camera."""
        try:
            self.camera.lookAt(self.parent.node)
        except:
            self.notifier.warning("Error on detached cam task. Exit.")
            return Task.done
        return Task.cont

    def enterThirdPerson(self, *args):
        """Lets the camera view the plane from far away."""
        self._hist = []
        self.camera.reparentTo(self.cameras.find("camera ThirdPerson"))
        self.cameras.find("camera ThirdPerson").setPos(0, -30, 0)
        #self.addTask(self.updateThirdPersonCam, "third person camera",
        #             taskChain="world")
        self.task = self.updateThirdPersonCam
        #print "entering third person"

    def exitThirdPerson(self, *args):
        #self.removeTask("third person camera")
        self.task = lambda x: Task.cont
        del self._hist

    def updateThirdPersonCam(self, task):
        """Updates camera position and rotation for ThirdPerson camera."""
        speed = self.parent.physics.speed()
        velocity = self.parent.physics.velocity()
        #v = Point3(self.parent.physics.angVelVector())
        v = Point3(self.parent.physics.angVelBodyHpr())
        print round(v.getX(), 2), round(v.getY(), 2), round(v.getZ(), 2)

        #self.segs = LineSegs("lines");
        #self.segs.setColor(1,1,1,1)
        #self.segs.drawTo(-1, 0)
        #self.segsnode = self.segs.create()
        #render2d.attachNewNode(self.segsnode) 

        vec = Point3(self.parent.physics.angVelBodyHpr())
        # Y hiervon ist pitch, Z ist roll
        #print round(vec.getY(), 2), round(vec.getZ(), 2)
        self.camera.lookAt(self.parent.node)
        self.camera.setR(self.camera, vec.getZ()*3)
        #self.camera.setPos(abs(v.getX()), 0,  vec.getY())

        

        #plane = self.parent.node
        #self._hist.insert(0, [task.time, camera.getPos(plane)])
        #while len(self._hist) > 50:
        #    self._hist.pop()
        #
        #for snapshot in self._hist:
        #    if snapshot[0] > task.time:
        #        break
        #time_delta = snapshot[0] - task.time
        #self.camera.setPos(plane, snapshot[1])

        #print snapshot
        #self.camera.setPos(render, snapshot[1])
        #self.camera.lookAt(plane, (0, 20+1*speed, 0))

        #self.camera.setY(5+0.1*speed)
        #self.camera.setZ(5-0.1*speed)

        return Task.cont

    def update(self, task):
        return self.task(task)
    
    def destroy(self):
        self.removeAllTasks()
        self.demand("Off")
def generateHullCache(modelClass):
    geom = loader.loadModel('models/shipparts/pir_m_shp_%s' % HullDict[modelClass])
    stripPrefix(geom, 'model:')
    for node in geom.findAllMatches('**/omit'):
        parent = node.getParent()
        omit = parent.attachNewNode(ModelNode('omit'))
        node.reparentTo(omit)
        node.setName('geom')

    preFlatten(geom)
    logic = loader.loadModel('models/shipparts/pir_m_shp_%s_logic' % HullDict[modelClass])
    locators = logic.find('**/locators')
    for side in [
        'left',
        'right']:
        bad = locators.find('**/location_ropeLadder_0_%s' % side)
        if bad:
            bad.setName('location_ropeLadder_%s_0' % side)

        bad = locators.find('**/location_ropeLadder_1_%s' % side)
        if bad:
            bad.setName('location_ropeLadder_%s_1' % side)

        bad = locators.find('**/location_ropeLadder_1_%s1' % side)
        if bad:
            bad.setName('location_ropeLadder_%s_2' % side)
            continue

    collisions = logic.find('**/collisions')
    badPanel = collisions.find('**/collision_panel_3')
    if badPanel:
        badPanel.setName('collision_panel_2')

    collisions.find('**/collision_panel_0').setTag('Hull Code', '0')
    collisions.find('**/collision_panel_1').setTag('Hull Code', '1')
    collisions.find('**/collision_panel_2').setTag('Hull Code', '2')
    walls = collisions.find('**/collision_walls')
    if walls:
        walls.setTag('Hull Code', '255')
    else:
        collisions.attachNewNode('collision_walls')
    shipToShipCollide = collisions.find('**/collision_shiptoship')
    shipToShipCollide.setCollideMask(PiratesGlobals.ShipCollideBitmask)
    deck = collisions.find('**/collision_deck')
    if not deck:
        deck = collisions.attachNewNode('deck')

    mask = deck.getCollideMask()
    mask ^= PiratesGlobals.FloorBitmask
    mask |= PiratesGlobals.ShipFloorBitmask
    deck.setCollideMask(mask)
    floors = collisions.find('**/collision_floors')
    if not floors:
        floors = collisions.find('**/collision_floor')

    mask = floors.getCollideMask()
    mask ^= PiratesGlobals.FloorBitmask
    mask |= PiratesGlobals.ShipFloorBitmask
    floors.setCollideMask(mask)
    floors.setTag('Hull Code', str(255))
    geomHigh = geom.find('**/lod_high')
    geomMed = geom.find('**/lod_medium')
    if not geomMed:
        geomMed = geom.find('**/low_medium')

    if not geomMed:
        geomMed = geomHigh.copyTo(NodePath())

    geomLow = geom.find('**/lod_low')
    if not geomLow:
        geomLow = geomMed.copyTo(NodePath())

    geomSuperLow = geom.find('**/lod_superlow')
    if not geomSuperLow:
        geomSuperLow = geomLow.copyTo(NodePath())

    geomHigh.setName('high')
    geomMed.setName('med')
    geomLow.setName('low')
    geomSuperLow.setName('superlow')
    if modelClass in [
        21,
        22,
        23]:
        spike = loader.loadModel('models/shipparts/pir_m_shp_ram_spike')
        spikeTrans = locators.find('**/location_ram').getTransform(locators)
        spike.setTransform(spikeTrans)
        spike.flattenLight()
        spikeHi = spike.find('**/lod_high')
        spikeMed = spike.find('**/lod_medium')
        spikeLow = spike.find('**/lod_low')
        spikeHi.copyTo(geomHigh)
        spikeMed.copyTo(geomMed)
        spikeLow.copyTo(geomLow)
        spikeLow.copyTo(geomSuperLow)

    flipRoot = NodePath('root')
    collisions.reparentTo(flipRoot)
    locators.reparentTo(flipRoot)
    geomHigh.reparentTo(flipRoot)
    geomMed.reparentTo(flipRoot)
    geomLow.reparentTo(flipRoot)
    geomSuperLow.reparentTo(flipRoot)
    flipRoot.setH(180)
    flipRoot.flattenLight()
    omits = flipRoot.findAllMatches('**/omit')
    for node in omits:
        node.flattenStrong()

    for group in [
        'static',
        'transparent',
        'ropeLadder_*',
        'stripeA',
        'stripeB',
        'pattern']:
        for node in flipRoot.findAllMatches('**/%s' % group):
            name = node.getName()
            for subNode in node.findAllMatches('**/*'):
                subNode.setName(name)

            node.flattenStrong()
            node.setName(name)


    geomHigh.detachNode()
    geomMed.detachNode()
    geomLow.detachNode()
    geomSuperLow.detachNode()
    locators.detachNode()
    collisions.detachNode()
    genericGeoms = [
        geomHigh,
        geomMed,
        geomLow,
        geomSuperLow]
    customGeoms = [ x.copyTo(NodePath()) for x in genericGeoms ]
    for np in genericGeoms:
        trans = np.find('**/transparent')
        if trans:
            trans.stash()

        np.flattenLight()
        sails = np.findAllMatches('**/sails')
        sails.stash()
        omits = np.findAllMatches('**/omit')
        omits.stash()
        for node in omits:
            node.node().setPreserveTransform(node.node().PTDropNode)

        generic = NodePath('generic')
        np.findAllMatches('**/+GeomNode').wrtReparentTo(generic)
        np.findAllMatches('*').detach()
        generic.flattenStrong()
        generic.reparentTo(np)
        stripAttribs(generic, TextureAttrib)
        collapse(generic)
        sails.unstash()
        sails.reparentTo(np)
        for node in sails:
            node.node().setPreserveTransform(node.node().PTDropNode)

        if trans:
            trans.unstash()
            trans.flattenStrong()
            if trans.node().isOfType(ModelNode.getClassType()):
                trans.node().setPreserveTransform(ModelNode.PTDropNode)


        deck = np.find('**/=cam=shground')
        if deck:
            deck.setName('deck')

        omits.unstash()

    for np in customGeoms:
        collapse(np.find('**/static'))

    data = HullCache()
    data.root = NodePath('hull')
    data.genericGeoms = genericGeoms
    data.customGeoms = customGeoms
    data.collisions = collisions
    data.locators = locators
    return data
예제 #13
0
    def load(self):
        self.arena = loader.loadModel("phase_13/models/parties/cogPieArena_model")
        self.arena.reparentTo(self.root)
        
        ground = self.arena.find("**/ground")
        # Make the ground plane draw before the shadow!
        ground.setBin("ground", 1)
        
        entranceArrows = self.arena.findAllMatches("**/arrowFlat*")
        for arrow in entranceArrows:
            arrow.setBin("ground", 5)
        
        # Get Entrance/Exit Locations
        self.leftEntranceLocator = self.arena.find("**/leftEntrance_locator")
        self.rightEntranceLocator = self.arena.find("**/rightEntrance_locator")
        self.leftExitLocator = self.arena.find("**/leftExit_locator")
        self.rightExitLocator = self.arena.find("**/rightExit_locator")
        
        self.teamCamPosLocators = (
            self.arena.find("**/team0CamPos_locator"),
            self.arena.find("**/team1CamPos_locator")
            )
        
        self.teamCamAimLocators = (
            self.arena.find("**/team0CamAim_locator"),
            self.arena.find("**/team1CamAim_locator"),
            )
        
        # Setup team locators
        # Toons are parented to these guys in order to do
        # Orthowalk properly
        leftTeamLocator = NodePath("TeamLocator-%d" % PartyGlobals.TeamActivityTeams.LeftTeam)
        leftTeamLocator.reparentTo(self.root)
        leftTeamLocator.setH(90)
        
        rightTeamLocator = NodePath("TeamLocator-%d" % PartyGlobals.TeamActivityTeams.RightTeam)
        rightTeamLocator.reparentTo(self.root)
        rightTeamLocator.setH(-90)
        
        self.teamLocators = (
            leftTeamLocator,
            rightTeamLocator
            )
        
        # Used to place the toons in even spaces
        self._lengthBetweenEntrances = self.leftEntranceLocator.getY() - self.rightExitLocator.getY()
        
        # Setup Sky Collisions. Important for cannons.
        self._skyCollisionsCollection = self.arena.findAllMatches("**/cogPieArena_sky*_collision")
        
        if len(self._skyCollisionsCollection) > 0:
            self._skyCollisionParent = self._skyCollisionsCollection[0].getParent()
        else:
            self._skyCollisionParent = self.arena
            
        # Get all the wall collisions:
        self._wallCollisionsCollection = self.arena.findAllMatches("**/cogPieArena_wall*_collision")
            
        # Get a hold of the flags:
        self._arenaFlagGroups = (
            self.arena.find("**/flagsL_grp"),
            self.arena.find("**/flagsR_grp")
           )
        
        self._initArenaDoors()
        
        # Setup Cogs
        self.cogManager = PartyCogManager()
        self.arrows = []
        
        self.distanceLabels = []
        self.teamColors = list(PartyGlobals.CogActivityColors) + [PartyGlobals.TeamActivityStatusColor]
        
        for i in range(3):
            start = self.arena.find("**/cog%d_start_locator" % (i+1))
            end = self.arena.find("**/cog%d_end_locator" % (i+1))
            
            cog = self.cogManager.generateCog(self.arena)
            cog.setEndPoints(start.getPos(), end.getPos())
            
            arrow1 = StretchingArrow(self.arena, useColor="orange")
            arrow2 = StretchingArrow(self.arena, useColor="blue")
            arrow1.setZ(0.1)
            arrow2.setZ(0.1)
            self.arrows.append([arrow1, arrow2])
            
            distanceLabel = self.createDistanceLabel(0, self.teamColors[1])
            distanceLabel[0].stash()
            distanceLabel2 = self.createDistanceLabel(0, self.teamColors[0])
            distanceLabel2[0].stash()
            self.distanceLabels.append([distanceLabel, distanceLabel2])
        
        
        self.winText = []
        text1 = self.createText(0, Point3(-0.5,0.0,-0.5), self.teamColors[1])
        text2 = self.createText(1, Point3(0.5,0.0,-0.5), self.teamColors[0])
        self.winText.append(text1)
        self.winText.append(text2)
        
        self.winStatus = self.createText(2, Point3(0.0,0.0,-0.8), self.teamColors[0])

        signLocator = self.arena.find("**/eventSign_locator")
        self.activity.sign.setPos(signLocator.getPos(self.root))
        
        self.enable()
예제 #14
0
class PartyCog(FSM):
    notify = directNotify.newCategory('PartyCog')
    HpTextGenerator = TextNode('HpTextGenerator')
    hpText = None
    height = 7

    def __init__(self,
                 parentNode,
                 id,
                 bounceSpeed=3,
                 bounceHeight=1,
                 rotateSpeed=1,
                 heightShift=1,
                 xMoveSpeed=0,
                 xMoveDistance=0,
                 bounceOffset=0):
        self.id = id
        FSM.__init__(self, 'PartyCogFSM-%d' % self.id)
        self.showFacingStatus = False
        self.xMoveSpeed = xMoveSpeed
        self.xMoveDistance = xMoveDistance
        self.heightShift = heightShift
        self.bounceSpeed = bounceSpeed
        self.bounceHeight = bounceHeight
        self.rotateSpeed = rotateSpeed
        self.parentNode = parentNode
        self.bounceOffset = bounceOffset
        self.hitInterval = None
        self.kaboomTrack = None
        self.resetRollIval = None
        self.netTimeSentToStartByHit = 0
        self.load()
        self.request('Down')
        return

    def load(self):
        self.root = NodePath('PartyCog-%d' % self.id)
        self.root.reparentTo(self.parentNode)
        path = 'phase_13/models/parties/cogPinata_'
        self.actor = Actor(
            path + 'actor', {
                'idle': path + 'idle_anim',
                'down': path + 'down_anim',
                'up': path + 'up_anim',
                'bodyHitBack': path + 'bodyHitBack_anim',
                'bodyHitFront': path + 'bodyHitFront_anim',
                'headHitBack': path + 'headHitBack_anim',
                'headHitFront': path + 'headHitFront_anim'
            })
        self.actor.reparentTo(self.root)
        self.temp_transform = Mat4()
        self.head_locator = self.actor.attachNewNode('temphead')
        self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75)
        self.bodyColl.setTangible(1)
        self.bodyCollNode = CollisionNode('PartyCog-%d-Body-Collision' %
                                          self.id)
        self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.bodyCollNode.addSolid(self.bodyColl)
        self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode)
        self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5)
        self.headColl.setTangible(1)
        self.headCollNode = CollisionNode('PartyCog-%d-Head-Collision' %
                                          self.id)
        self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.headCollNode.addSolid(self.headColl)
        self.headCollNodePath = self.root.attachNewNode(self.headCollNode)
        self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0)
        self.arm1Coll.setTangible(1)
        self.arm1CollNode = CollisionNode('PartyCog-%d-Arm1-Collision' %
                                          self.id)
        self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.arm1CollNode.addSolid(self.arm1Coll)
        self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode)
        self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0)
        self.arm2Coll.setTangible(1)
        self.arm2CollNode = CollisionNode('PartyCog-%d-Arm2-Collision' %
                                          self.id)
        self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.arm2CollNode.addSolid(self.arm2Coll)
        self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode)
        splatName = 'splat-creampie'
        self.splat = globalPropPool.getProp(splatName)
        self.splat.setBillboardPointEye()
        self.splatType = globalPropPool.getPropType(splatName)
        self.pieHitSound = globalBattleSoundCache.getSound(
            'AA_wholepie_only.ogg')
        self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.ogg')
        self.hole = loader.loadModel('phase_13/models/parties/cogPinataHole')
        self.hole.setTransparency(True)
        self.hole.setP(-90.0)
        self.hole.setScale(3)
        self.hole.setBin('ground', 3)
        self.hole.reparentTo(self.parentNode)

    def unload(self):
        self.request('Off')
        self.clearHitInterval()
        if self.hole is not None:
            self.hole.removeNode()
            self.hole = None
        if self.actor is not None:
            self.actor.cleanup()
            self.actor.removeNode()
            self.actor = None
        if self.root is not None:
            self.root.removeNode()
            self.root = None
        if self.kaboomTrack is not None and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()
        self.kaboomTrack = None
        if self.resetRollIval is not None and self.resetRollIval.isPlaying():
            self.resetRollIval.finish()
        self.resetRollIval = None
        if self.hitInterval is not None and self.hitInterval.isPlaying():
            self.hitInterval.finish()
        self.hitInterval = None
        del self.upSound
        del self.pieHitSound
        return

    def enterStatic(self):
        pass

    def exitStatic(self):
        pass

    def enterActive(self, startTime):
        self.root.setR(0.0)
        updateTask = Task.Task(self.updateTask)
        updateTask.startTime = startTime
        taskMgr.add(updateTask, 'PartyCog.update-%d' % self.id)

    def exitActive(self):
        taskMgr.remove('PartyCog.update-%d' % self.id)
        taskMgr.remove('PartyCog.bounceTask-%d' % self.id)
        self.clearHitInterval()
        self.resetRollIval = self.root.hprInterval(0.5,
                                                   Point3(
                                                       self.root.getH(), 0.0,
                                                       0.0),
                                                   blendType='easeInOut')
        self.resetRollIval.start()
        self.actor.stop()

    def enterDown(self):
        if self.oldState == 'Off':
            downAnimControl = self.actor.getAnimControl('down')
            self.actor.pose('down', downAnimControl.getNumFrames() - 1)
            return
        self.clearHitInterval()
        startScale = self.hole.getScale()
        endScale = Point3(5, 5, 5)
        self.hitInterval = Sequence(
            LerpFunc(self.setAlongSpline,
                     duration=1.0,
                     fromData=self.currentT,
                     toData=0.0),
            LerpScaleInterval(self.hole,
                              duration=0.175,
                              scale=endScale,
                              startScale=startScale,
                              blendType='easeIn'),
            Parallel(
                SoundInterval(self.upSound,
                              volume=0.6,
                              node=self.actor,
                              cutOff=PartyGlobals.PARTY_COG_CUTOFF),
                ActorInterval(self.actor, 'down', loop=0)),
            LerpScaleInterval(self.hole,
                              duration=0.175,
                              scale=Point3(3, 3, 3),
                              startScale=endScale,
                              blendType='easeOut'))
        self.hitInterval.start()

    def exitDown(self):
        self.root.setR(0.0)
        self.root.setH(0.0)
        self.targetDistance = 0.0
        self.targetFacing = 0.0
        self.currentT = 0.0
        self.setAlongSpline(0.0)
        self.clearHitInterval()
        startScale = self.hole.getScale()
        endScale = Point3(5, 5, 5)
        self.hitInterval = Sequence(
            LerpScaleInterval(self.hole,
                              duration=0.175,
                              scale=endScale,
                              startScale=startScale,
                              blendType='easeIn'),
            Parallel(
                SoundInterval(self.upSound,
                              volume=0.6,
                              node=self.actor,
                              cutOff=PartyGlobals.PARTY_COG_CUTOFF),
                ActorInterval(self.actor, 'up', loop=0)),
            Func(self.actor.loop, 'idle'),
            LerpScaleInterval(self.hole,
                              duration=0.175,
                              scale=Point3(3, 3, 3),
                              startScale=endScale,
                              blendType='easeOut'))
        self.hitInterval.start()

    def filterDown(self, request, args):
        if request == 'Down':
            return None
        else:
            return self.defaultFilter(request, args)
        return None

    def setEndPoints(self, start, end, amplitude=1.7):
        self.sinAmplitude = amplitude
        self.sinPeriod = (end.getX() - start.getX()) / 2
        self.sinDisplacement = start.getY()
        self.startPoint = start
        self.endPoint = end
        self.currentT = 0.0
        self.targetDistance = 0.0
        self.currentFacing = 0.0
        self.targetFacing = 0.0
        self.setAlongSpline(self.currentT)
        self.hole.setPos(self.root.getPos())
        self.hole.setZ(0.02)

    def rockBackAndForth(self, task):
        t = task.startTime + task.time
        angle = math.sin(t) * 20.0
        self.root.setR(angle)
        return task.cont

    def updateDistance(self, distance):
        self.targetDistance = clamp(distance, -1.0, 1.0)

    def updateTask(self, task):
        self.rockBackAndForth(task)
        if self.targetDistance > self.currentT:
            self.currentT += min(0.01, self.targetDistance - self.currentT)
            self.setAlongSpline(self.currentT)
        elif self.targetDistance < self.currentT:
            self.currentT += max(-0.01, self.targetDistance - self.currentT)
            self.setAlongSpline(self.currentT)
        if self.currentT < 0.0:
            self.targetFacing = -90.0
        elif self.currentT > 0.0:
            self.targetFacing = 90.0
        else:
            self.targetFacing = 0.0
        if self.targetFacing > self.currentFacing:
            self.currentFacing += min(10,
                                      self.targetFacing - self.currentFacing)
        elif self.targetFacing < self.currentFacing:
            self.currentFacing += max(-10,
                                      self.targetFacing - self.currentFacing)
        self.root.setH(self.currentFacing)
        return task.cont

    def setAlongSpline(self, t):
        t = t + 1.0
        dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0
        x = self.startPoint.getX() + t * dist
        y = self.startPoint.getY() - math.sin(
            t * 2 * math.pi) * self.sinAmplitude
        self.root.setPos(x, y, 0)

    def startBounce(self):
        taskMgr.add(self.bounce, 'PartyCog.bounceTask-%d' % self.id)

    def bounce(self, task):
        self.root.setZ(
            math.sin((self.bounceOffset + task.time) * self.bounceSpeed) *
            self.bounceHeight + self.heightShift)
        return task.cont

    def setPos(self, position):
        self.root.setPos(position)

    def respondToPieHit(self, timestamp, position, hot=False, direction=1.0):
        if self.netTimeSentToStartByHit < timestamp:
            self.__showSplat(position, direction, hot)
            if self.netTimeSentToStartByHit < timestamp:
                self.netTimeSentToStartByHit = timestamp
        else:
            self.notify.debug(
                'respondToPieHit self.netTimeSentToStartByHit = %s' %
                self.netTimeSentToStartByHit)

    def clearHitInterval(self):
        if self.hitInterval is not None and self.hitInterval.isPlaying():
            self.hitInterval.clearToInitial()
        return

    def __showSplat(self, position, direction, hot=False):
        if self.kaboomTrack is not None and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()
        self.clearHitInterval()
        splatName = 'splat-creampie'
        self.splat = globalPropPool.getProp(splatName)
        self.splat.setBillboardPointEye()
        self.splat.reparentTo(render)
        self.splat.setPos(self.root, position)
        self.splat.setAlphaScale(1.0)
        if not direction == 1.0:
            self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0])
            if self.currentFacing > 0.0:
                facing = 'HitFront'
            else:
                facing = 'HitBack'
        else:
            self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1])
            if self.currentFacing > 0.0:
                facing = 'HitBack'
            else:
                facing = 'HitFront'
        if hot:
            targetscale = 0.75
            part = 'head'
        else:
            targetscale = 0.5
            part = 'body'

        def setSplatAlpha(amount):
            self.splat.setAlphaScale(amount)

        self.hitInterval = Sequence(
            ActorInterval(self.actor, part + facing, loop=0),
            Func(self.actor.loop, 'idle'))
        self.hitInterval.start()
        self.kaboomTrack = Parallel(
            SoundInterval(self.pieHitSound,
                          volume=1.0,
                          node=self.actor,
                          cutOff=PartyGlobals.PARTY_COG_CUTOFF),
            Sequence(
                Func(self.splat.showThrough),
                Parallel(
                    Sequence(
                        LerpScaleInterval(self.splat,
                                          duration=0.175,
                                          scale=targetscale,
                                          startScale=Point3(0.1, 0.1, 0.1),
                                          blendType='easeOut'), Wait(0.175)),
                    Sequence(
                        Wait(0.1),
                        LerpFunc(setSplatAlpha,
                                 duration=1.0,
                                 fromData=1.0,
                                 toData=0.0,
                                 blendType='easeOut'))),
                Func(self.splat.cleanup), Func(self.splat.removeNode)))
        self.kaboomTrack.start()
        return

    def showHitScore(self, number, scale=1):
        if number <= 0:
            return
        if self.hpText:
            self.hideHitScore()
        self.HpTextGenerator.setFont(ToontownGlobals.getSignFont())
        if number < 0:
            self.HpTextGenerator.setText(str(number))
        else:
            self.HpTextGenerator.setText('+' + str(number))
        self.HpTextGenerator.clearShadow()
        self.HpTextGenerator.setAlign(TextNode.ACenter)
        r = 1
        g = 1
        b = 0
        a = 1
        self.HpTextGenerator.setTextColor(r, g, b, a)
        self.hpTextNode = self.HpTextGenerator.generate()
        self.hpText = render.attachNewNode(self.hpTextNode)
        self.hpText.setScale(scale)
        self.hpText.setBillboardPointEye()
        self.hpText.setBin('fixed', 100)
        self.hpText.setPos(self.root, 0, 0, self.height / 2)
        seq = Task.sequence(
            self.hpText.lerpPos(Point3(
                self.root.getX(render), self.root.getY(render),
                self.root.getZ(render) + self.height + 1.0),
                                0.25,
                                blendType='easeOut'), Task.pause(0.25),
            self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1),
            Task.Task(self.__hideHitScoreTask))
        taskMgr.add(seq, 'PartyCogHpText' + str(self.id))

    def __hideHitScoreTask(self, task):
        self.hideHitScore()
        return Task.done

    def hideHitScore(self):
        if self.hpText:
            taskMgr.remove('PartyCogHpText' + str(self.id))
            self.hpText.removeNode()
            self.hpText = None
        return

    def getHeadLocation(self):
        self.actor.getJoints(jointName='head')[0].getNetTransform(
            self.temp_transform)
        self.head_locator.setMat(self.temp_transform)
        return self.head_locator.getZ(self.root)
class DistributedIceGame(DistributedMinigame.DistributedMinigame, DistributedIceWorld.DistributedIceWorld):
    notify = directNotify.newCategory("DistributedIceGame")
    MaxLocalForce = 100
    MaxPhysicsForce = 25000

    def __init__(self, cr):
        DistributedMinigame.DistributedMinigame.__init__(self, cr)
        DistributedIceWorld.DistributedIceWorld.__init__(self, cr)
        self.gameFSM = ClassicFSM.ClassicFSM(
            "DistributedIceGame",
            [
                State.State("off", self.enterOff, self.exitOff, ["inputChoice"]),
                State.State(
                    "inputChoice",
                    self.enterInputChoice,
                    self.exitInputChoice,
                    ["waitServerChoices", "moveTires", "displayVotes", "cleanup"],
                ),
                State.State(
                    "waitServerChoices",
                    self.enterWaitServerChoices,
                    self.exitWaitServerChoices,
                    ["moveTires", "cleanup"],
                ),
                State.State("moveTires", self.enterMoveTires, self.exitMoveTires, ["synch", "cleanup"]),
                State.State("synch", self.enterSynch, self.exitSynch, ["inputChoice", "scoring", "cleanup"]),
                State.State("scoring", self.enterScoring, self.exitScoring, ["cleanup", "finalResults", "inputChoice"]),
                State.State("finalResults", self.enterFinalResults, self.exitFinalResults, ["cleanup"]),
                State.State("cleanup", self.enterCleanup, self.exitCleanup, []),
            ],
            "off",
            "cleanup",
        )
        self.addChildGameFSM(self.gameFSM)
        self.cameraThreeQuarterView = (0, -22, 45, 0, -62.89, 0)
        self.tireDict = {}
        self.forceArrowDict = {}
        self.canDrive = False
        self.timer = None
        self.timerStartTime = None
        self.curForce = 0
        self.curHeading = 0
        self.headingMomentum = 0.0
        self.forceMomentum = 0.0
        self.allTireInputs = None
        self.curRound = 0
        self.curMatch = 0
        self.controlKeyWarningLabel = DirectLabel(
            text=TTLocalizer.IceGameControlKeyWarning,
            text_fg=VBase4(1, 0, 0, 1),
            relief=None,
            pos=(0.0, 0, 0),
            scale=0.15,
        )
        self.controlKeyWarningLabel.hide()
        self.waitingMoveLabel = DirectLabel(
            text=TTLocalizer.IceGameWaitingForPlayersToFinishMove,
            text_fg=VBase4(1, 1, 1, 1),
            relief=None,
            pos=(-0.6, 0, -0.75),
            scale=0.075,
        )
        self.waitingMoveLabel.hide()
        self.waitingSyncLabel = DirectLabel(
            text=TTLocalizer.IceGameWaitingForAISync,
            text_fg=VBase4(1, 1, 1, 1),
            relief=None,
            pos=(-0.6, 0, -0.75),
            scale=0.075,
        )
        self.waitingSyncLabel.hide()
        self.infoLabel = DirectLabel(text="", text_fg=VBase4(0, 0, 0, 1), relief=None, pos=(0.0, 0, 0.7), scale=0.075)
        self.updateInfoLabel()
        self.lastForceArrowUpdateTime = 0
        self.sendForceArrowUpdateAsap = False
        self.treasures = []
        self.penalties = []
        self.obstacles = []
        self.controlKeyPressed = False
        self.controlKeyWarningIval = None
        return

    def delete(self):
        DistributedIceWorld.DistributedIceWorld.delete(self)
        DistributedMinigame.DistributedMinigame.delete(self)
        if self.controlKeyWarningIval:
            self.controlKeyWarningIval.finish()
            self.controlKeyWarningIval = None
        self.controlKeyWarningLabel.destroy()
        del self.controlKeyWarningLabel
        self.waitingMoveLabel.destroy()
        del self.waitingMoveLabel
        self.waitingSyncLabel.destroy()
        del self.waitingSyncLabel
        self.infoLabel.destroy()
        del self.infoLabel
        for treasure in self.treasures:
            treasure.destroy()

        del self.treasures
        for penalty in self.penalties:
            penalty.destroy()

        del self.penalties
        for obstacle in self.obstacles:
            obstacle.removeNode()

        del self.obstacles
        del self.gameFSM
        return

    def announceGenerate(self):
        DistributedMinigame.DistributedMinigame.announceGenerate(self)
        DistributedIceWorld.DistributedIceWorld.announceGenerate(self)
        self.debugTaskName = self.uniqueName("debugTask")

    def getTitle(self):
        return TTLocalizer.IceGameTitle

    def getInstructions(self):
        szId = self.getSafezoneId()
        numPenalties = IceGameGlobals.NumPenalties[szId]
        result = TTLocalizer.IceGameInstructions
        if numPenalties == 0:
            result = TTLocalizer.IceGameInstructionsNoTnt
        return result

    def getMaxDuration(self):
        return 0

    def load(self):
        self.notify.debug("load")
        DistributedMinigame.DistributedMinigame.load(self)
        self.music = base.loadMusic("phase_4/audio/bgm/MG_IceGame.ogg")
        self.gameBoard = loader.loadModel("phase_4/models/minigames/ice_game_icerink")
        background = loader.loadModel("phase_4/models/minigames/ice_game_2d")
        backgroundWide = loader.loadModel("phase_4/models/minigames/iceslide_ground")
        background.reparentTo(self.gameBoard)
        backgroundWide.reparentTo(self.gameBoard)
        backgroundWide.setPos(0, -0.3, -0.5)
        self.gameBoard.setPosHpr(0, 0, 0, 0, 0, 0)
        self.gameBoard.setScale(1.0)
        self.setupSimulation()
        index = 0
        for avId in self.avIdList:
            self.setupTire(avId, index)
            self.setupForceArrow(avId)
            index += 1

        for index in xrange(len(self.avIdList), 4):
            self.setupTire(-index, index)
            self.setupForceArrow(-index)

        self.showForceArrows(realPlayersOnly=True)
        self.westWallModel = NodePath()
        if not self.westWallModel.isEmpty():
            self.westWallModel.reparentTo(self.gameBoard)
            self.westWallModel.setPos(IceGameGlobals.MinWall[0], IceGameGlobals.MinWall[1], 0)
            self.westWallModel.setScale(4)
        self.eastWallModel = NodePath()
        if not self.eastWallModel.isEmpty():
            self.eastWallModel.reparentTo(self.gameBoard)
            self.eastWallModel.setPos(IceGameGlobals.MaxWall[0], IceGameGlobals.MaxWall[1], 0)
            self.eastWallModel.setScale(4)
            self.eastWallModel.setH(180)
        self.arrowKeys = ArrowKeys.ArrowKeys()
        self.target = loader.loadModel("phase_3/models/misc/sphere")
        self.target.setScale(0.01)
        self.target.reparentTo(self.gameBoard)
        self.target.setPos(0, 0, 0)
        self.scoreCircle = loader.loadModel("phase_4/models/minigames/ice_game_score_circle")
        self.scoreCircle.setScale(0.01)
        self.scoreCircle.reparentTo(self.gameBoard)
        self.scoreCircle.setZ(IceGameGlobals.TireRadius / 2.0)
        self.scoreCircle.setAlphaScale(0.5)
        self.scoreCircle.setTransparency(1)
        self.scoreCircle.hide()
        self.treasureModel = loader.loadModel("phase_4/models/minigames/ice_game_barrel")
        self.penaltyModel = loader.loadModel("phase_4/models/minigames/ice_game_tnt2")
        self.penaltyModel.setScale(0.75, 0.75, 0.7)
        szId = self.getSafezoneId()
        obstacles = IceGameGlobals.Obstacles[szId]
        index = 0
        cubicObstacle = IceGameGlobals.ObstacleShapes[szId]
        for pos in obstacles:
            newPos = Point3(pos[0], pos[1], IceGameGlobals.TireRadius)
            newObstacle = self.createObstacle(newPos, index, cubicObstacle)
            self.obstacles.append(newObstacle)
            index += 1

        self.countSound = loader.loadSfx("phase_3.5/audio/sfx/tick_counter.ogg")
        self.treasureGrabSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_vine_game_bananas.ogg")
        self.penaltyGrabSound = loader.loadSfx("phase_4/audio/sfx/MG_cannon_fire_alt.ogg")
        self.tireSounds = []
        for tireIndex in xrange(4):
            tireHit = loader.loadSfx("phase_4/audio/sfx/Golf_Hit_Barrier_1.ogg")
            wallHit = loader.loadSfx("phase_4/audio/sfx/MG_maze_pickup.ogg")
            obstacleHit = loader.loadSfx("phase_4/audio/sfx/Golf_Hit_Barrier_2.ogg")
            self.tireSounds.append({"tireHit": tireHit, "wallHit": wallHit, "obstacleHit": obstacleHit})

        self.arrowRotateSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_rotate.ogg")
        self.arrowUpSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_increase_3sec.ogg")
        self.arrowDownSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_force_decrease_3sec.ogg")
        self.scoreCircleSound = loader.loadSfx("phase_4/audio/sfx/MG_sfx_ice_scoring_1.ogg")

    def unload(self):
        self.notify.debug("unload")
        DistributedMinigame.DistributedMinigame.unload(self)
        del self.music
        self.gameBoard.removeNode()
        del self.gameBoard
        for forceArrow in self.forceArrowDict.values():
            forceArrow.removeNode()

        del self.forceArrowDict
        self.scoreCircle.removeNode()
        del self.scoreCircle
        del self.countSound

    def onstage(self):
        self.notify.debug("onstage")
        DistributedMinigame.DistributedMinigame.onstage(self)
        self.gameBoard.reparentTo(render)
        self.__placeToon(self.localAvId)
        self.moveCameraToTop()
        self.scorePanels = []
        base.playMusic(self.music, looping=1, volume=0.8)

    def offstage(self):
        self.notify.debug("offstage")
        self.music.stop()
        self.gameBoard.hide()
        self.infoLabel.hide()
        for avId in self.tireDict:
            self.tireDict[avId]["tireNodePath"].hide()

        for panel in self.scorePanels:
            panel.cleanup()

        del self.scorePanels
        for obstacle in self.obstacles:
            obstacle.hide()

        for treasure in self.treasures:
            treasure.nodePath.hide()

        for penalty in self.penalties:
            penalty.nodePath.hide()

        for avId in self.avIdList:
            av = self.getAvatar(avId)
            if av:
                av.dropShadow.show()
                av.resetLOD()

        taskMgr.remove(self.uniqueName("aimtask"))
        self.arrowKeys.destroy()
        del self.arrowKeys
        DistributedMinigame.DistributedMinigame.offstage(self)

    def handleDisabledAvatar(self, avId):
        self.notify.debug("handleDisabledAvatar")
        self.notify.debug("avatar " + str(avId) + " disabled")
        DistributedMinigame.DistributedMinigame.handleDisabledAvatar(self, avId)

    def setGameReady(self):
        if not self.hasLocalToon:
            return
        self.notify.debug("setGameReady")
        if DistributedMinigame.DistributedMinigame.setGameReady(self):
            return
        for index in xrange(self.numPlayers):
            avId = self.avIdList[index]
            toon = self.getAvatar(avId)
            if toon:
                toon.reparentTo(render)
                self.__placeToon(avId)
                toon.forwardSpeed = 0
                toon.rotateSpeed = False
                toon.dropShadow.hide()
                toon.setAnimState("Sit")
                if avId in self.tireDict:
                    tireNp = self.tireDict[avId]["tireNodePath"]
                    toon.reparentTo(tireNp)
                    toon.setY(1.0)
                    toon.setZ(-3)
                toon.startLookAround()

    def setGameStart(self, timestamp):
        if not self.hasLocalToon:
            return
        self.notify.debug("setGameStart")
        DistributedMinigame.DistributedMinigame.setGameStart(self, timestamp)
        for avId in self.remoteAvIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.stopLookAround()

        self.scores = [0] * self.numPlayers
        spacing = 0.4
        for i in xrange(self.numPlayers):
            avId = self.avIdList[i]
            avName = self.getAvatarName(avId)
            scorePanel = MinigameAvatarScorePanel.MinigameAvatarScorePanel(avId, avName)
            scorePanel.setScale(0.9)
            scorePanel.setPos(-0.583 - spacing * (self.numPlayers - 1 - i), 0.0, -0.15)
            scorePanel.reparentTo(base.a2dTopRight)
            scorePanel.makeTransparent(0.75)
            self.scorePanels.append(scorePanel)

        self.arrowKeys.setPressHandlers(
            [
                self.__upArrowPressed,
                self.__downArrowPressed,
                self.__leftArrowPressed,
                self.__rightArrowPressed,
                self.__controlPressed,
            ]
        )

    def isInPlayState(self):
        if not self.gameFSM.getCurrentState():
            return False
        if not self.gameFSM.getCurrentState().getName() == "play":
            return False
        return True

    def enterOff(self):
        self.notify.debug("enterOff")

    def exitOff(self):
        pass

    def enterInputChoice(self):
        self.notify.debug("enterInputChoice")
        self.forceLocalToonToTire()
        self.controlKeyPressed = False
        if self.curRound == 0:
            self.setupStartOfMatch()
        else:
            self.notify.debug("self.curRound = %s" % self.curRound)
        self.timer = ToontownTimer.ToontownTimer()
        self.timer.hide()
        if self.timerStartTime != None:
            self.startTimer()
        self.showForceArrows(realPlayersOnly=True)
        self.localForceArrow().setPosHpr(0, 0, -1.0, 0, 0, 0)
        self.localForceArrow().reparentTo(self.localTireNp())
        self.localForceArrow().setY(IceGameGlobals.TireRadius)
        self.localTireNp().headsUp(self.target)
        self.notify.debug("self.localForceArrow() heading = %s" % self.localForceArrow().getH())
        self.curHeading = self.localTireNp().getH()
        self.curForce = 25
        self.updateLocalForceArrow()
        for avId in self.forceArrowDict:
            forceArrow = self.forceArrowDict[avId]
            forceArrow.setPosHpr(0, 0, -1.0, 0, 0, 0)
            tireNp = self.tireDict[avId]["tireNodePath"]
            forceArrow.reparentTo(tireNp)
            forceArrow.setY(IceGameGlobals.TireRadius)
            tireNp.headsUp(self.target)
            self.updateForceArrow(avId, tireNp.getH(), 25)

        taskMgr.add(self.__aimTask, self.uniqueName("aimtask"))
        if base.localAvatar.laffMeter:
            base.localAvatar.laffMeter.stop()
        self.sendForceArrowUpdateAsap = False
        return

    def exitInputChoice(self):
        if not self.controlKeyPressed:
            if self.controlKeyWarningIval:
                self.controlKeyWarningIval.finish()
                self.controlKeyWarningIval = None
            self.controlKeyWarningIval = Sequence(
                Func(self.controlKeyWarningLabel.show),
                self.controlKeyWarningLabel.colorScaleInterval(
                    10, VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1, 1)
                ),
                Func(self.controlKeyWarningLabel.hide),
            )
            self.controlKeyWarningIval.start()
        if self.timer != None:
            self.timer.destroy()
            self.timer = None
        self.timerStartTime = None
        self.hideForceArrows()
        self.arrowRotateSound.stop()
        self.arrowUpSound.stop()
        self.arrowDownSound.stop()
        taskMgr.remove(self.uniqueName("aimtask"))
        return

    def enterWaitServerChoices(self):
        self.waitingMoveLabel.show()
        self.showForceArrows(True)

    def exitWaitServerChoices(self):
        self.waitingMoveLabel.hide()
        self.hideForceArrows()

    def enterMoveTires(self):
        for key in self.tireDict:
            body = self.tireDict[key]["tireBody"]
            body.setAngularVel(0, 0, 0)
            body.setLinearVel(0, 0, 0)

        for index in xrange(len(self.allTireInputs)):
            input = self.allTireInputs[index]
            avId = self.avIdList[index]
            body = self.getTireBody(avId)
            degs = input[1] + 90
            tireNp = self.getTireNp(avId)
            tireH = tireNp.getH()
            self.notify.debug("tireH = %s" % tireH)
            radAngle = deg2Rad(degs)
            foo = NodePath("foo")
            dirVector = Vec3(math.cos(radAngle), math.sin(radAngle), 0)
            self.notify.debug("dirVector is now=%s" % dirVector)
            inputForce = input[0]
            inputForce /= self.MaxLocalForce
            inputForce *= self.MaxPhysicsForce
            force = dirVector * inputForce
            self.notify.debug("adding force %s to %d" % (force, avId))
            body.addForce(force)

        self.enableAllTireBodies()
        self.totalPhysicsSteps = 0
        self.startSim()
        taskMgr.add(self.__moveTiresTask, self.uniqueName("moveTiresTtask"))

    def exitMoveTires(self):
        self.forceLocalToonToTire()
        self.disableAllTireBodies()
        self.stopSim()
        self.notify.debug("total Physics steps = %d" % self.totalPhysicsSteps)
        taskMgr.remove(self.uniqueName("moveTiresTtask"))

    def enterSynch(self):
        self.waitingSyncLabel.show()

    def exitSynch(self):
        self.waitingSyncLabel.hide()

    def enterScoring(self):
        sortedByDistance = []
        for avId in self.avIdList:
            np = self.getTireNp(avId)
            pos = np.getPos()
            pos.setZ(0)
            sortedByDistance.append((avId, pos.length()))

        def compareDistance(x, y):
            if x[1] - y[1] > 0:
                return 1
            elif x[1] - y[1] < 0:
                return -1
            else:
                return 0

        sortedByDistance.sort(cmp=compareDistance)
        self.scoreMovie = Sequence()
        curScale = 0.01
        curTime = 0
        self.scoreCircle.setScale(0.01)
        self.scoreCircle.show()
        self.notify.debug("newScores = %s" % self.newScores)
        circleStartTime = 0
        for index in xrange(len(sortedByDistance)):
            distance = sortedByDistance[index][1]
            avId = sortedByDistance[index][0]
            scorePanelIndex = self.avIdList.index(avId)
            time = (distance - curScale) / IceGameGlobals.ExpandFeetPerSec
            if time < 0:
                time = 0.01
            scaleXY = distance + IceGameGlobals.TireRadius
            self.notify.debug("circleStartTime = %s" % circleStartTime)
            self.scoreMovie.append(
                Parallel(
                    LerpScaleInterval(self.scoreCircle, time, Point3(scaleXY, scaleXY, 1.0)),
                    SoundInterval(self.scoreCircleSound, duration=time, startTime=circleStartTime),
                )
            )
            circleStartTime += time
            startScore = self.scorePanels[scorePanelIndex].getScore()
            destScore = self.newScores[scorePanelIndex]
            self.notify.debug("for avId %d, startScore=%d, newScores=%d" % (avId, startScore, destScore))

            def increaseScores(t, scorePanelIndex=scorePanelIndex, startScore=startScore, destScore=destScore):
                oldScore = self.scorePanels[scorePanelIndex].getScore()
                diff = destScore - startScore
                newScore = int(startScore + diff * t)
                if newScore > oldScore:
                    base.playSfx(self.countSound)
                self.scorePanels[scorePanelIndex].setScore(newScore)
                self.scores[scorePanelIndex] = newScore

            duration = (destScore - startScore) * IceGameGlobals.ScoreCountUpRate
            tireNp = self.tireDict[avId]["tireNodePath"]
            self.scoreMovie.append(
                Parallel(
                    LerpFunctionInterval(increaseScores, duration),
                    Sequence(
                        LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 0, 0, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0, VBase4(1, 1, 1, 1)),
                    ),
                )
            )
            curScale += distance

        self.scoreMovie.append(Func(self.sendUpdate, "reportScoringMovieDone", []))
        self.scoreMovie.start()

    def exitScoring(self):
        self.scoreMovie.finish()
        self.scoreMovie = None
        self.scoreCircle.hide()
        return

    def enterFinalResults(self):
        lerpTrack = Parallel()
        lerpDur = 0.5
        tY = 0.6
        bY = -0.05
        lX = -0.5
        cX = 0
        rX = 0.5
        scorePanelLocs = (
            ((cX, bY),),
            ((lX, bY), (rX, bY)),
            ((cX, tY), (lX, bY), (rX, bY)),
            ((lX, tY), (rX, tY), (lX, bY), (rX, bY)),
        )
        scorePanelLocs = scorePanelLocs[self.numPlayers - 1]
        for i in xrange(self.numPlayers):
            panel = self.scorePanels[i]
            pos = scorePanelLocs[i]
            panel.wrtReparentTo(aspect2d)
            lerpTrack.append(
                Parallel(
                    LerpPosInterval(panel, lerpDur, Point3(pos[0], 0, pos[1]), blendType="easeInOut"),
                    LerpScaleInterval(panel, lerpDur, Vec3(panel.getScale()) * 2.0, blendType="easeInOut"),
                )
            )

        self.showScoreTrack = Parallel(
            lerpTrack, Sequence(Wait(IceGameGlobals.ShowScoresDuration), Func(self.gameOver))
        )
        self.showScoreTrack.start()

    def exitFinalResults(self):
        self.showScoreTrack.pause()
        del self.showScoreTrack

    def enterCleanup(self):
        self.notify.debug("enterCleanup")
        if base.localAvatar.laffMeter:
            base.localAvatar.laffMeter.start()

    def exitCleanup(self):
        pass

    def __placeToon(self, avId):
        toon = self.getAvatar(avId)
        if toon:
            toon.setPos(0, 0, 0)
            toon.setHpr(0, 0, 0)

    def moveCameraToTop(self):
        camera.reparentTo(render)
        p = self.cameraThreeQuarterView
        camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5])

    def setupTire(self, avId, index):
        tireNp, tireBody, tireOdeGeom = self.createTire(index)
        self.tireDict[avId] = {"tireNodePath": tireNp, "tireBody": tireBody, "tireOdeGeom": tireOdeGeom}
        if avId <= 0:
            tireBlocker = tireNp.find("**/tireblockermesh")
            if not tireBlocker.isEmpty():
                tireBlocker.hide()
        if avId == self.localAvId:
            tireNp = self.tireDict[avId]["tireNodePath"]
            self.treasureSphereName = "treasureCollider"
            self.treasureCollSphere = CollisionSphere(0, 0, 0, IceGameGlobals.TireRadius)
            self.treasureCollSphere.setTangible(0)
            self.treasureCollNode = CollisionNode(self.treasureSphereName)
            self.treasureCollNode.setFromCollideMask(ToontownGlobals.PieBitmask)
            self.treasureCollNode.addSolid(self.treasureCollSphere)
            self.treasureCollNodePath = tireNp.attachNewNode(self.treasureCollNode)
            self.treasureHandler = CollisionHandlerEvent()
            self.treasureHandler.addInPattern("%fn-intoTreasure")
            base.cTrav.addCollider(self.treasureCollNodePath, self.treasureHandler)
            eventName = "%s-intoTreasure" % self.treasureCollNodePath.getName()
            self.notify.debug("eventName = %s" % eventName)
            self.accept(eventName, self.toonHitSomething)

    def setupForceArrow(self, avId):
        arrow = loader.loadModel("phase_4/models/minigames/ice_game_arrow")
        priority = 0
        if avId < 0:
            priority = -avId
        else:
            priority = self.avIdList.index(avId)
            if avId == self.localAvId:
                priority = 10
        self.forceArrowDict[avId] = arrow

    def hideForceArrows(self):
        for forceArrow in self.forceArrowDict.values():
            forceArrow.hide()

    def showForceArrows(self, realPlayersOnly=True):
        for avId in self.forceArrowDict:
            if realPlayersOnly:
                if avId > 0:
                    self.forceArrowDict[avId].show()
                else:
                    self.forceArrowDict[avId].hide()
            else:
                self.forceArrowDict[avId].show()

    def localForceArrow(self):
        if self.localAvId in self.forceArrowDict:
            return self.forceArrowDict[self.localAvId]
        else:
            return None
        return None

    def setChoices(self, input0, input1, input2, input3):
        pass

    def startDebugTask(self):
        taskMgr.add(self.debugTask, self.debugTaskName)

    def stopDebugTask(self):
        taskMgr.remove(self.debugTaskName)

    def debugTask(self, task):
        if self.canDrive and self.tireDict.has_key(localAvatar.doId):
            dt = globalClock.getDt()
            forceMove = 25000
            forceMoveDt = forceMove
            tireBody = self.tireDict[localAvatar.doId]["tireBody"]
            if self.arrowKeys.upPressed() and not tireBody.isEnabled():
                x = 0
                y = 1
                tireBody.enable()
                tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))
            if self.arrowKeys.downPressed() and not tireBody.isEnabled():
                x = 0
                y = -1
                tireBody.enable()
                tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))
            if self.arrowKeys.leftPressed() and not tireBody.isEnabled():
                x = -1
                y = 0
                tireBody.enable()
                tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))
            if self.arrowKeys.rightPressed() and not tireBody.isEnabled():
                x = 1
                y = 0
                tireBody.enable()
                tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))
        return task.cont

    def __upArrowPressed(self):
        pass

    def __downArrowPressed(self):
        pass

    def __leftArrowPressed(self):
        pass

    def __rightArrowPressed(self):
        pass

    def __controlPressed(self):
        if self.gameFSM.getCurrentState().getName() == "inputChoice":
            self.sendForceArrowUpdateAsap = True
            self.updateLocalForceArrow()
            self.controlKeyPressed = True
            self.sendUpdate("setAvatarChoice", [self.curForce, self.curHeading])
            self.gameFSM.request("waitServerChoices")

    def startTimer(self):
        now = globalClock.getFrameTime()
        elapsed = now - self.timerStartTime
        self.timer.posInTopRightCorner()
        self.timer.setTime(IceGameGlobals.InputTimeout)
        self.timer.countdown(IceGameGlobals.InputTimeout - elapsed, self.handleChoiceTimeout)
        self.timer.show()

    def setTimerStartTime(self, timestamp):
        if not self.hasLocalToon:
            return
        self.timerStartTime = globalClockDelta.networkToLocalTime(timestamp)
        if self.timer != None:
            self.startTimer()
        return

    def handleChoiceTimeout(self):
        self.sendUpdate("setAvatarChoice", [0, 0])
        self.gameFSM.request("waitServerChoices")

    def localTireNp(self):
        ret = None
        if self.localAvId in self.tireDict:
            ret = self.tireDict[self.localAvId]["tireNodePath"]
        return ret

    def localTireBody(self):
        ret = None
        if self.localAvId in self.tireDict:
            ret = self.tireDict[self.localAvId]["tireBody"]
        return ret

    def getTireBody(self, avId):
        ret = None
        if avId in self.tireDict:
            ret = self.tireDict[avId]["tireBody"]
        return ret

    def getTireNp(self, avId):
        ret = None
        if avId in self.tireDict:
            ret = self.tireDict[avId]["tireNodePath"]
        return ret

    def updateForceArrow(self, avId, curHeading, curForce):
        forceArrow = self.forceArrowDict[avId]
        tireNp = self.tireDict[avId]["tireNodePath"]
        tireNp.setH(curHeading)
        tireBody = self.tireDict[avId]["tireBody"]
        tireBody.setQuaternion(tireNp.getQuat())
        self.notify.debug("curHeading = %s" % curHeading)
        yScale = curForce / 100.0
        yScale *= 1
        headY = yScale * 15
        xScale = (yScale - 1) / 2.0 + 1.0
        shaft = forceArrow.find("**/arrow_shaft")
        head = forceArrow.find("**/arrow_head")
        shaft.setScale(xScale, yScale, 1)
        head.setPos(0, headY, 0)
        head.setScale(xScale, xScale, 1)

    def updateLocalForceArrow(self):
        avId = self.localAvId
        self.b_setForceArrowInfo(avId, self.curHeading, self.curForce)

    def __aimTask(self, task):
        if not hasattr(self, "arrowKeys"):
            return task.done
        dt = globalClock.getDt()
        headingMomentumChange = dt * 60.0
        forceMomentumChange = dt * 160.0
        arrowUpdate = False
        arrowRotating = False
        arrowUp = False
        arrowDown = False
        if self.arrowKeys.upPressed() and not self.arrowKeys.downPressed():
            self.forceMomentum += forceMomentumChange
            if self.forceMomentum < 0:
                self.forceMomentum = 0
            if self.forceMomentum > 50:
                self.forceMomentum = 50
            oldForce = self.curForce
            self.curForce += self.forceMomentum * dt
            arrowUpdate = True
            if oldForce < self.MaxLocalForce:
                arrowUp = True
        elif self.arrowKeys.downPressed() and not self.arrowKeys.upPressed():
            self.forceMomentum += forceMomentumChange
            if self.forceMomentum < 0:
                self.forceMomentum = 0
            if self.forceMomentum > 50:
                self.forceMomentum = 50
            oldForce = self.curForce
            self.curForce -= self.forceMomentum * dt
            arrowUpdate = True
            if oldForce > 0.01:
                arrowDown = True
        else:
            self.forceMomentum = 0
        if self.arrowKeys.leftPressed() and not self.arrowKeys.rightPressed():
            self.headingMomentum += headingMomentumChange
            if self.headingMomentum < 0:
                self.headingMomentum = 0
            if self.headingMomentum > 50:
                self.headingMomentum = 50
            self.curHeading += self.headingMomentum * dt
            arrowUpdate = True
            arrowRotating = True
        elif self.arrowKeys.rightPressed() and not self.arrowKeys.leftPressed():
            self.headingMomentum += headingMomentumChange
            if self.headingMomentum < 0:
                self.headingMomentum = 0
            if self.headingMomentum > 50:
                self.headingMomentum = 50
            self.curHeading -= self.headingMomentum * dt
            arrowUpdate = True
            arrowRotating = True
        else:
            self.headingMomentum = 0
        if arrowUpdate:
            self.normalizeHeadingAndForce()
            self.updateLocalForceArrow()
        if arrowRotating:
            if not self.arrowRotateSound.status() == self.arrowRotateSound.PLAYING:
                base.playSfx(self.arrowRotateSound, looping=True)
        else:
            self.arrowRotateSound.stop()
        if arrowUp:
            if not self.arrowUpSound.status() == self.arrowUpSound.PLAYING:
                base.playSfx(self.arrowUpSound, looping=False)
        else:
            self.arrowUpSound.stop()
        if arrowDown:
            if not self.arrowDownSound.status() == self.arrowDownSound.PLAYING:
                base.playSfx(self.arrowDownSound, looping=False)
        else:
            self.arrowDownSound.stop()
        return task.cont

    def normalizeHeadingAndForce(self):
        if self.curForce > self.MaxLocalForce:
            self.curForce = self.MaxLocalForce
        if self.curForce < 0.01:
            self.curForce = 0.01

    def setTireInputs(self, tireInputs):
        if not self.hasLocalToon:
            return
        self.allTireInputs = tireInputs
        self.gameFSM.request("moveTires")

    def enableAllTireBodies(self):
        for avId in self.tireDict.keys():
            self.tireDict[avId]["tireBody"].enable()

    def disableAllTireBodies(self):
        for avId in self.tireDict.keys():
            self.tireDict[avId]["tireBody"].disable()

    def areAllTiresDisabled(self):
        for avId in self.tireDict.keys():
            if self.tireDict[avId]["tireBody"].isEnabled():
                return False

        return True

    def __moveTiresTask(self, task):
        if self.areAllTiresDisabled():
            self.sendTirePositions()
            self.gameFSM.request("synch")
            return task.done
        return task.cont

    def sendTirePositions(self):
        tirePositions = []
        for index in xrange(len(self.avIdList)):
            avId = self.avIdList[index]
            tire = self.getTireBody(avId)
            pos = Point3(tire.getPosition())
            tirePositions.append([pos[0], pos[1], pos[2]])

        for index in xrange(len(self.avIdList), 4):
            avId = -index
            tire = self.getTireBody(avId)
            pos = Point3(tire.getPosition())
            tirePositions.append([pos[0], pos[1], pos[2]])

        self.sendUpdate("endingPositions", [tirePositions])

    def setFinalPositions(self, finalPos):
        if not self.hasLocalToon:
            return
        for index in xrange(len(self.avIdList)):
            avId = self.avIdList[index]
            tire = self.getTireBody(avId)
            np = self.getTireNp(avId)
            pos = finalPos[index]
            tire.setPosition(pos[0], pos[1], pos[2])
            np.setPos(pos[0], pos[1], pos[2])

        for index in xrange(len(self.avIdList), 4):
            avId = -index
            tire = self.getTireBody(avId)
            np = self.getTireNp(avId)
            pos = finalPos[index]
            tire.setPosition(pos[0], pos[1], pos[2])
            np.setPos(pos[0], pos[1], pos[2])

    def updateInfoLabel(self):
        self.infoLabel["text"] = TTLocalizer.IceGameInfo % {
            "curMatch": self.curMatch + 1,
            "numMatch": IceGameGlobals.NumMatches,
            "curRound": self.curRound + 1,
            "numRound": IceGameGlobals.NumRounds,
        }

    def setMatchAndRound(self, match, round):
        if not self.hasLocalToon:
            return
        self.curMatch = match
        self.curRound = round
        self.updateInfoLabel()

    def setScores(self, match, round, scores):
        if not self.hasLocalToon:
            return
        self.newMatch = match
        self.newRound = round
        self.newScores = scores

    def setNewState(self, state):
        if not self.hasLocalToon:
            return
        self.notify.debug("setNewState gameFSM=%s newState=%s" % (self.gameFSM, state))
        self.gameFSM.request(state)

    def putAllTiresInStartingPositions(self):
        for index in xrange(len(self.avIdList)):
            avId = self.avIdList[index]
            np = self.tireDict[avId]["tireNodePath"]
            np.setPos(IceGameGlobals.StartingPositions[index])
            self.notify.debug("avId=%s newPos=%s" % (avId, np.getPos))
            np.setHpr(0, 0, 0)
            quat = np.getQuat()
            body = self.tireDict[avId]["tireBody"]
            body.setPosition(IceGameGlobals.StartingPositions[index])
            body.setQuaternion(quat)

        for index in xrange(len(self.avIdList), 4):
            avId = -index
            np = self.tireDict[avId]["tireNodePath"]
            np.setPos(IceGameGlobals.StartingPositions[index])
            self.notify.debug("avId=%s newPos=%s" % (avId, np.getPos))
            np.setHpr(0, 0, 0)
            quat = np.getQuat()
            body = self.tireDict[avId]["tireBody"]
            body.setPosition(IceGameGlobals.StartingPositions[index])
            body.setQuaternion(quat)

    def b_setForceArrowInfo(self, avId, force, heading):
        self.setForceArrowInfo(avId, force, heading)
        self.d_setForceArrowInfo(avId, force, heading)

    def d_setForceArrowInfo(self, avId, force, heading):
        sendIt = False
        curTime = self.getCurrentGameTime()
        if self.sendForceArrowUpdateAsap:
            sendIt = True
        elif curTime - self.lastForceArrowUpdateTime > 0.2:
            sendIt = True
        if sendIt:
            self.sendUpdate("setForceArrowInfo", [avId, force, heading])
            self.sendForceArrowUpdateAsap = False
            self.lastForceArrowUpdateTime = self.getCurrentGameTime()

    def setForceArrowInfo(self, avId, force, heading):
        if not self.hasLocalToon:
            return
        self.updateForceArrow(avId, force, heading)

    def setupStartOfMatch(self):
        self.putAllTiresInStartingPositions()
        szId = self.getSafezoneId()
        self.numTreasures = IceGameGlobals.NumTreasures[szId]
        if self.treasures:
            for treasure in self.treasures:
                treasure.destroy()

            self.treasures = []
        index = 0
        treasureMargin = IceGameGlobals.TireRadius + 1.0
        while len(self.treasures) < self.numTreasures:
            xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5)
            yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5)
            self.notify.debug("yPos=%s" % yPos)
            pos = Point3(xPos, yPos, IceGameGlobals.TireRadius)
            newTreasure = IceTreasure.IceTreasure(self.treasureModel, pos, index, self.doId, penalty=False)
            goodSpot = True
            for obstacle in self.obstacles:
                if newTreasure.nodePath.getDistance(obstacle) < treasureMargin:
                    goodSpot = False
                    break

            if goodSpot:
                for treasure in self.treasures:
                    if newTreasure.nodePath.getDistance(treasure.nodePath) < treasureMargin:
                        goodSpot = False
                        break

            if goodSpot:
                self.treasures.append(newTreasure)
                index += 1
            else:
                newTreasure.destroy()

        self.numPenalties = IceGameGlobals.NumPenalties[szId]
        if self.penalties:
            for penalty in self.penalties:
                penalty.destroy()

            self.penalties = []
        index = 0
        while len(self.penalties) < self.numPenalties:
            xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5, IceGameGlobals.MaxWall[0] - 5)
            yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5, IceGameGlobals.MaxWall[1] - 5)
            self.notify.debug("yPos=%s" % yPos)
            pos = Point3(xPos, yPos, IceGameGlobals.TireRadius)
            newPenalty = IceTreasure.IceTreasure(self.penaltyModel, pos, index, self.doId, penalty=True)
            goodSpot = True
            for obstacle in self.obstacles:
                if newPenalty.nodePath.getDistance(obstacle) < treasureMargin:
                    goodSpot = False
                    break

            if goodSpot:
                for treasure in self.treasures:
                    if newPenalty.nodePath.getDistance(treasure.nodePath) < treasureMargin:
                        goodSpot = False
                        break

            if goodSpot:
                for penalty in self.penalties:
                    if newPenalty.nodePath.getDistance(penalty.nodePath) < treasureMargin:
                        goodSpot = False
                        break

            if goodSpot:
                self.penalties.append(newPenalty)
                index += 1
            else:
                newPenalty.destroy()

    def toonHitSomething(self, entry):
        self.notify.debug("---- treasure Enter ---- ")
        self.notify.debug("%s" % entry)
        name = entry.getIntoNodePath().getName()
        parts = name.split("-")
        if len(parts) < 3:
            self.notify.debug("collided with %s, but returning" % name)
            return
        if not int(parts[1]) == self.doId:
            self.notify.debug("collided with %s, but doId doesn't match" % name)
            return
        treasureNum = int(parts[2])
        if "penalty" in parts[0]:
            self.__penaltyGrabbed(treasureNum)
        else:
            self.__treasureGrabbed(treasureNum)

    def __treasureGrabbed(self, treasureNum):
        self.treasures[treasureNum].showGrab()
        self.treasureGrabSound.play()
        self.sendUpdate("claimTreasure", [treasureNum])

    def setTreasureGrabbed(self, avId, treasureNum):
        if not self.hasLocalToon:
            return
        self.notify.debug("treasure %s grabbed by %s" % (treasureNum, avId))
        if avId != self.localAvId:
            self.treasures[treasureNum].showGrab()
        i = self.avIdList.index(avId)
        self.scores[i] += 1
        self.scorePanels[i].setScore(self.scores[i])

    def __penaltyGrabbed(self, penaltyNum):
        self.penalties[penaltyNum].showGrab()
        self.sendUpdate("claimPenalty", [penaltyNum])

    def setPenaltyGrabbed(self, avId, penaltyNum):
        if not self.hasLocalToon:
            return
        self.notify.debug("penalty %s grabbed by %s" % (penaltyNum, avId))
        if avId != self.localAvId:
            self.penalties[penaltyNum].showGrab()
        i = self.avIdList.index(avId)
        self.scores[i] -= 1
        self.scorePanels[i].setScore(self.scores[i])

    def postStep(self):
        DistributedIceWorld.DistributedIceWorld.postStep(self)
        if not self.colCount:
            return
        for count in xrange(self.colCount):
            c0, c1 = self.getOrderedContacts(count)
            if c1 in self.tireCollideIds:
                tireIndex = self.tireCollideIds.index(c1)
                if c0 in self.tireCollideIds:
                    self.tireSounds[tireIndex]["tireHit"].play()
                elif c0 == self.wallCollideId:
                    self.tireSounds[tireIndex]["wallHit"].play()
                elif c0 == self.obstacleCollideId:
                    self.tireSounds[tireIndex]["obstacleHit"].play()

    def forceLocalToonToTire(self):
        toon = localAvatar
        if toon and self.localAvId in self.tireDict:
            tireNp = self.tireDict[self.localAvId]["tireNodePath"]
            toon.reparentTo(tireNp)
            toon.setPosHpr(0, 0, 0, 0, 0, 0)
            toon.setY(1.0)
            toon.setZ(-3)
예제 #16
0
 def _createQuadrant(self, filepath, serialNum, angle, size):
     root = NodePath('QuadrantRoot-%i' % serialNum)
     quadrant = loader.loadModel(filepath)
     quadrant.getChildren().reparentTo(root)
     root.setH(angle)
     return root
class GameOverNotification(object):

	def __init__(self,cameraX,cameraY,cameraZ,cameraAngle):
		self.ticks=0
		self.endOfLife=False
		self.currentLetterAngle=0.0
		self.letterNodes=[]
		self.distance=200
		self.closestDistance=20
		self.endOfLifeTicks=400
		self.cameraX=cameraX
		self.reduceSpinning=False
		self.spinningChange=5.0
		self.minimumSpinning=False
		self.stoppedMoving=False

		self.gameOverContainerNode=NodePath("GameOverContainer")
		self.gameOverContainerNode.reparentTo(render)
		self.gameOverContainerNode.setPos(cameraX,cameraY,cameraZ-0.85)

		self.gameOverNode=self.getGameOverNode()
		self.gameOverNode.reparentTo(self.gameOverContainerNode)

		angle=cameraAngle-90
		if angle<0.0:
			angle=angle+360.0

		self.gameOverContainerNode.setH(angle)

	def advanceTime(self):
		if self.stoppedMoving:
			self.ticksUntilDeath=self.ticksUntilDeath-1
			if self.ticksUntilDeath==0:
				self.endOfLife=True
		else:
			self.currentLetterAngle=self.currentLetterAngle+self.spinningChange
			if self.currentLetterAngle>360.0:
				if self.minimumSpinning:
					self.stoppedMoving=True
					self.ticksUntilDeath=120
				else:
					self.currentLetterAngle=self.currentLetterAngle-360.0

		if not self.reduceSpinning:
			self.distance=self.distance-1
			if self.distance<=self.closestDistance:
				self.distance=self.closestDistance
				self.reduceSpinning=True

		if self.reduceSpinning:
			if self.spinningChange>1.75:
				self.spinningChange=self.spinningChange-0.05
			else:
				self.minimumSpinning=True
			
		self.gameOverNode.setY(self.distance)
		for letterNode in self.letterNodes:
			letterNode.setH(self.currentLetterAngle)

	def getGameOverNode(self):
		gameOverNode=NodePath("GameOver")

		letterGeometry=LetterGeometry.getCardGeometryByPhrase('game over')

		for letter in letterGeometry:
			letterCm=CardMaker('card')
			letterCm.setFrame(letter['left'],letter['right'],letter['top'],letter['bottom'])
			letterNode=gameOverNode.attachNewNode(letterCm.generate())
			self.letterNodes.append(letterNode)
			letterNode.setTwoSided(True)
			letterNode.setTransparency(TransparencyAttrib.MAlpha)
			letterNode.setBin('unsorted',50)
			letterNode.setDepthTest(False)
			letterNode.setDepthWrite(False)
			tex=loader.loadTexture('textures/letter-'+letter['letter']+'.png')
			tex.setWrapU(Texture.WMClamp)
			tex.setWrapV(Texture.WMClamp)
			letterNode.setTexture(tex)
			letterNode.setPos(letter['originx'],letter['originy'],0)
	
		return gameOverNode

	def setCompletionEvent(self,completionEvent):
		self.completionEvent=completionEvent

	def getCompletionEvent(self):
		return self.completionEvent

	def hasDied(self):
		return self.endOfLife

	def delete(self):
		self.gameOverContainerNode.removeNode()
예제 #18
0
파일: entity.py 프로젝트: asceth/devsyn
class Entity(DirectObject, object):
  def __init__(self, model = None):
    self.prime = None
    if model != None:
      self.set_model(model)

  def get_model(self):
    return self.prime

  def set_model(self, model):
    if model != None:
      if isinstance(model, PandaNode):
        self.prime = NodePath(model)
      elif isinstance(model, NodePath):
        self.prime = model
      else:
        if Filename(model).exists():
          self.model = Filename(model).getBasenameWoExtension()
          path = model
        else:
          if isinstance(model, Filename):
            self.model = model.getBasenameWoExtension()
            path = model.getFullpath()
          else:
            path = APP_PATH + model

          print "path: ", path
          if Filename(path).exists():
            pass
          elif Filename(path + ".bam").exists():
            path += ".bam"
          elif Filename(path + ".bam.pz").exists():
            path += ".bam.pz"
          elif Filename(path + ".egg").exists():
            path += ".egg"
          elif Filename(path + ".egg.pz").exists():
            path += ".egg.pz"
          elif Filename(path + ".x").exists():
            path += ".x"
          else:
            print ":object(error): can't find model", model, "!"
            # Probably shouldn't exit because of this
            sys.exit(1)
          self.model = model
        self.prime = base.loader.loadModel(path)
        if self.prime == None:
          print ":object(error): can't load model", model, "!"
          # Probably shouldn't exit because of this
          sys.exit(1)

  def getX(self):
    return self.prime.getX(base.render)

  def getY(self):
    return self.prime.getY(base.render)

  def getZ(self):
    return self.prime.getZ(base.render)

  def getH(self):
    return self.prime.getH(base.render)

  def getP(self):
    return self.prime.getP(base.render)

  def getR(self):
    return self.prime.getR(base.render)

  def getSx(self):
    return self.prime.getSx(base.render)

  def getSy(self):
    return self.prime.getSy(base.render)

  def getSz(self):
    return self.prime.getSz(base.render)

  def getPos(self):
    return self.prime.getPos(base.render)

  def getHpr(self):
    return self.prime.getHpr(base.render)

  def getScale(self):
    return self.prime.getScale(base.render)

  def getCollideMask(self):
    return self.prime.getCollideMask()

  def getTransparency(self):
    return self.prime.getTransparency()

  def getTwoSided(self):
    return self.prime.getTwoSided()

  def getParent(self):
    return self.prime.getParent()

  def setX(self, *v):
    self.prime.setX(*v)

  def setY(self, *v):
    self.prime.setY(*v)

  def setZ(self, *v):
    self.prime.setZ(*v)

  def setH(self, *v):
    self.prime.setH(*v)

  def setP(self, *v):
    self.prime.setP(*v)

  def setR(self, *v):
    self.prime.setR(*v)

  def setSx(self, *v):
    self.prime.setSx(*v)

  def setSy(self, *v):
    self.prime.setSy(*v)

  def setSz(self, *v):
    self.prime.setSz(*v)

  def setPos(self, *v):
    self.prime.setPos(*v)

  def setHpr(self, *v):
    self.prime.setHpr(*v)

  def setScale(self, *v):
    self.prime.setScale(*v)

  def setCollideMask(self, *v):
    self.prime.setCollideMask(*v)

  def setTransparency(self, *v):
    self.prime.setTransparency(*v)

  def setTwoSided(self, *v):
    self.prime.setTwoSided(*v)

  def removeNode(self):
    self.prime.removeNode()

  def reparentTo(self, parent):
    if isinstance(parent, Entity):
      parent = parent.prime
    if isinstance(parent, str):
      if parent.startswith("render/"):
        parent = parent[7:]
        tv = parent
        parent = base.render.find(tv)
        if parent == NodePath():
          parent = base.render.find("**/" + tv)
    if parent != NodePath() and parent != None:
      self.prime.reparentTo(parent)

  def wrtReparentTo(self, parent):
    if isinstance(parent, Entity):
      parent = parent.prime
    if isinstance(parent, str):
      if parent.startswith("render/"):
        parent = parent[7:]
        tv = parent
        parent = base.render.find(tv)
        if parent == NodePath():
          parent = base.render.find("**/" + tv)
    if parent != NodePath():
      self.prime.reparentTo(parent)

  def attachTo(self, parent):
    """This attaches the object to another object/nodepath. The caller object stays at the same place, with the same scale and rotation,
    but they become relative to the other object/nodepath. This is useful with for example a character that steps onto a moving ship or so."""
    if isinstance(parent, Entity):
      parent = parent.prime
    if isinstance(parent, str):
      if(parent.startswith("render/")): parent = parent[7:]
      tv = parent
      parent = base.render.find(tv)
      if(parent == NodePath()):
        parent = base.render.find("**/" + tv)
    if(parent != NodePath()):
      self.prime.setPos(self.prime.getPos(parent))
      self.prime.setHpr(self.prime.getHpr(parent))
      self.prime.setScale(self.prime.getScale(parent))
      self.prime.reparentTo(parent)

  def hide(self):
    self.prime.hide()

  def show(self):
    self.prime.show()

  def __del__(self):
    try:
      if isinstance(self.prime, NodePath):
        self.prime.removeNode()
    except AttributeError: pass

  def __getstate__(self):
    return [self.model, self.getX(), self.getY(), self.getZ(), self.getH(),
            self.getP(), self.getR(), self.getSx(), self.getSy(),
            self.getSz(), self.getCollideMask().getWord(),
            self.getTransparency(), self.getTwoSided(), str(self.getParent())]

  def __setstate__(self, p):
    if len(p) < 14:
      print ":object(error): This state is not compatible with this version!"
      sys.exit(1)

    self.setModel(p[0])
    self.setX(p[1])
    self.setY(p[2])
    self.setZ(p[3])
    self.setH(p[4])
    self.setP(p[5])
    self.setR(p[6])
    self.setSx(p[7])
    self.setSy(p[8])
    self.setSz(p[9])
    self.setCollideMask(BitMask32(p[10]))
    self.setTransparency(p[11])
    self.setTwoSided(p[12])
    self.reparentTo(p[13])
예제 #19
0
def generateHullCache(modelClass):
    geom = loader.loadModel("models/shipparts/pir_m_shp_%s" % HullDict[modelClass])
    stripPrefix(geom, "model:")
    for node in geom.findAllMatches("**/omit"):
        parent = node.getParent()
        omit = parent.attachNewNode(ModelNode("omit"))
        node.reparentTo(omit)
        node.setName("geom")

    preFlatten(geom)
    logic = loader.loadModel("models/shipparts/pir_m_shp_%s_logic" % HullDict[modelClass])
    locators = logic.find("**/locators")
    for side in ["left", "right"]:
        bad = locators.find("**/location_ropeLadder_0_%s" % side)
        if bad:
            bad.setName("location_ropeLadder_%s_0" % side)

        bad = locators.find("**/location_ropeLadder_1_%s" % side)
        if bad:
            bad.setName("location_ropeLadder_%s_1" % side)

        bad = locators.find("**/location_ropeLadder_1_%s1" % side)
        if bad:
            bad.setName("location_ropeLadder_%s_2" % side)
            continue

    collisions = logic.find("**/collisions")
    badPanel = collisions.find("**/collision_panel_3")
    if badPanel:
        badPanel.setName("collision_panel_2")

    collisions.find("**/collision_panel_0").setTag("Hull Code", "0")
    collisions.find("**/collision_panel_1").setTag("Hull Code", "1")
    collisions.find("**/collision_panel_2").setTag("Hull Code", "2")
    walls = collisions.find("**/collision_walls")
    if walls:
        walls.setTag("Hull Code", "255")
    else:
        collisions.attachNewNode("collision_walls")
    shipToShipCollide = collisions.find("**/collision_shiptoship")
    shipToShipCollide.setCollideMask(PiratesGlobals.ShipCollideBitmask)
    deck = collisions.find("**/collision_deck")
    if not deck:
        deck = collisions.attachNewNode("deck")

    mask = deck.getCollideMask()
    mask ^= PiratesGlobals.FloorBitmask
    mask |= PiratesGlobals.ShipFloorBitmask
    deck.setCollideMask(mask)
    floors = collisions.find("**/collision_floors")
    if not floors:
        floors = collisions.find("**/collision_floor")

    mask = floors.getCollideMask()
    mask ^= PiratesGlobals.FloorBitmask
    mask |= PiratesGlobals.ShipFloorBitmask
    floors.setCollideMask(mask)
    floors.setTag("Hull Code", str(255))
    geomHigh = geom.find("**/lod_high")
    geomMed = geom.find("**/lod_medium")
    if not geomMed:
        geomMed = geom.find("**/low_medium")

    if not geomMed:
        geomMed = geomHigh.copyTo(NodePath())

    geomLow = geom.find("**/lod_low")
    if not geomLow:
        geomLow = geomMed.copyTo(NodePath())

    geomSuperLow = geom.find("**/lod_superlow")
    if not geomSuperLow:
        geomSuperLow = geomLow.copyTo(NodePath())

    geomHigh.setName("high")
    geomMed.setName("med")
    geomLow.setName("low")
    geomSuperLow.setName("superlow")
    if modelClass in [21, 22, 23]:
        spike = loader.loadModel("models/shipparts/pir_m_shp_ram_spike")
        spikeTrans = locators.find("**/location_ram").getTransform(locators)
        spike.setTransform(spikeTrans)
        spike.flattenLight()
        spikeHi = spike.find("**/lod_high")
        spikeMed = spike.find("**/lod_medium")
        spikeLow = spike.find("**/lod_low")
        spikeHi.copyTo(geomHigh)
        spikeMed.copyTo(geomMed)
        spikeLow.copyTo(geomLow)
        spikeLow.copyTo(geomSuperLow)

    flipRoot = NodePath("root")
    collisions.reparentTo(flipRoot)
    locators.reparentTo(flipRoot)
    geomHigh.reparentTo(flipRoot)
    geomMed.reparentTo(flipRoot)
    geomLow.reparentTo(flipRoot)
    geomSuperLow.reparentTo(flipRoot)
    flipRoot.setH(180)
    flipRoot.flattenLight()
    omits = flipRoot.findAllMatches("**/omit")
    for node in omits:
        node.flattenStrong()

    for group in ["static", "transparent", "ropeLadder_*", "stripeA", "stripeB", "pattern"]:
        for node in flipRoot.findAllMatches("**/%s" % group):
            name = node.getName()
            for subNode in node.findAllMatches("**/*"):
                subNode.setName(name)

            node.flattenStrong()
            node.setName(name)

    geomHigh.detachNode()
    geomMed.detachNode()
    geomLow.detachNode()
    geomSuperLow.detachNode()
    locators.detachNode()
    collisions.detachNode()
    genericGeoms = [geomHigh, geomMed, geomLow, geomSuperLow]
    customGeoms = [x.copyTo(NodePath()) for x in genericGeoms]
    for np in genericGeoms:
        trans = np.find("**/transparent")
        if trans:
            trans.stash()

        np.flattenLight()
        sails = np.findAllMatches("**/sails")
        sails.stash()
        omits = np.findAllMatches("**/omit")
        omits.stash()
        for node in omits:
            node.node().setPreserveTransform(node.node().PTDropNode)

        generic = NodePath("generic")
        np.findAllMatches("**/+GeomNode").wrtReparentTo(generic)
        np.findAllMatches("*").detach()
        generic.flattenStrong()
        generic.reparentTo(np)
        stripAttribs(generic, TextureAttrib)
        stripAttribs(generic, TransparencyAttrib)
        stripAttribs(generic, CullBinAttrib)
        generic.setBin("ground", 1)
        collapse(generic)
        sails.unstash()
        sails.reparentTo(np)
        for node in sails:
            node.node().setPreserveTransform(node.node().PTDropNode)

        if trans:
            trans.unstash()
            trans.flattenStrong()
            if trans.node().isOfType(ModelNode.getClassType()):
                trans.node().setPreserveTransform(ModelNode.PTDropNode)

        deck = np.find("**/=cam=shground")
        if deck:
            deck.setName("deck")

        omits.unstash()

    for np in customGeoms:
        collapse(np.find("**/static"))

    data = HullCache()
    data.root = NodePath("hull")
    data.genericGeoms = genericGeoms
    data.customGeoms = customGeoms
    data.collisions = collisions
    data.locators = locators
    return data
class DistributedPartyActivity(DistributedObject.DistributedObject):
    deferFor = 1

    def __init__(self, cr, activityId, activityType, wantLever = False, wantRewardGui = False):
        DistributedObject.DistributedObject.__init__(self, cr)
        self.activityId = activityId
        self.activityName = PartyGlobals.ActivityIds.getString(self.activityId)
        self.activityType = activityType
        self.wantLever = wantLever
        self.wantRewardGui = wantRewardGui
        self.messageGui = None
        self.rewardGui = None
        self.toonIds = []
        self._toonId2ror = {}
        childName = '%s' % self
        childName = childName[childName.rfind('.DistributedParty') + len('.DistributedParty'):childName.rfind('Activity instance')]
        if not hasattr(base, 'partyActivityDict'):
            base.partyActivityDict = {}
        base.partyActivityDict[childName] = self
        self.root = NodePath('root')
        self.rulesDoneEvent = 'rulesDone'
        self.modelCount = 500
        self.cleanupActions = []
        self.usesSmoothing = 0
        self.usesLookAround = 0
        self.difficultyOverride = None
        self.trolleyZoneOverride = None
        self._localToonRequestStatus = None
        return

    def localToonExiting(self):
        self._localToonRequestStatus = PartyGlobals.ActivityRequestStatus.Exiting

    def localToonJoining(self):
        self._localToonRequestStatus = PartyGlobals.ActivityRequestStatus.Joining

    def d_toonJoinRequest(self):
        if self._localToonRequestStatus is None:
            self.localToonJoining()
            self.sendUpdate('toonJoinRequest')
        return

    def d_toonExitRequest(self):
        if self._localToonRequestStatus is None:
            self.localToonExiting()
            self.sendUpdate('toonExitRequest')
        return

    def d_toonExitDemand(self):
        self.localToonExiting()
        self.sendUpdate('toonExitDemand')

    def joinRequestDenied(self, reason):
        self._localToonRequestStatus = None
        return

    def exitRequestDenied(self, reason):
        self._localToonRequestStatus = None
        return

    def handleToonJoined(self, toonId):
        self.notify.error('BASE: handleToonJoined should be overridden %s' % self.activityName)

    def handleToonExited(self, toonId):
        self.notify.error('BASE: handleToonExited should be overridden %s' % self.activityName)

    def handleToonDisabled(self, toonId):
        self.notify.error('BASE: handleToonDisabled should be overridden %s' % self.activityName)

    def setToonsPlaying(self, toonIds):
        exitedToons, joinedToons = self.getToonsPlayingChanges(self.toonIds, toonIds)
        self.setToonIds(toonIds)
        self._processExitedToons(exitedToons)
        self._processJoinedToons(joinedToons)

    def _processExitedToons(self, exitedToons):
        for toonId in exitedToons:
            if toonId != base.localAvatar.doId or toonId == base.localAvatar.doId and self.isLocalToonRequestStatus(PartyGlobals.ActivityRequestStatus.Exiting):
                toon = self.getAvatar(toonId)
                if toon is not None:
                    self.ignore(toon.uniqueName('disable'))
                self.handleToonExited(toonId)
                if toonId == base.localAvatar.doId:
                    self._localToonRequestStatus = None
                if toonId in self._toonId2ror:
                    self.cr.relatedObjectMgr.abortRequest(self._toonId2ror[toonId])
                    del self._toonId2ror[toonId]

        return

    def _processJoinedToons(self, joinedToons):
        for toonId in joinedToons:
            if toonId != base.localAvatar.doId or toonId == base.localAvatar.doId and self.isLocalToonRequestStatus(PartyGlobals.ActivityRequestStatus.Joining):
                if toonId not in self._toonId2ror:
                    request = self.cr.relatedObjectMgr.requestObjects([toonId], allCallback=self._handlePlayerPresent)
                    if toonId in self._toonId2ror:
                        del self._toonId2ror[toonId]
                    else:
                        self._toonId2ror[toonId] = request

    def _handlePlayerPresent(self, toons):
        toon = toons[0]
        toonId = toon.doId
        if toonId in self._toonId2ror:
            del self._toonId2ror[toonId]
        else:
            self._toonId2ror[toonId] = None
        self._enableHandleToonDisabled(toonId)
        self.handleToonJoined(toonId)
        if toonId == base.localAvatar.doId:
            self._localToonRequestStatus = None
        return

    def _enableHandleToonDisabled(self, toonId):
        toon = self.getAvatar(toonId)
        if toon is not None:
            self.acceptOnce(toon.uniqueName('disable'), self.handleToonDisabled, [toonId])
        else:
            self.notify.warning('BASE: unable to get handle to toon with toonId:%d. Hook for handleToonDisabled not set.' % toonId)
        return

    def isLocalToonRequestStatus(self, requestStatus):
        return self._localToonRequestStatus == requestStatus

    def setToonIds(self, toonIds):
        self.toonIds = toonIds

    def getToonsPlayingChanges(self, oldToonIds, newToonIds):
        oldToons = set(oldToonIds)
        newToons = set(newToonIds)
        exitedToons = oldToons.difference(newToons)
        joinedToons = newToons.difference(oldToons)
        return (list(exitedToons), list(joinedToons))

    def setUsesSmoothing(self):
        self.usesSmoothing = True

    def setUsesLookAround(self):
        self.usesLookAround = True

    def getInstructions(self):
        return TTLocalizer.DefaultPartyActivityInstructions

    def getParentNodePath(self):
        if hasattr(base.cr.playGame, 'hood') and base.cr.playGame.hood and hasattr(base.cr.playGame.hood, 'loader') and base.cr.playGame.hood.loader and hasattr(base.cr.playGame.hood.loader, 'geom') and base.cr.playGame.hood.loader.geom:
            return base.cr.playGame.hood.loader.geom
        else:
            self.notify.warning('Hood or loader not created, defaulting to render')
            return render

    def __createRandomNumGen(self):
        self.notify.debug('BASE: self.doId=0x%08X' % self.doId)
        self.randomNumGen = RandomNumGen.RandomNumGen(self.doId)

        def destroy(self = self):
            self.notify.debug('BASE: destroying random num gen')
            del self.randomNumGen

        self.cleanupActions.append(destroy)

    def generate(self):
        DistributedObject.DistributedObject.generate(self)
        self.notify.debug('BASE: generate, %s' % self.getTitle())
        self.__createRandomNumGen()

    def announceGenerate(self):
        DistributedObject.DistributedObject.announceGenerate(self)
        self.notify.debug('BASE: announceGenerate %s' % self.activityName)
        self.root.setName(self.activityName + 'Root')
        centeredX, centeredY = getCenterPosFromGridSize(self.x, self.y, PartyGlobals.ActivityInformationDict[self.activityId]['gridsize'])
        self.root.setPos(centeredX, centeredY, 0.0)
        self.root.setH(self.h)
        self.normalExit = True
        if self.wantLever:
            self.leverTriggerEvent = self.uniqueName('leverTriggerEvent')
        self.load()

        def cleanup(self = self):
            self.notify.debug('BASE: cleanup: normalExit=%s' % self.normalExit)
            base.cr.renderFrame()
            if self.normalExit:
                self.sendUpdate('toonExitRequest')

        self.cleanupActions.append(cleanup)

    def disable(self):
        self.notify.debug('BASE: disable')
        DistributedObject.DistributedObject.disable(self)
        rorToonIds = self._toonId2ror.keys()
        for toonId in rorToonIds:
            self.cr.relatedObjectMgr.abortRequest(self._toonId2ror[toonId])
            del self._toonId2ror[toonId]

        self.ignore(self.messageDoneEvent)
        if self.messageGui is not None and not self.messageGui.isEmpty():
            self.messageGui.cleanup()
            self.messageGui = None
        return

    def delete(self):
        self.notify.debug('BASE: delete')
        self.unload()
        self.ignoreAll()
        DistributedObject.DistributedObject.delete(self)

    def load(self):
        self.notify.debug('BASE: load')
        self.loadSign()
        if self.wantLever:
            self.loadLever()
        if self.wantRewardGui:
            self.showRewardDoneEvent = self.uniqueName('showRewardDoneEvent')
            self.rewardGui = JellybeanRewardGui(self.showRewardDoneEvent)
        self.messageDoneEvent = self.uniqueName('messageDoneEvent')
        self.root.reparentTo(self.getParentNodePath())
        self._enableCollisions()

    def loadSign(self):
        actNameForSign = self.activityName
        if self.activityId == PartyGlobals.ActivityIds.PartyJukebox40:
            actNameForSign = PartyGlobals.ActivityIds.getString(PartyGlobals.ActivityIds.PartyJukebox)
        elif self.activityId == PartyGlobals.ActivityIds.PartyDance20:
            actNameForSign = PartyGlobals.ActivityIds.getString(PartyGlobals.ActivityIds.PartyDance)
        self.sign = self.root.attachNewNode('%sSign' % self.activityName)
        self.signModel = self.party.defaultSignModel.copyTo(self.sign)
        self.signFlat = self.signModel.find('**/sign_flat')
        self.signFlatWithNote = self.signModel.find('**/sign_withNote')
        self.signTextLocator = self.signModel.find('**/signText_locator')
        textureNodePath = getPartyActivityIcon(self.party.activityIconsModel, actNameForSign)
        textureNodePath.setPos(0.0, -0.02, 2.2)
        textureNodePath.setScale(2.35)
        textureNodePath.copyTo(self.signFlat)
        textureNodePath.copyTo(self.signFlatWithNote)
        text = TextNode('noteText')
        text.setTextColor(0.2, 0.1, 0.7, 1.0)
        text.setAlign(TextNode.ACenter)
        text.setFont(OTPGlobals.getInterfaceFont())
        text.setWordwrap(10.0)
        text.setText('')
        self.noteText = self.signFlatWithNote.attachNewNode(text)
        self.noteText.setPosHpr(self.signTextLocator, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0)
        self.noteText.setScale(0.2)
        self.signFlatWithNote.stash()
        self.signTextLocator.stash()

    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 unloadLever(self):
        self.lever.removeNode()
        self.leverModel.removeNode()
        self.controlColumn.removeNode()
        self.stickHinge.removeNode()
        self.stick.removeNode()
        self.bottom.removeNode()
        self.leverTrigger.removeNode()
        self.leverTube.removeNode()
        del self.bottomPos
        del self.lever
        del self.leverModel
        del self.controlColumn
        del self.stickHinge
        del self.stick
        del self.bottom
        del self.leverTrigger
        del self.leverTube

    def _enableCollisions(self):
        if self.wantLever:
            self.leverTrigger.unstash()
            self.accept('enter%s' % self.leverTriggerEvent, self._leverPulled)

    def _disableCollisions(self):
        if self.wantLever:
            self.leverTrigger.stash()
            self.ignore('enter%s' % self.leverTriggerEvent)

    def _leverPulled(self, collEntry):
        self.notify.debug('_leverPulled : Someone pulled the lever!!! ')
        if self.activityType == PartyGlobals.ActivityTypes.HostInitiated and base.localAvatar.doId != self.party.partyInfo.hostId:
            return False
        return True

    def getToonPullingLeverInterval(self, toon):
        walkTime = 0.2
        reach = ActorInterval(toon, 'leverReach', playRate=2.0)
        pull = ActorInterval(toon, 'leverPull', startFrame=6)
        origPos = toon.getPos(render)
        origHpr = toon.getHpr(render)
        newPos = self.lever.getPos(render)
        newHpr = self.lever.getHpr(render)
        origHpr.setX(PythonUtil.fitSrcAngle2Dest(origHpr[0], newHpr[0]))
        toon.setPosHpr(origPos, origHpr)
        reachAndPull = Sequence(ActorInterval(toon, 'walk', loop=True, duration=walkTime - reach.getDuration()), reach, pull)
        leverSeq = Sequence(Wait(walkTime + reach.getDuration() - 0.1), self.stick.hprInterval(0.55, Point3(0.0, 25.0, 0.0), Point3(0.0, 0.0, 0.0)), Wait(0.3), self.stick.hprInterval(0.4, Point3(0.0, 0.0, 0.0), Point3(0.0, 25.0, 0.0)))
        returnSeq = Sequence(Parallel(toon.posInterval(walkTime, newPos, origPos), toon.hprInterval(walkTime, newHpr, origHpr), leverSeq, reachAndPull))
        return returnSeq

    def showMessage(self, message, endState = 'walk'):
        base.cr.playGame.getPlace().fsm.request('activity')
        self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone)
        self.messageGui = TTDialog.TTGlobalDialog(doneEvent=self.messageDoneEvent, message=message, style=TTDialog.Acknowledge)
        self.messageGui.endState = endState

    def __handleMessageDone(self):
        self.ignore(self.messageDoneEvent)
        if hasattr(base.cr.playGame.getPlace(), 'fsm'):
            if self.messageGui and hasattr(self.messageGui, 'endState'):
                self.notify.info('__handleMessageDone (endState=%s)' % self.messageGui.endState)
                base.cr.playGame.getPlace().fsm.request(self.messageGui.endState)
            else:
                self.notify.warning("messageGui has no endState, defaulting to 'walk'")
                base.cr.playGame.getPlace().fsm.request('walk')
        if self.messageGui is not None and not self.messageGui.isEmpty():
            self.messageGui.cleanup()
            self.messageGui = None
        return

    def showJellybeanReward(self, earnedAmount, jarAmount, message):
        if not self.isLocalToonInActivity() or base.localAvatar.doId in self.getToonIdsAsList():
            messenger.send('DistributedPartyActivity-showJellybeanReward')
            base.cr.playGame.getPlace().fsm.request('activity')
            self.acceptOnce(self.showRewardDoneEvent, self.__handleJellybeanRewardDone)
            self.rewardGui.showReward(earnedAmount, jarAmount, message)

    def __handleJellybeanRewardDone(self):
        self.ignore(self.showRewardDoneEvent)
        self.handleRewardDone()

    def handleRewardDone(self):
        if base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(), 'fsm'):
            base.cr.playGame.getPlace().fsm.request('walk')

    def setSignNote(self, note):
        self.noteText.node().setText(note)
        if len(note.strip()) > 0:
            self.signFlat.stash()
            self.signFlatWithNote.unstash()
            self.signTextLocator.unstash()
        else:
            self.signFlat.unstash()
            self.signFlatWithNote.stash()
            self.signTextLocator.stash()

    def unload(self):
        self.notify.debug('BASE: unload')
        self.finishRules()
        self._disableCollisions()
        self.signModel.removeNode()
        del self.signModel
        self.sign.removeNode()
        del self.sign
        self.ignoreAll()
        if self.wantLever:
            self.unloadLever()
        self.root.removeNode()
        del self.root
        del self.activityId
        del self.activityName
        del self.activityType
        del self.wantLever
        del self.messageGui
        if self.rewardGui is not None:
            self.rewardGui.destroy()
        del self.rewardGui
        if hasattr(self, 'toonIds'):
            del self.toonIds
        del self.rulesDoneEvent
        del self.modelCount
        del self.cleanupActions
        del self.usesSmoothing
        del self.usesLookAround
        del self.difficultyOverride
        del self.trolleyZoneOverride
        if hasattr(base, 'partyActivityDict'):
            del base.partyActivityDict
        return

    def setPartyDoId(self, partyDoId):
        self.party = base.cr.doId2do[partyDoId]

    def setX(self, x):
        self.x = x

    def setY(self, y):
        self.y = y

    def setH(self, h):
        self.h = h

    def setState(self, newState, timestamp):
        if newState == 'Active':
            self.activityStartTime = globalClockDelta.networkToLocalTime(timestamp)

    def turnOffSmoothingOnGuests(self):
        for toonId in self.toonIds:
            avatar = self.getAvatar(toonId)
            if avatar:
                if not self.usesSmoothing:
                    avatar.stopSmooth()
                if not self.usesLookAround:
                    avatar.stopLookAround()

    def getAvatar(self, toonId):
        if self.cr.doId2do.has_key(toonId):
            return self.cr.doId2do[toonId]
        else:
            self.notify.warning('BASE: getAvatar: No avatar in doId2do with id: ' + str(toonId))
            return None
        return None

    def getAvatarName(self, toonId):
        avatar = self.getAvatar(toonId)
        if avatar:
            return avatar.getName()
        else:
            return 'Unknown'

    def isLocalToonInActivity(self):
        result = False
        place = base.cr.playGame.getPlace()
        if place and place.__class__.__name__ == 'Party' and hasattr(place, 'fsm') and place.fsm:
            result = place.fsm.getCurrentState().getName() == 'activity'
        return result

    def getToonIdsAsList(self):
        return self.toonIds

    def startRules(self, timeout = PartyGlobals.DefaultRulesTimeout):
        self.notify.debug('BASE: startRules')
        self.accept(self.rulesDoneEvent, self.handleRulesDone)
        self.rulesPanel = MinigameRulesPanel('PartyRulesPanel', self.getTitle(), self.getInstructions(), self.rulesDoneEvent, timeout)
        base.setCellsAvailable(base.bottomCells + [base.leftCells[0], base.rightCells[1]], False)
        self.rulesPanel.load()
        self.rulesPanel.enter()

    def finishRules(self):
        self.notify.debug('BASE: finishRules')
        self.ignore(self.rulesDoneEvent)
        if hasattr(self, 'rulesPanel'):
            self.rulesPanel.exit()
            self.rulesPanel.unload()
            del self.rulesPanel
            base.setCellsAvailable(base.bottomCells + [base.leftCells[0], base.rightCells[1]], True)

    def handleRulesDone(self):
        self.notify.error('BASE: handleRulesDone should be overridden')

    def getTitle(self):
        return TTLocalizer.PartyActivityNameDict[self.activityId]['generic']

    def local2ActivityTime(self, timestamp):
        return timestamp - self.activityStartTime

    def activity2LocalTime(self, timestamp):
        return timestamp + self.activityStartTime

    def getCurrentActivityTime(self):
        return self.local2ActivityTime(globalClock.getFrameTime())

    def disableEmotes(self):
        Emote.globalEmote.disableAll(base.localAvatar)

    def enableEmotes(self):
        Emote.globalEmote.releaseAll(base.localAvatar)
예제 #21
0
class GameOverNotification(object):
    def __init__(self, cameraX, cameraY, cameraZ, cameraAngle):
        self.ticks = 0
        self.endOfLife = False
        self.currentLetterAngle = 0.0
        self.letterNodes = []
        self.distance = 200
        self.closestDistance = 20
        self.endOfLifeTicks = 400
        self.cameraX = cameraX
        self.reduceSpinning = False
        self.spinningChange = 5.0
        self.minimumSpinning = False
        self.stoppedMoving = False

        self.gameOverContainerNode = NodePath("GameOverContainer")
        self.gameOverContainerNode.reparentTo(render)
        self.gameOverContainerNode.setPos(cameraX, cameraY, cameraZ - 0.85)

        self.gameOverNode = self.getGameOverNode()
        self.gameOverNode.reparentTo(self.gameOverContainerNode)

        angle = cameraAngle - 90
        if angle < 0.0:
            angle = angle + 360.0

        self.gameOverContainerNode.setH(angle)

    def advanceTime(self):
        if self.stoppedMoving:
            self.ticksUntilDeath = self.ticksUntilDeath - 1
            if self.ticksUntilDeath == 0:
                self.endOfLife = True
        else:
            self.currentLetterAngle = self.currentLetterAngle + self.spinningChange
            if self.currentLetterAngle > 360.0:
                if self.minimumSpinning:
                    self.stoppedMoving = True
                    self.ticksUntilDeath = 120
                else:
                    self.currentLetterAngle = self.currentLetterAngle - 360.0

        if not self.reduceSpinning:
            self.distance = self.distance - 1
            if self.distance <= self.closestDistance:
                self.distance = self.closestDistance
                self.reduceSpinning = True

        if self.reduceSpinning:
            if self.spinningChange > 1.75:
                self.spinningChange = self.spinningChange - 0.05
            else:
                self.minimumSpinning = True

        self.gameOverNode.setY(self.distance)
        for letterNode in self.letterNodes:
            letterNode.setH(self.currentLetterAngle)

    def getGameOverNode(self):
        gameOverNode = NodePath("GameOver")

        letterGeometry = LetterGeometry.getCardGeometryByPhrase('game over')

        for letter in letterGeometry:
            letterCm = CardMaker('card')
            letterCm.setFrame(letter['left'], letter['right'], letter['top'],
                              letter['bottom'])
            letterNode = gameOverNode.attachNewNode(letterCm.generate())
            self.letterNodes.append(letterNode)
            letterNode.setTwoSided(True)
            letterNode.setTransparency(TransparencyAttrib.MAlpha)
            letterNode.setBin('unsorted', 50)
            letterNode.setDepthTest(False)
            letterNode.setDepthWrite(False)
            tex = loader.loadTexture('textures/letter-' + letter['letter'] +
                                     '.png')
            tex.setWrapU(Texture.WMClamp)
            tex.setWrapV(Texture.WMClamp)
            letterNode.setTexture(tex)
            letterNode.setPos(letter['originx'], letter['originy'], 0)

        return gameOverNode

    def setCompletionEvent(self, completionEvent):
        self.completionEvent = completionEvent

    def getCompletionEvent(self):
        return self.completionEvent

    def hasDied(self):
        return self.endOfLife

    def delete(self):
        self.gameOverContainerNode.removeNode()
def generateHullCache(modelClass):
    geom = loader.loadModel('models/shipparts/pir_m_shp_%s' %
                            HullDict[modelClass])
    stripPrefix(geom, 'model:')
    for node in geom.findAllMatches('**/omit'):
        parent = node.getParent()
        omit = parent.attachNewNode(ModelNode('omit'))
        node.reparentTo(omit)
        node.setName('geom')

    preFlatten(geom)
    logic = loader.loadModel('models/shipparts/pir_m_shp_%s_logic' %
                             HullDict[modelClass])
    locators = logic.find('**/locators')
    for side in ['left', 'right']:
        bad = locators.find('**/location_ropeLadder_0_%s' % side)
        if bad:
            bad.setName('location_ropeLadder_%s_0' % side)

        bad = locators.find('**/location_ropeLadder_1_%s' % side)
        if bad:
            bad.setName('location_ropeLadder_%s_1' % side)

        bad = locators.find('**/location_ropeLadder_1_%s1' % side)
        if bad:
            bad.setName('location_ropeLadder_%s_2' % side)

    collisions = logic.find('**/collisions')
    badPanel = collisions.find('**/collision_panel_3')
    if badPanel:
        badPanel.setName('collision_panel_2')
    collisions.find('**/collision_panel_0').setTag('Hull Code', '0')
    collisions.find('**/collision_panel_1').setTag('Hull Code', '1')
    collisions.find('**/collision_panel_2').setTag('Hull Code', '2')
    walls = collisions.find('**/collision_walls')
    if walls:
        walls.setTag('Hull Code', '255')
    else:
        collisions.attachNewNode('collision_walls')

    shipToShipCollide = collisions.find('**/collision_shiptoship')
    shipToShipCollide.setCollideMask(PiratesGlobals.ShipCollideBitmask)
    deck = collisions.find('**/collision_deck')
    if not deck:
        deck = collisions.attachNewNode('deck')

    mask = deck.getCollideMask()
    mask ^= PiratesGlobals.FloorBitmask
    mask |= PiratesGlobals.ShipFloorBitmask
    deck.setCollideMask(mask)
    floors = collisions.find('**/collision_floors')
    if not floors:
        floors = collisions.find('**/collision_floor')

    mask = floors.getCollideMask()
    mask ^= PiratesGlobals.FloorBitmask
    mask |= PiratesGlobals.ShipFloorBitmask
    floors.setCollideMask(mask)
    floors.setTag('Hull Code', str(255))
    geomHigh = geom.find('**/lod_high')
    geomMed = geom.find('**/lod_medium')
    if not geomMed:
        geomMed = geom.find('**/low_medium')
    if not geomMed:
        geomMed = geomHigh.copyTo(NodePath())
    geomLow = geom.find('**/lod_low')
    if not geomLow:
        geomLow = geomMed.copyTo(NodePath())
    geomSuperLow = geom.find('**/lod_superlow')
    if not geomSuperLow:
        geomSuperLow = geomLow.copyTo(NodePath())
    geomHigh.setName('high')
    geomMed.setName('med')
    geomLow.setName('low')
    geomSuperLow.setName('superlow')
    if modelClass in [21, 22, 23]:
        spike = loader.loadModel('models/shipparts/pir_m_shp_ram_spike')
        spikeTrans = locators.find('**/location_ram').getTransform(locators)
        spike.setTransform(spikeTrans)
        spike.flattenLight()
        spikeHi = spike.find('**/lod_high')
        spikeMed = spike.find('**/lod_medium')
        spikeLow = spike.find('**/lod_low')
        spikeHi.copyTo(geomHigh)
        spikeMed.copyTo(geomMed)
        spikeLow.copyTo(geomLow)
        spikeLow.copyTo(geomSuperLow)

    flipRoot = NodePath('root')
    collisions.reparentTo(flipRoot)
    locators.reparentTo(flipRoot)
    geomHigh.reparentTo(flipRoot)
    geomMed.reparentTo(flipRoot)
    geomLow.reparentTo(flipRoot)
    geomSuperLow.reparentTo(flipRoot)
    flipRoot.setH(180)
    flipRoot.flattenLight()
    omits = flipRoot.findAllMatches('**/omit')
    for node in omits:
        node.flattenStrong()

    for group in [
            'static', 'transparent', 'ropeLadder_*', 'stripeA', 'stripeB',
            'pattern'
    ]:
        for node in flipRoot.findAllMatches('**/%s' % group):
            name = node.getName()
            for subNode in node.findAllMatches('**/*'):
                subNode.setName(name)

            node.flattenStrong()
            node.setName(name)

    geomHigh.detachNode()
    geomMed.detachNode()
    geomLow.detachNode()
    geomSuperLow.detachNode()
    locators.detachNode()
    collisions.detachNode()
    genericGeoms = [geomHigh, geomMed, geomLow, geomSuperLow]

    customGeoms = [x.copyTo(NodePath()) for x in genericGeoms]
    for np in genericGeoms:
        trans = np.find('**/transparent')
        if trans:
            trans.stash()
        np.flattenLight()
        sails = np.findAllMatches('**/sails')
        sails.stash()
        omits = np.findAllMatches('**/omit')
        omits.stash()
        for node in omits:
            node.node().setPreserveTransform(node.node().PTDropNode)

        generic = NodePath('generic')
        np.findAllMatches('**/+GeomNode').wrtReparentTo(generic)
        np.findAllMatches('*').detach()
        generic.flattenStrong()
        generic.reparentTo(np)
        stripAttribs(generic, TextureAttrib)
        stripAttribs(generic, TransparencyAttrib)
        stripAttribs(generic, CullBinAttrib)
        generic.setBin('ground', 1)
        collapse(generic)
        sails.unstash()
        sails.reparentTo(np)
        for node in sails:
            node.node().setPreserveTransform(node.node().PTDropNode)

        if trans:
            trans.unstash()
            trans.flattenStrong()
            if trans.node().isOfType(ModelNode.getClassType()):
                trans.node().setPreserveTransform(ModelNode.PTDropNode)
        deck = np.find('**/=cam=shground')
        if deck:
            deck.setName('deck')
        omits.unstash()

    for np in customGeoms:
        collapse(np.find('**/static'))

    data = HullCache()
    data.root = NodePath('hull')
    data.genericGeoms = genericGeoms
    data.customGeoms = customGeoms
    data.collisions = collisions
    data.locators = locators
    return data
예제 #23
0
class PlaneCamera(FSM, DirectObject):
    """Give this class a plane as argument and it will create
    some nodes around it which you can parent the camera to (if there are no
    such nodes yet). Keep in mind, that it only uses base.camera the whole
    time - no other cams are involved.

    Usage:
    plane_camera = PlaneCamera(aeroplane)
    plane_camera.setView("ThirdPerson")
    plane_camera.setView("Next")
    """
    def __init__(self, parent):
        """Arguments:
        parent -- Aeroplane which the camera should follow
        """

        # Used for debugging. Verbosity is set in config file.
        # Usually this is called self.notify, but in this case it would
        # override FSM's own.
        self.notifier = DirectNotify().newCategory("azure-camera")
        self.parent = parent
        # Replaced by a NodePath with all available cameras as children and
        # plane node as parent.
        self.cameras = None

        #if parent.__class__.__name__ is not "Aeroplane":
        if not isinstance(self.parent, Aeroplane):
            raise ParamError, "Parent must be an Aeroplane instance, " + \
                              "but is %s" % type(self.parent)

        FSM.__init__(self, "PlaneCamera: %s" % self.parent.name)
        DirectObject.__init__(self)

        try:
            self.camera = base.camera
        except:
            raise BaseMissing

        self.cameras = self.parent.node.find("cameras")
        if self.cameras.isEmpty():
            self.createCamNodes()
        self.updateCamArray()

        self.sideview_direction = 0

        # Set up the default camera
        self.setView("ThirdPerson")

    def createCamNodes(self):
        """Creates a few empty nodes around a plane which the camera might be
        parented to. It looks if there are cameras inside the model file and
        uses those if possible. Where everything named "camera CamType" is
        considered a camera. At least ThirdPerson, FirstPerson and Cockpit
        should be defined inside the egg file, otherwise some guessed defaults
        are taken.
        """

        # Look for cameras inside the model (loaded egg file)
        self.cameras = NodePath("cameras")
        found_cams = self.parent.node.findAllMatches("**/camera ?*")
        found_cams.removeDuplicatePaths()
        found_cams.reparentTo(self.cameras)

        if not found_cams.isEmpty():
            self.notifier.info("Cameras found under model:\n%s"
                               % found_cams)
        else:
            self.notifier.info("No cameras found under model.")

        # FirstPerson camera is a must-have. Set up a guessed one if none
        # defined yet.
        if self.cameras.find("camera FirstPerson").isEmpty():
            assert self.notifier.debug("No first person camera found in %s. "
                                  "Guessing best position." % self.parent.name)
            first_person = NodePath("camera FirstPerson")
            # TODO: Guess best position based on bounding box.
            first_person.setY(5)
            first_person.reparentTo(cameras)

        # ThirdPerson camera is a must-have. Set up a guessed one if none
        # defined yet.
        if self.cameras.find("camera ThirdPerson").isEmpty():
            assert self.notifier.debug("No third person camera found in %s. "
                                  "Guessing best position." % self.parent.name)
            third_person = NodePath("camera ThirdPerson")
            # TODO: Guess best position based on bounding box.
            third_person.setPos(0, -30, 5)
            #third_person.setP(-80)
            third_person.reparentTo(cameras)

        # Cockpit needs to be accurate. Don't try to guess it.
        if self.cameras.find("camera Cockpit").isEmpty():
            assert self.notifier.debug("No cockpit camera found in "
                                       "%s. Cockpit camera disabled."
                                       % self.parent.name)
        self.sideview_cam = NodePath("camera Sideview")
        self.sideview_cam.reparentTo(render)

        # Store the cams at parent node..
        # You can edit the camera nodes from outside as well.
        # If you attach new camera nodes, though, you'll have to call this
        # function again.
        self.cameras.reparentTo(self.parent.node)

    def updateCamArray(self, cameramodes=None):
        """Set the cameras which next and previous will switch to. Expects a
        list or tuple. Defaults to all available cameras."""
        a = []
        if not cameramodes:
            for c in self.cameras.getChildren():
                if c.getName().startswith("camera "):
                    a.append(c.getName().strip("camera "))
            self.setStateArray(a)
        else:
            self.setStateArray(cameramodes)

    def getView(self):
        """Returns the current view mode."""
        return self.getCurrentOrNextState()

    def setView(self, mode, *args):
        """Convenience function."""
        return self.request(mode, args)

    def defaultEnter(self, *args):
        """Executed by the FSM every time an undefined state is entered.
        Note: this function is called AFTER the responsible filter."""

        assert self.notifier.debug("Changing state from %s to %s with args: %s."
                                   % (self.oldState, self.newState, args))
        request = self.newState

        target_cam = self.cameras.find("camera " + request)
        if not target_cam.isEmpty():
            try:
                self.camera.reparentTo(target_cam)
                self.camera.setPosHpr(0, 0, 0, 0, 0, 0)
            except:
                self.notifier.warning(
                        "Ok, now this really shouldn't happen! Filter said the "
                        "camera is there and enter can't find it...")



    def defaultFilter(self, request, args):
        """Executed by the FSM every time an undefined state is requested."""
        assert self.notifier.debug("Requested %s with args: %s"
                                   % (request, args))

        self.camera.setPosHpr(0, 0, 0, 0, 0, 0)

        # Always available.
        if request == "Off":   # implemented in FSM.py
            return (request,) + args
        if request == "Next":  # implemented in FSM.py
            return self.requestNext(args)
        if request == "Prev":  # implemented in FSM.py
            return self.requestPrev(args)
        if request == "Detached":
            return (request,) + args
        if request == "Sideview":
            return (request,) + args
        
        # Depending on airplane.
        if not self.cameras.find("camera " + request).isEmpty():
            # TODO(Nemesis13, 26.10.09): add some nice camera transition
            return (request,) + args
        assert self.notifier.info("Sorry, no %s camera found." % request)
        return None


    def enterOff(self, *args):
        """Clean up everything by reparenting the camera to the airplane."""
        self.camera.reparentTo(self.parent.node)
        self.camera.setPosHpr(0, 0, 0, 0, 0, 0)

    def enterSideview(self, *args):
        self.sideview_direction += 90
        self.camera.reparentTo(self.sideview_cam)
        self.camera.setY(-30)
        self.sideview_cam.setH(self.sideview_direction)
        self.addTask(self.updateSideview, "sideview camera", taskChain="world")

    def exitSideview(self, *args):
        self.removeTask("sideview camera")

    def updateSideview(self, task):
        self.sideview_cam.setPos(self.parent.node.getPos())
        return Task.cont

    def enterDetached(self, *args):
        """Lets the camera view the plane from far away."""
        self.camera.reparentTo(render)
        self.camera.setPosHpr(0, 0, 10, 0, 0, 0)
        self.addTask(self.updateDetachedCam, "detached camera",
                     taskChain="world")

    def exitDetached(self, *args):
        self.removeTask("detached camera")

    def updateDetachedCam(self, task):
        """Updates camera position and rotation for Detached camera."""
        try:
            self.camera.lookAt(self.parent.node)
        except:
            self.notifier.warning("Error on detached cam task. Exit.")
            return Task.done
        return Task.cont

    def enterThirdPerson(self, *args):
        """Lets the camera view the plane from far away."""
        self._hist = []
        self.camera.reparentTo(self.cameras.find("camera ThirdPerson"))
        self.addTask(self.updateThirdPersonCam, "third person camera",
                     taskChain="world")
        #print "entering third person"

    def exitThirdPerson(self, *args):
        self.removeTask("third person camera")
        del self._hist
        #print "third person exited"

    def updateThirdPersonCam(self, task):
        """Updates camera position and rotation for ThirdPerson camera."""
        #speed = self.parent.speed()
        #plane = self.parent.node
        #self._hist.insert(0, [task.time, camera.getPos(plane)])
        #while len(self._hist) > 50:
        #    self._hist.pop()
        #
        #for snapshot in self._hist:
        #    if snapshot[0] > task.time:
        #        break
        #time_delta = snapshot[0] - task.time
        #self.camera.setPos(plane, snapshot[1])

        #print snapshot
        #self.camera.setPos(render, snapshot[1])
        #self.camera.lookAt(plane, (0, 20+1*speed, 0))

        #self.camera.setY(5+0.1*speed)
        #self.camera.setZ(5-0.1*speed)

        return Task.cont

    def destroy(self):
        self.removeAllTasks()
        self.demand("Off")
예제 #24
0
class DistributedPartyActivity(DistributedObject.DistributedObject):
    deferFor = 1

    def __init__(self,
                 cr,
                 activityId,
                 activityType,
                 wantLever=False,
                 wantRewardGui=False):
        DistributedObject.DistributedObject.__init__(self, cr)
        self.activityId = activityId
        self.activityName = PartyGlobals.ActivityIds.getString(self.activityId)
        self.activityType = activityType
        self.wantLever = wantLever
        self.wantRewardGui = wantRewardGui
        self.messageGui = None
        self.rewardGui = None
        self.toonIds = []
        self._toonId2ror = {}
        childName = '%s' % self
        childName = childName[childName.rfind('.DistributedParty') +
                              len('.DistributedParty'):childName.
                              rfind('Activity instance')]
        if not hasattr(base, 'partyActivityDict'):
            base.partyActivityDict = {}
        base.partyActivityDict[childName] = self
        self.root = NodePath('root')
        self.rulesDoneEvent = 'rulesDone'
        self.modelCount = 500
        self.cleanupActions = []
        self.usesSmoothing = 0
        self.usesLookAround = 0
        self.difficultyOverride = None
        self.trolleyZoneOverride = None
        self._localToonRequestStatus = None
        #self.root.setPos(self.x, self.y, self.z)
        return

    def localToonExiting(self):
        self._localToonRequestStatus = PartyGlobals.ActivityRequestStatus.Exiting

    def localToonJoining(self):
        self._localToonRequestStatus = PartyGlobals.ActivityRequestStatus.Joining

    def d_toonJoinRequest(self):
        if self._localToonRequestStatus is None:
            self.localToonJoining()
            self.sendUpdate('toonJoinRequest')
        return

    def d_toonExitRequest(self):
        if self._localToonRequestStatus is None:
            self.localToonExiting()
            self.sendUpdate('toonExitRequest')
        return

    def d_toonExitDemand(self):
        self.localToonExiting()
        self.sendUpdate('toonExitDemand')

    def joinRequestDenied(self, reason):
        self._localToonRequestStatus = None
        return

    def exitRequestDenied(self, reason):
        self._localToonRequestStatus = None
        return

    def handleToonJoined(self, toonId):
        self.notify.error('BASE: handleToonJoined should be overridden %s' %
                          self.activityName)

    def handleToonExited(self, toonId):
        self.notify.error('BASE: handleToonExited should be overridden %s' %
                          self.activityName)

    def handleToonDisabled(self, toonId):
        self.notify.error('BASE: handleToonDisabled should be overridden %s' %
                          self.activityName)

    def setToonsPlaying(self, toonIds):
        exitedToons, joinedToons = self.getToonsPlayingChanges(
            self.toonIds, toonIds)
        self.setToonIds(toonIds)
        self._processExitedToons(exitedToons)
        self._processJoinedToons(joinedToons)

    def _processExitedToons(self, exitedToons):
        for toonId in exitedToons:
            if toonId != base.localAvatar.doId or toonId == base.localAvatar.doId and self.isLocalToonRequestStatus(
                    PartyGlobals.ActivityRequestStatus.Exiting):
                toon = self.getAvatar(toonId)
                if toon is not None:
                    self.ignore(toon.uniqueName('disable'))
                self.handleToonExited(toonId)
                if toonId == base.localAvatar.doId:
                    self._localToonRequestStatus = None
                if toonId in self._toonId2ror:
                    self.cr.relatedObjectMgr.abortRequest(
                        self._toonId2ror[toonId])
                    del self._toonId2ror[toonId]

        return

    def _processJoinedToons(self, joinedToons):
        for toonId in joinedToons:
            if toonId != base.localAvatar.doId or toonId == base.localAvatar.doId and self.isLocalToonRequestStatus(
                    PartyGlobals.ActivityRequestStatus.Joining):
                if toonId not in self._toonId2ror:
                    request = self.cr.relatedObjectMgr.requestObjects(
                        [toonId], allCallback=self._handlePlayerPresent)
                    if toonId in self._toonId2ror:
                        del self._toonId2ror[toonId]
                    else:
                        self._toonId2ror[toonId] = request

    def _handlePlayerPresent(self, toons):
        toon = toons[0]
        toonId = toon.doId
        if toonId in self._toonId2ror:
            del self._toonId2ror[toonId]
        else:
            self._toonId2ror[toonId] = None
        self._enableHandleToonDisabled(toonId)
        self.handleToonJoined(toonId)
        if toonId == base.localAvatar.doId:
            self._localToonRequestStatus = None
        return

    def _enableHandleToonDisabled(self, toonId):
        toon = self.getAvatar(toonId)
        if toon is not None:
            self.acceptOnce(toon.uniqueName('disable'),
                            self.handleToonDisabled, [toonId])
        else:
            self.notify.warning(
                'BASE: unable to get handle to toon with toonId:%d. Hook for handleToonDisabled not set.'
                % toonId)
        return

    def isLocalToonRequestStatus(self, requestStatus):
        return self._localToonRequestStatus == requestStatus

    def setToonIds(self, toonIds):
        self.toonIds = toonIds

    def getToonsPlayingChanges(self, oldToonIds, newToonIds):
        oldToons = set(oldToonIds)
        newToons = set(newToonIds)
        exitedToons = oldToons.difference(newToons)
        joinedToons = newToons.difference(oldToons)
        return (list(exitedToons), list(joinedToons))

    def setUsesSmoothing(self):
        self.usesSmoothing = True

    def setUsesLookAround(self):
        self.usesLookAround = True

    def getInstructions(self):
        return TTLocalizer.DefaultPartyActivityInstructions

    def getParentNodePath(self):
        if hasattr(base.cr.playGame,
                   'hood') and base.cr.playGame.hood and hasattr(
                       base.cr.playGame.hood,
                       'loader') and base.cr.playGame.hood.loader and hasattr(
                           base.cr.playGame.hood.loader,
                           'geom') and base.cr.playGame.hood.loader.geom:
            return base.cr.playGame.hood.loader.geom
        else:
            self.notify.warning(
                'Hood or loader not created, defaulting to render')
            return render

    def __createRandomNumGen(self):
        self.notify.debug('BASE: self.doId=0x%08X' % self.doId)
        self.randomNumGen = RandomNumGen.RandomNumGen(self.doId)

        def destroy(self=self):
            self.notify.debug('BASE: destroying random num gen')
            del self.randomNumGen

        self.cleanupActions.append(destroy)

    def generate(self):
        DistributedObject.DistributedObject.generate(self)
        self.notify.debug('BASE: generate, %s' % self.getTitle())
        self.__createRandomNumGen()

    def announceGenerate(self):
        DistributedObject.DistributedObject.announceGenerate(self)
        self.notify.debug('BASE: announceGenerate %s' % self.activityName)
        self.root.setName(self.activityName + 'Root')
        centeredX, centeredY = getCenterPosFromGridSize(
            self.x, self.y,
            PartyGlobals.ActivityInformationDict[self.activityId]['gridsize'])
        self.root.setPos(centeredX, centeredY, 0.0)
        self.root.setH(self.h)
        self.root.setZ(self.z)
        self.normalExit = True
        if self.wantLever:
            self.leverTriggerEvent = self.uniqueName('leverTriggerEvent')
        self.load()

        def cleanup(self=self):
            self.notify.debug('BASE: cleanup: normalExit=%s' % self.normalExit)
            base.cr.renderFrame()
            if self.normalExit:
                self.sendUpdate('toonExitRequest')

        self.cleanupActions.append(cleanup)

    def disable(self):
        self.notify.debug('BASE: disable')
        DistributedObject.DistributedObject.disable(self)
        rorToonIds = self._toonId2ror.keys()
        for toonId in rorToonIds:
            self.cr.relatedObjectMgr.abortRequest(self._toonId2ror[toonId])
            del self._toonId2ror[toonId]

        self.ignore(self.messageDoneEvent)
        if self.messageGui is not None and not self.messageGui.isEmpty():
            self.messageGui.cleanup()
            self.messageGui = None
        return

    def delete(self):
        self.notify.debug('BASE: delete')
        self.unload()
        self.ignoreAll()
        DistributedObject.DistributedObject.delete(self)

    def load(self):
        self.notify.debug('BASE: load')
        self.loadSign()
        if self.wantLever:
            self.loadLever()
        if self.wantRewardGui:
            self.showRewardDoneEvent = self.uniqueName('showRewardDoneEvent')
            self.rewardGui = JellybeanRewardGui(self.showRewardDoneEvent)
        self.messageDoneEvent = self.uniqueName('messageDoneEvent')
        self.root.reparentTo(self.getParentNodePath())
        self._enableCollisions()

    def loadSign(self):
        actNameForSign = self.activityName
        if self.activityId == PartyGlobals.ActivityIds.PartyJukebox40:
            actNameForSign = PartyGlobals.ActivityIds.getString(
                PartyGlobals.ActivityIds.PartyJukebox)
        elif self.activityId == PartyGlobals.ActivityIds.PartyDance20:
            actNameForSign = PartyGlobals.ActivityIds.getString(
                PartyGlobals.ActivityIds.PartyDance)
        self.sign = self.root.attachNewNode('%sSign' % self.activityName)
        self.signModel = self.party.defaultSignModel.copyTo(self.sign)
        self.signFlat = self.signModel.find('**/sign_flat')
        self.signFlatWithNote = self.signModel.find('**/sign_withNote')
        self.signTextLocator = self.signModel.find('**/signText_locator')
        textureNodePath = getPartyActivityIcon(self.party.activityIconsModel,
                                               actNameForSign)
        textureNodePath.setPos(0.0, -0.02, 2.2)
        textureNodePath.setScale(2.35)
        textureNodePath.copyTo(self.signFlat)
        textureNodePath.copyTo(self.signFlatWithNote)
        text = TextNode('noteText')
        text.setTextColor(0.2, 0.1, 0.7, 1.0)
        text.setAlign(TextNode.ACenter)
        text.setFont(OTPGlobals.getInterfaceFont())
        text.setWordwrap(10.0)
        text.setText('')
        self.noteText = self.signFlatWithNote.attachNewNode(text)
        self.noteText.setPosHpr(self.signTextLocator, 0.0, 0.0, 0.2, 0.0, 0.0,
                                0.0)
        self.noteText.setScale(0.2)
        self.signFlatWithNote.stash()
        self.signTextLocator.stash()

    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 unloadLever(self):
        self.lever.removeNode()
        self.leverModel.removeNode()
        self.controlColumn.removeNode()
        self.stickHinge.removeNode()
        self.stick.removeNode()
        self.bottom.removeNode()
        self.leverTrigger.removeNode()
        self.leverTube.removeNode()
        del self.bottomPos
        del self.lever
        del self.leverModel
        del self.controlColumn
        del self.stickHinge
        del self.stick
        del self.bottom
        del self.leverTrigger
        del self.leverTube

    def _enableCollisions(self):
        if self.wantLever:
            self.leverTrigger.unstash()
            self.accept('enter%s' % self.leverTriggerEvent, self._leverPulled)

    def _disableCollisions(self):
        if self.wantLever:
            self.leverTrigger.stash()
            self.ignore('enter%s' % self.leverTriggerEvent)

    def _leverPulled(self, collEntry):
        self.notify.debug('_leverPulled : Someone pulled the lever!!! ')
        if self.activityType == PartyGlobals.ActivityTypes.HostInitiated and base.localAvatar.doId != self.party.partyInfo.hostId:
            return False
        return True

    def getToonPullingLeverInterval(self, toon):
        walkTime = 0.2
        reach = ActorInterval(toon, 'leverReach', playRate=2.0)
        pull = ActorInterval(toon, 'leverPull', startFrame=6)
        origPos = toon.getPos(render)
        origHpr = toon.getHpr(render)
        newPos = self.lever.getPos(render)
        newHpr = self.lever.getHpr(render)
        origHpr.setX(PythonUtil.fitSrcAngle2Dest(origHpr[0], newHpr[0]))
        toon.setPosHpr(origPos, origHpr)
        reachAndPull = Sequence(
            ActorInterval(toon,
                          'walk',
                          loop=True,
                          duration=walkTime - reach.getDuration()), reach,
            pull)
        leverSeq = Sequence(
            Wait(walkTime + reach.getDuration() - 0.1),
            self.stick.hprInterval(0.55, Point3(0.0, 25.0, 0.0),
                                   Point3(0.0, 0.0, 0.0)), Wait(0.3),
            self.stick.hprInterval(0.4, Point3(0.0, 0.0, 0.0),
                                   Point3(0.0, 25.0, 0.0)))
        returnSeq = Sequence(
            Parallel(toon.posInterval(walkTime, newPos, origPos),
                     toon.hprInterval(walkTime, newHpr, origHpr), leverSeq,
                     reachAndPull))
        return returnSeq

    def showMessage(self, message, endState='walk'):
        base.cr.playGame.getPlace().fsm.request('activity')
        self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone)
        self.messageGui = TTDialog.TTGlobalDialog(
            doneEvent=self.messageDoneEvent,
            message=message,
            style=TTDialog.Acknowledge)
        self.messageGui.endState = endState

    def __handleMessageDone(self):
        self.ignore(self.messageDoneEvent)
        if hasattr(base.cr.playGame.getPlace(), 'fsm'):
            if self.messageGui and hasattr(self.messageGui, 'endState'):
                self.notify.info('__handleMessageDone (endState=%s)' %
                                 self.messageGui.endState)
                base.cr.playGame.getPlace().fsm.request(
                    self.messageGui.endState)
            else:
                self.notify.warning(
                    "messageGui has no endState, defaulting to 'walk'")
                base.cr.playGame.getPlace().fsm.request('walk')
        if self.messageGui is not None and not self.messageGui.isEmpty():
            self.messageGui.cleanup()
            self.messageGui = None
        return

    def showJellybeanReward(self, earnedAmount, jarAmount, message):
        if not self.isLocalToonInActivity(
        ) or base.localAvatar.doId in self.getToonIdsAsList():
            messenger.send('DistributedPartyActivity-showJellybeanReward')
            base.cr.playGame.getPlace().fsm.request('activity')
            self.acceptOnce(self.showRewardDoneEvent,
                            self.__handleJellybeanRewardDone)
            self.rewardGui.showReward(earnedAmount, jarAmount, message)

    def __handleJellybeanRewardDone(self):
        self.ignore(self.showRewardDoneEvent)
        self.handleRewardDone()

    def handleRewardDone(self):
        if base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(),
                                                   'fsm'):
            base.cr.playGame.getPlace().fsm.request('walk')

    def setSignNote(self, note):
        self.noteText.node().setText(note)
        if len(note.strip()) > 0:
            self.signFlat.stash()
            self.signFlatWithNote.unstash()
            self.signTextLocator.unstash()
        else:
            self.signFlat.unstash()
            self.signFlatWithNote.stash()
            self.signTextLocator.stash()

    def unload(self):
        self.notify.debug('BASE: unload')
        self.finishRules()
        self._disableCollisions()
        self.signModel.removeNode()
        del self.signModel
        self.sign.removeNode()
        del self.sign
        self.ignoreAll()
        if self.wantLever:
            self.unloadLever()
        self.root.removeNode()
        del self.root
        del self.activityId
        del self.activityName
        del self.activityType
        del self.wantLever
        del self.messageGui
        if self.rewardGui is not None:
            self.rewardGui.destroy()
        del self.rewardGui
        if hasattr(self, 'toonIds'):
            del self.toonIds
        del self.rulesDoneEvent
        del self.modelCount
        del self.cleanupActions
        del self.usesSmoothing
        del self.usesLookAround
        del self.difficultyOverride
        del self.trolleyZoneOverride
        if hasattr(base, 'partyActivityDict'):
            del base.partyActivityDict
        return

    def setPartyDoId(self, partyDoId):
        #print base.cr.doId2do
        self.party = base.cr.doId2do[partyDoId]

    def setX(self, x):
        self.x = x

    def setY(self, y):
        self.y = y

    def setZ(self, z):
        self.z = z

    def setH(self, h):
        self.h = h

    def setState(self, newState, timestamp):
        if newState == 'Active':
            self.activityStartTime = globalClockDelta.networkToLocalTime(
                timestamp)

    def turnOffSmoothingOnGuests(self):
        for toonId in self.toonIds:
            avatar = self.getAvatar(toonId)
            if avatar:
                if not self.usesSmoothing:
                    avatar.stopSmooth()
                if not self.usesLookAround:
                    avatar.stopLookAround()

    def getAvatar(self, toonId):
        if self.cr.doId2do.has_key(toonId):
            return self.cr.doId2do[toonId]
        else:
            self.notify.warning(
                'BASE: getAvatar: No avatar in doId2do with id: ' +
                str(toonId))
            return None
        return None

    def getAvatarName(self, toonId):
        avatar = self.getAvatar(toonId)
        if avatar:
            return avatar.getName()
        else:
            return 'Unknown'

    def isLocalToonInActivity(self):
        result = False
        place = base.cr.playGame.getPlace()
        if place and place.__class__.__name__ == 'Party' and hasattr(
                place, 'fsm') and place.fsm:
            result = place.fsm.getCurrentState().getName() == 'activity'
        return result

    def getToonIdsAsList(self):
        return self.toonIds

    def startRules(self, timeout=PartyGlobals.DefaultRulesTimeout):
        self.notify.debug('BASE: startRules')
        self.accept(self.rulesDoneEvent, self.handleRulesDone)
        self.rulesPanel = MinigameRulesPanel('PartyRulesPanel',
                                             self.getTitle(),
                                             self.getInstructions(),
                                             self.rulesDoneEvent, timeout)
        base.setCellsAvailable(
            base.bottomCells + [base.leftCells[0], base.rightCells[1]], False)
        self.rulesPanel.load()
        self.rulesPanel.enter()

    def finishRules(self):
        self.notify.debug('BASE: finishRules')
        self.ignore(self.rulesDoneEvent)
        if hasattr(self, 'rulesPanel'):
            self.rulesPanel.exit()
            self.rulesPanel.unload()
            del self.rulesPanel
            base.setCellsAvailable(
                base.bottomCells + [base.leftCells[0], base.rightCells[1]],
                True)

    def handleRulesDone(self):
        self.notify.error('BASE: handleRulesDone should be overridden')

    def getTitle(self):
        return TTLocalizer.PartyActivityNameDict[self.activityId]['generic']

    def local2ActivityTime(self, timestamp):
        return timestamp - self.activityStartTime

    def activity2LocalTime(self, timestamp):
        return timestamp + self.activityStartTime

    def getCurrentActivityTime(self):
        return self.local2ActivityTime(globalClock.getFrameTime())

    def disableEmotes(self):
        Emote.globalEmote.disableAll(base.localAvatar)

    def enableEmotes(self):
        Emote.globalEmote.releaseAll(base.localAvatar)
예제 #25
0
    def load(self):
        self.arena = loader.loadModel(self.arenaModel)
        self.arena.reparentTo(self.root)
        ground = self.arena.find('**/ground')
        ground.setBin('ground', 1)
        entranceArrows = self.arena.findAllMatches('**/arrowFlat*')
        for arrow in entranceArrows:
            arrow.setBin('ground', 5)

        self.leftEntranceLocator = self.arena.find('**/leftEntrance_locator')
        self.rightEntranceLocator = self.arena.find('**/rightEntrance_locator')
        self.leftExitLocator = self.arena.find('**/leftExit_locator')
        self.rightExitLocator = self.arena.find('**/rightExit_locator')
        self.teamCamPosLocators = (self.arena.find('**/team0CamPos_locator'), self.arena.find('**/team1CamPos_locator'))
        self.teamCamAimLocators = (self.arena.find('**/team0CamAim_locator'), self.arena.find('**/team1CamAim_locator'))
        leftTeamLocator = NodePath('TeamLocator-%d' % PartyGlobals.TeamActivityTeams.LeftTeam)
        leftTeamLocator.reparentTo(self.root)
        leftTeamLocator.setH(90)
        rightTeamLocator = NodePath('TeamLocator-%d' % PartyGlobals.TeamActivityTeams.RightTeam)
        rightTeamLocator.reparentTo(self.root)
        rightTeamLocator.setH(-90)
        self.teamLocators = (leftTeamLocator, rightTeamLocator)
        self._lengthBetweenEntrances = self.leftEntranceLocator.getY() - self.rightExitLocator.getY()
        self._skyCollisionsCollection = self.arena.findAllMatches('**/cogPieArena_sky*_collision')
        if len(self._skyCollisionsCollection) > 0:
            self._skyCollisionParent = self._skyCollisionsCollection[0].getParent()
        else:
            self._skyCollisionParent = self.arena
        self._wallCollisionsCollection = self.arena.findAllMatches('**/cogPieArena_wall*_collision')
        self._arenaFlagGroups = (self.arena.find('**/flagsL_grp'), self.arena.find('**/flagsR_grp'))
        self._initArenaDoors()
        self.cogManager = PartyCogManager()
        self.arrows = []
        self.distanceLabels = []
        self.teamColors = list(PartyGlobals.CogActivityColors) + [PartyGlobals.TeamActivityStatusColor]
        for i in range(3):
            start = self.arena.find('**/cog%d_start_locator' % (i + 1))
            end = self.arena.find('**/cog%d_end_locator' % (i + 1))
            cog = self.cogManager.generateCog(self.arena)
            cog.setEndPoints(start.getPos(), end.getPos())
            arrow1 = StretchingArrow(self.arena, useColor='orange')
            arrow2 = StretchingArrow(self.arena, useColor='blue')
            arrow1.setZ(0.1)
            arrow2.setZ(0.1)
            self.arrows.append([arrow1, arrow2])
            distanceLabel = self.createDistanceLabel(0, self.teamColors[1])
            distanceLabel[0].stash()
            distanceLabel2 = self.createDistanceLabel(0, self.teamColors[0])
            distanceLabel2[0].stash()
            self.distanceLabels.append([distanceLabel, distanceLabel2])

        self.winText = []
        text1 = self.createText(0, Point3(-0.5, 0.0, -0.5), self.teamColors[1])
        text2 = self.createText(1, Point3(0.5, 0.0, -0.5), self.teamColors[0])
        self.winText.append(text1)
        self.winText.append(text2)
        self.winStatus = self.createText(2, Point3(0.0, 0.0, -0.8), self.teamColors[0])
        signLocator = self.arena.find('**/eventSign_locator')
        self.activity.sign.setPos(signLocator.getPos(self.root))
        if self.texture:
            textureAlpha = self.texture[:-4] + '_a.rgb'
            reskinTexture = loader.loadTexture(self.texture, textureAlpha)
            self.arena.find('**/center_grp').setTexture(reskinTexture, 100)
            self.arena.find('**/leftSide_grp').setTexture(reskinTexture, 100)
            self.arena.find('**/rightSide_grp').setTexture(reskinTexture, 100)
        self.enable()
 def _createQuadrant(self, filepath, serialNum, angle, size):
     root = NodePath('QuadrantRoot-%i' % serialNum)
     quadrant = loader.loadModel(filepath)
     quadrant.getChildren().reparentTo(root)
     root.setH(angle)
     return root
class CogdoFlyingCameraManager:
    def __init__(self, cam, parent, player, level):
        self._toon = player.toon
        self._camera = cam
        self._parent = parent
        self._player = player
        self._level = level
        self._enabled = False

    def enable(self):
        if self._enabled:
            return
        self._toon.detachCamera()
        self._prevToonY = 0.0
        levelBounds = self._level.getBounds()
        l = Globals.Camera.LevelBoundsFactor
        self._bounds = (
            (levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]),
            (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]),
            (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]),
        )
        self._lookAtZ = self._toon.getHeight() + Globals.Camera.LookAtToonHeightOffset
        self._camParent = NodePath("CamParent")
        self._camParent.reparentTo(self._parent)
        self._camParent.setPos(self._toon, 0, 0, 0)
        self._camParent.setHpr(180, Globals.Camera.Angle, 0)
        self._camera.reparentTo(self._camParent)
        self._camera.setPos(0, Globals.Camera.Distance, 0)
        self._camera.lookAt(self._toon, 0, 0, self._lookAtZ)
        self._cameraLookAtNP = NodePath("CameraLookAt")
        self._cameraLookAtNP.reparentTo(self._camera.getParent())
        self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr())
        self._levelBounds = self._level.getBounds()
        self._enabled = True
        self._frozen = False
        self._initCollisions()

    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)

    def _destroyCollisions(self):
        self._collTrav.removeCollider(self._camCollNP)
        self._camCollNP.removeNode()
        del self._camCollNP
        del self._camCollRay
        del self._collHandler
        del self._collOffset
        del self._betweenCamAndToon
        self._transNP.removeNode()
        del self._transNP

    def freeze(self):
        self._frozen = True

    def unfreeze(self):
        self._frozen = False

    def disable(self):
        if not self._enabled:
            return
        self._destroyCollisions()
        self._camera.wrtReparentTo(render)
        self._cameraLookAtNP.removeNode()
        del self._cameraLookAtNP
        self._camParent.removeNode()
        del self._camParent
        del self._prevToonY
        del self._lookAtZ
        del self._bounds
        del self._frozen
        self._enabled = False

    def update(self, dt=0.0):
        self._updateCam(dt)
        self._updateCollisions()

    def _updateCam(self, dt):
        toonPos = self._toon.getPos()
        camPos = self._camParent.getPos()
        x = camPos[0]
        z = camPos[2]
        toonWorldX = self._toon.getX(render)
        maxX = Globals.Camera.MaxSpinX
        toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX)
        spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (maxX * maxX)
        newH = 180.0 + spinAngle
        self._camParent.setH(newH)
        spinAngle = spinAngle * (pi / 180.0)
        distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle)
        distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle)
        d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0])
        if abs(d) > Globals.Camera.LeewayX:
            if d > Globals.Camera.LeewayX:
                x = toonPos[0] + Globals.Camera.LeewayX
            else:
                x = toonPos[0] - Globals.Camera.LeewayX
        x = self._toon.getX(render) + distToRightOfToon
        boundToonZ = min(toonPos[2], self._bounds[2][1])
        d = z - boundToonZ
        if d > Globals.Camera.MinLeewayZ:
            if self._player.velocity[2] >= 0 and toonPos[1] != self._prevToonY or self._player.velocity[2] > 0:
                z = boundToonZ + d * INVERSE_E ** (dt * Globals.Camera.CatchUpRateZ)
            elif d > Globals.Camera.MaxLeewayZ:
                z = boundToonZ + Globals.Camera.MaxLeewayZ
        elif d < -Globals.Camera.MinLeewayZ:
            z = boundToonZ - Globals.Camera.MinLeewayZ
        if self._frozen:
            y = camPos[1]
        else:
            y = self._toon.getY(render) - distBehindToon
        self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z))
        if toonPos[2] < self._bounds[2][1]:
            h = self._cameraLookAtNP.getH()
            if d >= Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ)
            elif d <= -Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ)
            self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0)
            self._camera.setHpr(smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr()))
        self._prevToonY = toonPos[1]

    def _updateCollisions(self):
        pos = self._toon.getPos(self._camera) + self._collOffset
        self._camCollRay.setOrigin(pos)
        direction = -Vec3(pos)
        direction.normalize()
        self._camCollRay.setDirection(direction)
        self._collTrav.traverse(render)
        nodesInBetween = {}
        if self._collHandler.getNumEntries() > 0:
            self._collHandler.sortEntries()
            for entry in self._collHandler.getEntries():
                name = entry.getIntoNode().getName()
                if name.find("col_") >= 0:
                    np = entry.getIntoNodePath().getParent()
                    if not nodesInBetween.has_key(np):
                        nodesInBetween[np] = np.getParent()

        for np in nodesInBetween.keys():
            if self._betweenCamAndToon.has_key(np):
                del self._betweenCamAndToon[np]
            else:
                np.setTransparency(True)
                np.wrtReparentTo(self._transNP)
                if np.getName().find("lightFixture") >= 0:
                    if not np.find("**/*floor_mesh").isEmpty():
                        np.find("**/*floor_mesh").hide()
                elif np.getName().find("platform") >= 0:
                    if not np.find("**/*Floor").isEmpty():
                        np.find("**/*Floor").hide()

        for np, parent in self._betweenCamAndToon.items():
            np.wrtReparentTo(parent)
            np.setTransparency(False)
            if np.getName().find("lightFixture") >= 0:
                if not np.find("**/*floor_mesh").isEmpty():
                    np.find("**/*floor_mesh").show()
            elif np.getName().find("platform") >= 0:
                if not np.find("**/*Floor").isEmpty():
                    np.find("**/*Floor").show()

        self._betweenCamAndToon = nodesInBetween
예제 #28
0
class DistributedIceGame(DistributedMinigame.DistributedMinigame,
                         DistributedIceWorld.DistributedIceWorld):
    notify = directNotify.newCategory('DistributedIceGame')
    MaxLocalForce = 100
    MaxPhysicsForce = 25000

    def __init__(self, cr):
        DistributedMinigame.DistributedMinigame.__init__(self, cr)
        DistributedIceWorld.DistributedIceWorld.__init__(self, cr)
        self.gameFSM = ClassicFSM.ClassicFSM('DistributedIceGame', [
            State.State('off', self.enterOff, self.exitOff, ['inputChoice']),
            State.State(
                'inputChoice', self.enterInputChoice, self.exitInputChoice,
                ['waitServerChoices', 'moveTires', 'displayVotes', 'cleanup']),
            State.State('waitServerChoices', self.enterWaitServerChoices,
                        self.exitWaitServerChoices, ['moveTires', 'cleanup']),
            State.State('moveTires', self.enterMoveTires, self.exitMoveTires,
                        ['synch', 'cleanup']),
            State.State('synch', self.enterSynch, self.exitSynch,
                        ['inputChoice', 'scoring', 'cleanup']),
            State.State('scoring', self.enterScoring, self.exitScoring,
                        ['cleanup', 'finalResults', 'inputChoice']),
            State.State('finalResults', self.enterFinalResults,
                        self.exitFinalResults, ['cleanup']),
            State.State('cleanup', self.enterCleanup, self.exitCleanup, [])
        ], 'off', 'cleanup')
        self.addChildGameFSM(self.gameFSM)
        self.cameraThreeQuarterView = (0, -22, 45, 0, -62.890000000000001, 0)
        self.tireDict = {}
        self.forceArrowDict = {}
        self.canDrive = False
        self.timer = None
        self.timerStartTime = None
        self.curForce = 0
        self.curHeading = 0
        self.headingMomentum = 0.0
        self.forceMomentum = 0.0
        self.allTireInputs = None
        self.curRound = 0
        self.curMatch = 0
        self.controlKeyWarningLabel = DirectLabel(
            text=TTLocalizer.IceGameControlKeyWarning,
            text_fg=VBase4(1, 0, 0, 1),
            relief=None,
            pos=(0.0, 0, 0),
            scale=0.14999999999999999)
        self.controlKeyWarningLabel.hide()
        self.waitingMoveLabel = DirectLabel(
            text=TTLocalizer.IceGameWaitingForPlayersToFinishMove,
            text_fg=VBase4(1, 1, 1, 1),
            relief=None,
            pos=(-0.59999999999999998, 0, -0.75),
            scale=0.074999999999999997)
        self.waitingMoveLabel.hide()
        self.waitingSyncLabel = DirectLabel(
            text=TTLocalizer.IceGameWaitingForAISync,
            text_fg=VBase4(1, 1, 1, 1),
            relief=None,
            pos=(-0.59999999999999998, 0, -0.75),
            scale=0.074999999999999997)
        self.waitingSyncLabel.hide()
        self.infoLabel = DirectLabel(text='',
                                     text_fg=VBase4(0, 0, 0, 1),
                                     relief=None,
                                     pos=(0.0, 0, 0.69999999999999996),
                                     scale=0.074999999999999997)
        self.updateInfoLabel()
        self.lastForceArrowUpdateTime = 0
        self.sendForceArrowUpdateAsap = False
        self.treasures = []
        self.penalties = []
        self.obstacles = []
        self.controlKeyPressed = False
        self.controlKeyWarningIval = None

    def delete(self):
        DistributedIceWorld.DistributedIceWorld.delete(self)
        DistributedMinigame.DistributedMinigame.delete(self)
        if self.controlKeyWarningIval:
            self.controlKeyWarningIval.finish()
            self.controlKeyWarningIval = None

        self.controlKeyWarningLabel.destroy()
        del self.controlKeyWarningLabel
        self.waitingMoveLabel.destroy()
        del self.waitingMoveLabel
        self.waitingSyncLabel.destroy()
        del self.waitingSyncLabel
        self.infoLabel.destroy()
        del self.infoLabel
        for treasure in self.treasures:
            treasure.destroy()

        del self.treasures
        for penalty in self.penalties:
            penalty.destroy()

        del self.penalties
        for obstacle in self.obstacles:
            obstacle.removeNode()

        del self.obstacles
        del self.gameFSM

    def announceGenerate(self):
        DistributedMinigame.DistributedMinigame.announceGenerate(self)
        DistributedIceWorld.DistributedIceWorld.announceGenerate(self)
        self.debugTaskName = self.uniqueName('debugTask')

    def getTitle(self):
        return TTLocalizer.IceGameTitle

    def getInstructions(self):
        szId = self.getSafezoneId()
        numPenalties = IceGameGlobals.NumPenalties[szId]
        result = TTLocalizer.IceGameInstructions
        if numPenalties == 0:
            result = TTLocalizer.IceGameInstructionsNoTnt

        return result

    def getMaxDuration(self):
        return 0

    def load(self):
        self.notify.debug('load')
        DistributedMinigame.DistributedMinigame.load(self)
        self.music = base.loadMusic('phase_4/audio/bgm/MG_IceGame.mid')
        self.gameBoard = loader.loadModel(
            'phase_4/models/minigames/ice_game_icerink')
        background = loader.loadModel('phase_4/models/minigames/ice_game_2d')
        background.reparentTo(self.gameBoard)
        self.gameBoard.setPosHpr(0, 0, 0, 0, 0, 0)
        self.gameBoard.setScale(1.0)
        self.setupSimulation()
        index = 0
        for avId in self.avIdList:
            self.setupTire(avId, index)
            self.setupForceArrow(avId)
            index += 1

        for index in xrange(len(self.avIdList), 4):
            self.setupTire(-index, index)
            self.setupForceArrow(-index)

        self.showForceArrows(realPlayersOnly=True)
        self.westWallModel = NodePath()
        if not self.westWallModel.isEmpty():
            self.westWallModel.reparentTo(self.gameBoard)
            self.westWallModel.setPos(IceGameGlobals.MinWall[0],
                                      IceGameGlobals.MinWall[1], 0)
            self.westWallModel.setScale(4)

        self.eastWallModel = NodePath()
        if not self.eastWallModel.isEmpty():
            self.eastWallModel.reparentTo(self.gameBoard)
            self.eastWallModel.setPos(IceGameGlobals.MaxWall[0],
                                      IceGameGlobals.MaxWall[1], 0)
            self.eastWallModel.setScale(4)
            self.eastWallModel.setH(180)

        self.arrowKeys = ArrowKeys.ArrowKeys()
        self.target = loader.loadModel('phase_3/models/misc/sphere')
        self.target.setScale(0.01)
        self.target.reparentTo(self.gameBoard)
        self.target.setPos(0, 0, 0)
        self.scoreCircle = loader.loadModel(
            'phase_4/models/minigames/ice_game_score_circle')
        self.scoreCircle.setScale(0.01)
        self.scoreCircle.reparentTo(self.gameBoard)
        self.scoreCircle.setZ(IceGameGlobals.TireRadius / 2.0)
        self.scoreCircle.setAlphaScale(0.5)
        self.scoreCircle.setTransparency(1)
        self.scoreCircle.hide()
        self.treasureModel = loader.loadModel(
            'phase_4/models/minigames/ice_game_barrel')
        self.penaltyModel = loader.loadModel(
            'phase_4/models/minigames/ice_game_tnt2')
        self.penaltyModel.setScale(0.75, 0.75, 0.69999999999999996)
        szId = self.getSafezoneId()
        obstacles = IceGameGlobals.Obstacles[szId]
        index = 0
        cubicObstacle = IceGameGlobals.ObstacleShapes[szId]
        for pos in obstacles:
            newPos = Point3(pos[0], pos[1], IceGameGlobals.TireRadius)
            newObstacle = self.createObstacle(newPos, index, cubicObstacle)
            self.obstacles.append(newObstacle)
            index += 1

        self.countSound = loader.loadSfx(
            'phase_3.5/audio/sfx/tick_counter.mp3')
        self.treasureGrabSound = loader.loadSfx(
            'phase_4/audio/sfx/MG_sfx_vine_game_bananas.mp3')
        self.penaltyGrabSound = loader.loadSfx(
            'phase_4/audio/sfx/MG_cannon_fire_alt.mp3')
        self.tireSounds = []
        for tireIndex in xrange(4):
            tireHit = loader.loadSfx(
                'phase_4/audio/sfx/Golf_Hit_Barrier_1.mp3')
            wallHit = loader.loadSfx('phase_4/audio/sfx/MG_maze_pickup.mp3')
            obstacleHit = loader.loadSfx(
                'phase_4/audio/sfx/Golf_Hit_Barrier_2.mp3')
            self.tireSounds.append({
                'tireHit': tireHit,
                'wallHit': wallHit,
                'obstacleHit': obstacleHit
            })

        self.arrowRotateSound = loader.loadSfx(
            'phase_4/audio/sfx/MG_sfx_ice_force_rotate.wav')
        self.arrowUpSound = loader.loadSfx(
            'phase_4/audio/sfx/MG_sfx_ice_force_increase_3sec.mp3')
        self.arrowDownSound = loader.loadSfx(
            'phase_4/audio/sfx/MG_sfx_ice_force_decrease_3sec.mp3')
        self.scoreCircleSound = loader.loadSfx(
            'phase_4/audio/sfx/MG_sfx_ice_scoring_1.mp3')

    def unload(self):
        self.notify.debug('unload')
        DistributedMinigame.DistributedMinigame.unload(self)
        del self.music
        self.gameBoard.removeNode()
        del self.gameBoard
        for forceArrow in self.forceArrowDict.values():
            forceArrow.removeNode()

        del self.forceArrowDict
        self.scoreCircle.removeNode()
        del self.scoreCircle
        del self.countSound

    def onstage(self):
        self.notify.debug('onstage')
        DistributedMinigame.DistributedMinigame.onstage(self)
        self.gameBoard.reparentTo(render)
        self._DistributedIceGame__placeToon(self.localAvId)
        self.moveCameraToTop()
        self.scorePanels = []
        base.playMusic(self.music, looping=1, volume=0.80000000000000004)

    def offstage(self):
        self.notify.debug('offstage')
        self.music.stop()
        self.gameBoard.hide()
        self.infoLabel.hide()
        for avId in self.tireDict:
            self.tireDict[avId]['tireNodePath'].hide()

        for panel in self.scorePanels:
            panel.cleanup()

        del self.scorePanels
        for obstacle in self.obstacles:
            obstacle.hide()

        for treasure in self.treasures:
            treasure.nodePath.hide()

        for penalty in self.penalties:
            penalty.nodePath.hide()

        for avId in self.avIdList:
            av = self.getAvatar(avId)
            if av:
                av.dropShadow.show()
                av.resetLOD()
                continue

        taskMgr.remove(self.uniqueName('aimtask'))
        self.arrowKeys.destroy()
        del self.arrowKeys
        DistributedMinigame.DistributedMinigame.offstage(self)

    def handleDisabledAvatar(self, avId):
        self.notify.debug('handleDisabledAvatar')
        self.notify.debug('avatar ' + str(avId) + ' disabled')
        DistributedMinigame.DistributedMinigame.handleDisabledAvatar(
            self, avId)

    def setGameReady(self):
        if not self.hasLocalToon:
            return None

        self.notify.debug('setGameReady')
        if DistributedMinigame.DistributedMinigame.setGameReady(self):
            return None

        for index in xrange(self.numPlayers):
            avId = self.avIdList[index]
            toon = self.getAvatar(avId)
            if toon:
                toon.reparentTo(render)
                self._DistributedIceGame__placeToon(avId)
                toon.forwardSpeed = 0
                toon.rotateSpeed = False
                toon.dropShadow.hide()
                toon.setAnimState('Sit')
                if avId in self.tireDict:
                    tireNp = self.tireDict[avId]['tireNodePath']
                    toon.reparentTo(tireNp)
                    toon.setY(1.0)
                    toon.setZ(-3)

                toon.startLookAround()
                continue

    def setGameStart(self, timestamp):
        if not self.hasLocalToon:
            return None

        self.notify.debug('setGameStart')
        DistributedMinigame.DistributedMinigame.setGameStart(self, timestamp)
        for avId in self.remoteAvIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.stopLookAround()
                continue

        self.scores = [0] * self.numPlayers
        spacing = 0.40000000000000002
        for i in xrange(self.numPlayers):
            avId = self.avIdList[i]
            avName = self.getAvatarName(avId)
            scorePanel = MinigameAvatarScorePanel.MinigameAvatarScorePanel(
                avId, avName)
            scorePanel.setScale(0.90000000000000002)
            scorePanel.setPos(0.75 - spacing * (self.numPlayers - 1 - i), 0.0,
                              0.875)
            scorePanel.makeTransparent(0.75)
            self.scorePanels.append(scorePanel)

        self.arrowKeys.setPressHandlers([
            self._DistributedIceGame__upArrowPressed,
            self._DistributedIceGame__downArrowPressed,
            self._DistributedIceGame__leftArrowPressed,
            self._DistributedIceGame__rightArrowPressed,
            self._DistributedIceGame__controlPressed
        ])

    def isInPlayState(self):
        if not self.gameFSM.getCurrentState():
            return False

        if not self.gameFSM.getCurrentState().getName() == 'play':
            return False

        return True

    def enterOff(self):
        self.notify.debug('enterOff')

    def exitOff(self):
        pass

    def enterInputChoice(self):
        self.notify.debug('enterInputChoice')
        self.forceLocalToonToTire()
        self.controlKeyPressed = False
        if self.curRound == 0:
            self.setupStartOfMatch()
        else:
            self.notify.debug('self.curRound = %s' % self.curRound)
        self.timer = ToontownTimer.ToontownTimer()
        self.timer.hide()
        if self.timerStartTime != None:
            self.startTimer()

        self.showForceArrows(realPlayersOnly=True)
        self.localForceArrow().setPosHpr(0, 0, -1.0, 0, 0, 0)
        self.localForceArrow().reparentTo(self.localTireNp())
        self.localForceArrow().setY(IceGameGlobals.TireRadius)
        self.localTireNp().headsUp(self.target)
        self.notify.debug('self.localForceArrow() heading = %s' %
                          self.localForceArrow().getH())
        self.curHeading = self.localTireNp().getH()
        self.curForce = 25
        self.updateLocalForceArrow()
        for avId in self.forceArrowDict:
            forceArrow = self.forceArrowDict[avId]
            forceArrow.setPosHpr(0, 0, -1.0, 0, 0, 0)
            tireNp = self.tireDict[avId]['tireNodePath']
            forceArrow.reparentTo(tireNp)
            forceArrow.setY(IceGameGlobals.TireRadius)
            tireNp.headsUp(self.target)
            self.updateForceArrow(avId, tireNp.getH(), 25)

        taskMgr.add(self._DistributedIceGame__aimTask,
                    self.uniqueName('aimtask'))
        if base.localAvatar.laffMeter:
            base.localAvatar.laffMeter.stop()

        self.sendForceArrowUpdateAsap = False

    def exitInputChoice(self):
        if not self.controlKeyPressed:
            if self.controlKeyWarningIval:
                self.controlKeyWarningIval.finish()
                self.controlKeyWarningIval = None

            self.controlKeyWarningIval = Sequence(
                Func(self.controlKeyWarningLabel.show),
                self.controlKeyWarningLabel.colorScaleInterval(
                    10, VBase4(1, 1, 1, 0), startColorScale=VBase4(1, 1, 1,
                                                                   1)),
                Func(self.controlKeyWarningLabel.hide))
            self.controlKeyWarningIval.start()

        if self.timer != None:
            self.timer.destroy()
            self.timer = None

        self.timerStartTime = None
        self.hideForceArrows()
        self.arrowRotateSound.stop()
        self.arrowUpSound.stop()
        self.arrowDownSound.stop()
        taskMgr.remove(self.uniqueName('aimtask'))

    def enterWaitServerChoices(self):
        self.waitingMoveLabel.show()
        self.showForceArrows(True)

    def exitWaitServerChoices(self):
        self.waitingMoveLabel.hide()
        self.hideForceArrows()

    def enterMoveTires(self):
        for key in self.tireDict:
            body = self.tireDict[key]['tireBody']
            body.setAngularVel(0, 0, 0)
            body.setLinearVel(0, 0, 0)

        for index in xrange(len(self.allTireInputs)):
            input = self.allTireInputs[index]
            avId = self.avIdList[index]
            body = self.getTireBody(avId)
            degs = input[1] + 90
            tireNp = self.getTireNp(avId)
            tireH = tireNp.getH()
            self.notify.debug('tireH = %s' % tireH)
            radAngle = deg2Rad(degs)
            foo = NodePath('foo')
            dirVector = Vec3(math.cos(radAngle), math.sin(radAngle), 0)
            self.notify.debug('dirVector is now=%s' % dirVector)
            inputForce = input[0]
            inputForce /= self.MaxLocalForce
            inputForce *= self.MaxPhysicsForce
            force = dirVector * inputForce
            self.notify.debug('adding force %s to %d' % (force, avId))
            body.addForce(force)

        self.enableAllTireBodies()
        self.totalPhysicsSteps = 0
        self.startSim()
        taskMgr.add(self._DistributedIceGame__moveTiresTask,
                    self.uniqueName('moveTiresTtask'))

    def exitMoveTires(self):
        self.forceLocalToonToTire()
        self.disableAllTireBodies()
        self.stopSim()
        self.notify.debug('total Physics steps = %d' % self.totalPhysicsSteps)
        taskMgr.remove(self.uniqueName('moveTiresTtask'))

    def enterSynch(self):
        self.waitingSyncLabel.show()

    def exitSynch(self):
        self.waitingSyncLabel.hide()

    def enterScoring(self):
        sortedByDistance = []
        for avId in self.avIdList:
            np = self.getTireNp(avId)
            pos = np.getPos()
            pos.setZ(0)
            sortedByDistance.append((avId, pos.length()))

        def compareDistance(x, y):
            if x[1] - y[1] > 0:
                return 1
            elif x[1] - y[1] < 0:
                return -1
            else:
                return 0

        sortedByDistance.sort(cmp=compareDistance)
        self.scoreMovie = Sequence()
        curScale = 0.01
        curTime = 0
        self.scoreCircle.setScale(0.01)
        self.scoreCircle.show()
        self.notify.debug('newScores = %s' % self.newScores)
        circleStartTime = 0
        for index in xrange(len(sortedByDistance)):
            distance = sortedByDistance[index][1]
            avId = sortedByDistance[index][0]
            scorePanelIndex = self.avIdList.index(avId)
            time = (distance - curScale) / IceGameGlobals.ExpandFeetPerSec
            if time < 0:
                time = 0.01

            scaleXY = distance + IceGameGlobals.TireRadius
            self.notify.debug('circleStartTime = %s' % circleStartTime)
            self.scoreMovie.append(
                Parallel(
                    LerpScaleInterval(self.scoreCircle, time,
                                      Point3(scaleXY, scaleXY, 1.0)),
                    SoundInterval(self.scoreCircleSound,
                                  duration=time,
                                  startTime=circleStartTime)))
            circleStartTime += time
            startScore = self.scorePanels[scorePanelIndex].getScore()
            destScore = self.newScores[scorePanelIndex]
            self.notify.debug('for avId %d, startScore=%d, newScores=%d' %
                              (avId, startScore, destScore))

            def increaseScores(t,
                               scorePanelIndex=scorePanelIndex,
                               startScore=startScore,
                               destScore=destScore):
                oldScore = self.scorePanels[scorePanelIndex].getScore()
                diff = destScore - startScore
                newScore = int(startScore + diff * t)
                if newScore > oldScore:
                    base.playSfx(self.countSound)

                self.scorePanels[scorePanelIndex].setScore(newScore)
                self.scores[scorePanelIndex] = newScore

            duration = (destScore -
                        startScore) * IceGameGlobals.ScoreCountUpRate
            tireNp = self.tireDict[avId]['tireNodePath']
            self.scoreMovie.append(
                Parallel(
                    LerpFunctionInterval(increaseScores, duration),
                    Sequence(
                        LerpColorScaleInterval(tireNp, duration / 6.0,
                                               VBase4(1, 0, 0, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0,
                                               VBase4(1, 1, 1, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0,
                                               VBase4(1, 0, 0, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0,
                                               VBase4(1, 1, 1, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0,
                                               VBase4(1, 0, 0, 1)),
                        LerpColorScaleInterval(tireNp, duration / 6.0,
                                               VBase4(1, 1, 1, 1)))))
            curScale += distance

        self.scoreMovie.append(
            Func(self.sendUpdate, 'reportScoringMovieDone', []))
        self.scoreMovie.start()

    def exitScoring(self):
        self.scoreMovie.finish()
        self.scoreMovie = None
        self.scoreCircle.hide()

    def enterFinalResults(self):
        lerpTrack = Parallel()
        lerpDur = 0.5
        tY = 0.59999999999999998
        bY = -0.050000000000000003
        lX = -0.5
        cX = 0
        rX = 0.5
        scorePanelLocs = (((cX, bY), ), ((lX, bY), (rX, bY)),
                          ((cX, tY), (lX, bY), (rX, bY)), ((lX, tY), (rX, tY),
                                                           (lX, bY), (rX, bY)))
        scorePanelLocs = scorePanelLocs[self.numPlayers - 1]
        for i in xrange(self.numPlayers):
            panel = self.scorePanels[i]
            pos = scorePanelLocs[i]
            lerpTrack.append(
                Parallel(
                    LerpPosInterval(panel,
                                    lerpDur,
                                    Point3(pos[0], 0, pos[1]),
                                    blendType='easeInOut'),
                    LerpScaleInterval(panel,
                                      lerpDur,
                                      Vec3(panel.getScale()) * 2.0,
                                      blendType='easeInOut')))

        self.showScoreTrack = Parallel(
            lerpTrack,
            Sequence(Wait(IceGameGlobals.ShowScoresDuration),
                     Func(self.gameOver)))
        self.showScoreTrack.start()

    def exitFinalResults(self):
        self.showScoreTrack.pause()
        del self.showScoreTrack

    def enterCleanup(self):
        self.notify.debug('enterCleanup')
        if base.localAvatar.laffMeter:
            base.localAvatar.laffMeter.start()

    def exitCleanup(self):
        pass

    def _DistributedIceGame__placeToon(self, avId):
        toon = self.getAvatar(avId)
        if toon:
            toon.setPos(0, 0, 0)
            toon.setHpr(0, 0, 0)

    def moveCameraToTop(self):
        camera.reparentTo(render)
        p = self.cameraThreeQuarterView
        camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5])

    def setupTire(self, avId, index):
        (tireNp, tireBody, tireOdeGeom) = self.createTire(index)
        self.tireDict[avId] = {
            'tireNodePath': tireNp,
            'tireBody': tireBody,
            'tireOdeGeom': tireOdeGeom
        }
        if avId <= 0:
            tireBlocker = tireNp.find('**/tireblockermesh')
            if not tireBlocker.isEmpty():
                tireBlocker.hide()

        if avId == self.localAvId:
            tireNp = self.tireDict[avId]['tireNodePath']
            self.treasureSphereName = 'treasureCollider'
            self.treasureCollSphere = CollisionSphere(
                0, 0, 0, IceGameGlobals.TireRadius)
            self.treasureCollSphere.setTangible(0)
            self.treasureCollNode = CollisionNode(self.treasureSphereName)
            self.treasureCollNode.setFromCollideMask(
                ToontownGlobals.PieBitmask)
            self.treasureCollNode.addSolid(self.treasureCollSphere)
            self.treasureCollNodePath = tireNp.attachNewNode(
                self.treasureCollNode)
            self.treasureHandler = CollisionHandlerEvent()
            self.treasureHandler.addInPattern('%fn-intoTreasure')
            base.cTrav.addCollider(self.treasureCollNodePath,
                                   self.treasureHandler)
            eventName = '%s-intoTreasure' % self.treasureCollNodePath.getName()
            self.notify.debug('eventName = %s' % eventName)
            self.accept(eventName, self.toonHitSomething)

    def setupForceArrow(self, avId):
        arrow = loader.loadModel('phase_4/models/minigames/ice_game_arrow')
        priority = 0
        if avId < 0:
            priority = -avId
        else:
            priority = self.avIdList.index(avId)
            if avId == self.localAvId:
                priority = 10

        self.forceArrowDict[avId] = arrow

    def hideForceArrows(self):
        for forceArrow in self.forceArrowDict.values():
            forceArrow.hide()

    def showForceArrows(self, realPlayersOnly=True):
        for avId in self.forceArrowDict:
            if realPlayersOnly:
                if avId > 0:
                    self.forceArrowDict[avId].show()
                else:
                    self.forceArrowDict[avId].hide()
            avId > 0
            self.forceArrowDict[avId].show()

    def localForceArrow(self):
        if self.localAvId in self.forceArrowDict:
            return self.forceArrowDict[self.localAvId]
        else:
            return None

    def setChoices(self, input0, input1, input2, input3):
        pass

    def startDebugTask(self):
        taskMgr.add(self.debugTask, self.debugTaskName)

    def stopDebugTask(self):
        taskMgr.remove(self.debugTaskName)

    def debugTask(self, task):
        if self.canDrive and self.tireDict.has_key(localAvatar.doId):
            dt = globalClock.getDt()
            forceMove = 25000
            forceMoveDt = forceMove
            tireBody = self.tireDict[localAvatar.doId]['tireBody']
            if self.arrowKeys.upPressed() and not tireBody.isEnabled():
                x = 0
                y = 1
                tireBody.enable()
                tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))

            if self.arrowKeys.downPressed() and not tireBody.isEnabled():
                x = 0
                y = -1
                tireBody.enable()
                tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))

            if self.arrowKeys.leftPressed() and not tireBody.isEnabled():
                x = -1
                y = 0
                tireBody.enable()
                tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))

            if self.arrowKeys.rightPressed() and not tireBody.isEnabled():
                x = 1
                y = 0
                tireBody.enable()
                tireBody.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))

        return task.cont

    def _DistributedIceGame__upArrowPressed(self):
        pass

    def _DistributedIceGame__downArrowPressed(self):
        pass

    def _DistributedIceGame__leftArrowPressed(self):
        pass

    def _DistributedIceGame__rightArrowPressed(self):
        pass

    def _DistributedIceGame__controlPressed(self):
        if self.gameFSM.getCurrentState().getName() == 'inputChoice':
            self.sendForceArrowUpdateAsap = True
            self.updateLocalForceArrow()
            self.controlKeyPressed = True
            self.sendUpdate('setAvatarChoice',
                            [self.curForce, self.curHeading])
            self.gameFSM.request('waitServerChoices')

    def startTimer(self):
        now = globalClock.getFrameTime()
        elapsed = now - self.timerStartTime
        self.timer.posInTopRightCorner()
        self.timer.setTime(IceGameGlobals.InputTimeout)
        self.timer.countdown(IceGameGlobals.InputTimeout - elapsed,
                             self.handleChoiceTimeout)
        self.timer.show()

    def setTimerStartTime(self, timestamp):
        if not self.hasLocalToon:
            return None

        self.timerStartTime = globalClockDelta.networkToLocalTime(timestamp)
        if self.timer != None:
            self.startTimer()

    def handleChoiceTimeout(self):
        self.sendUpdate('setAvatarChoice', [0, 0])
        self.gameFSM.request('waitServerChoices')

    def localTireNp(self):
        ret = None
        if self.localAvId in self.tireDict:
            ret = self.tireDict[self.localAvId]['tireNodePath']

        return ret

    def localTireBody(self):
        ret = None
        if self.localAvId in self.tireDict:
            ret = self.tireDict[self.localAvId]['tireBody']

        return ret

    def getTireBody(self, avId):
        ret = None
        if avId in self.tireDict:
            ret = self.tireDict[avId]['tireBody']

        return ret

    def getTireNp(self, avId):
        ret = None
        if avId in self.tireDict:
            ret = self.tireDict[avId]['tireNodePath']

        return ret

    def updateForceArrow(self, avId, curHeading, curForce):
        forceArrow = self.forceArrowDict[avId]
        tireNp = self.tireDict[avId]['tireNodePath']
        tireNp.setH(curHeading)
        tireBody = self.tireDict[avId]['tireBody']
        tireBody.setQuaternion(tireNp.getQuat())
        self.notify.debug('curHeading = %s' % curHeading)
        yScale = curForce / 100.0
        yScale *= 1
        headY = yScale * 15
        xScale = (yScale - 1) / 2.0 + 1.0
        shaft = forceArrow.find('**/arrow_shaft')
        head = forceArrow.find('**/arrow_head')
        shaft.setScale(xScale, yScale, 1)
        head.setPos(0, headY, 0)
        head.setScale(xScale, xScale, 1)

    def updateLocalForceArrow(self):
        avId = self.localAvId
        self.b_setForceArrowInfo(avId, self.curHeading, self.curForce)

    def _DistributedIceGame__aimTask(self, task):
        if not hasattr(self, 'arrowKeys'):
            return task.done

        dt = globalClock.getDt()
        headingMomentumChange = dt * 60.0
        forceMomentumChange = dt * 160.0
        arrowUpdate = False
        arrowRotating = False
        arrowUp = False
        arrowDown = False
        if self.arrowKeys.upPressed() and not self.arrowKeys.downPressed():
            self.forceMomentum += forceMomentumChange
            if self.forceMomentum < 0:
                self.forceMomentum = 0

            if self.forceMomentum > 50:
                self.forceMomentum = 50

            oldForce = self.curForce
            self.curForce += self.forceMomentum * dt
            arrowUpdate = True
            if oldForce < self.MaxLocalForce:
                arrowUp = True

        elif self.arrowKeys.downPressed() and not self.arrowKeys.upPressed():
            self.forceMomentum += forceMomentumChange
            if self.forceMomentum < 0:
                self.forceMomentum = 0

            if self.forceMomentum > 50:
                self.forceMomentum = 50

            oldForce = self.curForce
            self.curForce -= self.forceMomentum * dt
            arrowUpdate = True
            if oldForce > 0.01:
                arrowDown = True

        else:
            self.forceMomentum = 0
        if self.arrowKeys.leftPressed() and not self.arrowKeys.rightPressed():
            self.headingMomentum += headingMomentumChange
            if self.headingMomentum < 0:
                self.headingMomentum = 0

            if self.headingMomentum > 50:
                self.headingMomentum = 50

            self.curHeading += self.headingMomentum * dt
            arrowUpdate = True
            arrowRotating = True
        elif self.arrowKeys.rightPressed(
        ) and not self.arrowKeys.leftPressed():
            self.headingMomentum += headingMomentumChange
            if self.headingMomentum < 0:
                self.headingMomentum = 0

            if self.headingMomentum > 50:
                self.headingMomentum = 50

            self.curHeading -= self.headingMomentum * dt
            arrowUpdate = True
            arrowRotating = True
        else:
            self.headingMomentum = 0
        if arrowUpdate:
            self.normalizeHeadingAndForce()
            self.updateLocalForceArrow()

        if arrowRotating:
            if not self.arrowRotateSound.status(
            ) == self.arrowRotateSound.PLAYING:
                base.playSfx(self.arrowRotateSound, looping=True)

        else:
            self.arrowRotateSound.stop()
        if arrowUp:
            if not self.arrowUpSound.status() == self.arrowUpSound.PLAYING:
                base.playSfx(self.arrowUpSound, looping=False)

        else:
            self.arrowUpSound.stop()
        if arrowDown:
            if not self.arrowDownSound.status() == self.arrowDownSound.PLAYING:
                base.playSfx(self.arrowDownSound, looping=False)

        else:
            self.arrowDownSound.stop()
        return task.cont

    def normalizeHeadingAndForce(self):
        if self.curForce > self.MaxLocalForce:
            self.curForce = self.MaxLocalForce

        if self.curForce < 0.01:
            self.curForce = 0.01

    def setTireInputs(self, tireInputs):
        if not self.hasLocalToon:
            return None

        self.allTireInputs = tireInputs
        self.gameFSM.request('moveTires')

    def enableAllTireBodies(self):
        for avId in self.tireDict.keys():
            self.tireDict[avId]['tireBody'].enable()

    def disableAllTireBodies(self):
        for avId in self.tireDict.keys():
            self.tireDict[avId]['tireBody'].disable()

    def areAllTiresDisabled(self):
        for avId in self.tireDict.keys():
            if self.tireDict[avId]['tireBody'].isEnabled():
                return False
                continue

        return True

    def _DistributedIceGame__moveTiresTask(self, task):
        if self.areAllTiresDisabled():
            self.sendTirePositions()
            self.gameFSM.request('synch')
            return task.done

        return task.cont

    def sendTirePositions(self):
        tirePositions = []
        for index in xrange(len(self.avIdList)):
            avId = self.avIdList[index]
            tire = self.getTireBody(avId)
            pos = Point3(tire.getPosition())
            tirePositions.append([pos[0], pos[1], pos[2]])

        for index in xrange(len(self.avIdList), 4):
            avId = -index
            tire = self.getTireBody(avId)
            pos = Point3(tire.getPosition())
            tirePositions.append([pos[0], pos[1], pos[2]])

        self.sendUpdate('endingPositions', [tirePositions])

    def setFinalPositions(self, finalPos):
        if not self.hasLocalToon:
            return None

        for index in xrange(len(self.avIdList)):
            avId = self.avIdList[index]
            tire = self.getTireBody(avId)
            np = self.getTireNp(avId)
            pos = finalPos[index]
            tire.setPosition(pos[0], pos[1], pos[2])
            np.setPos(pos[0], pos[1], pos[2])

        for index in xrange(len(self.avIdList), 4):
            avId = -index
            tire = self.getTireBody(avId)
            np = self.getTireNp(avId)
            pos = finalPos[index]
            tire.setPosition(pos[0], pos[1], pos[2])
            np.setPos(pos[0], pos[1], pos[2])

    def updateInfoLabel(self):
        self.infoLabel['text'] = TTLocalizer.IceGameInfo % {
            'curMatch': self.curMatch + 1,
            'numMatch': IceGameGlobals.NumMatches,
            'curRound': self.curRound + 1,
            'numRound': IceGameGlobals.NumRounds
        }

    def setMatchAndRound(self, match, round):
        if not self.hasLocalToon:
            return None

        self.curMatch = match
        self.curRound = round
        self.updateInfoLabel()

    def setScores(self, match, round, scores):
        if not self.hasLocalToon:
            return None

        self.newMatch = match
        self.newRound = round
        self.newScores = scores

    def setNewState(self, state):
        if not self.hasLocalToon:
            return None

        self.notify.debug('setNewState gameFSM=%s newState=%s' %
                          (self.gameFSM, state))
        self.gameFSM.request(state)

    def putAllTiresInStartingPositions(self):
        for index in xrange(len(self.avIdList)):
            avId = self.avIdList[index]
            np = self.tireDict[avId]['tireNodePath']
            np.setPos(IceGameGlobals.StartingPositions[index])
            self.notify.debug('avId=%s newPos=%s' % (avId, np.getPos))
            np.setHpr(0, 0, 0)
            quat = np.getQuat()
            body = self.tireDict[avId]['tireBody']
            body.setPosition(IceGameGlobals.StartingPositions[index])
            body.setQuaternion(quat)

        for index in xrange(len(self.avIdList), 4):
            avId = -index
            np = self.tireDict[avId]['tireNodePath']
            np.setPos(IceGameGlobals.StartingPositions[index])
            self.notify.debug('avId=%s newPos=%s' % (avId, np.getPos))
            np.setHpr(0, 0, 0)
            quat = np.getQuat()
            body = self.tireDict[avId]['tireBody']
            body.setPosition(IceGameGlobals.StartingPositions[index])
            body.setQuaternion(quat)

    def b_setForceArrowInfo(self, avId, force, heading):
        self.setForceArrowInfo(avId, force, heading)
        self.d_setForceArrowInfo(avId, force, heading)

    def d_setForceArrowInfo(self, avId, force, heading):
        sendIt = False
        curTime = self.getCurrentGameTime()
        if self.sendForceArrowUpdateAsap:
            sendIt = True
        elif curTime - self.lastForceArrowUpdateTime > 0.20000000000000001:
            sendIt = True

        if sendIt:
            self.sendUpdate('setForceArrowInfo', [avId, force, heading])
            self.sendForceArrowUpdateAsap = False
            self.lastForceArrowUpdateTime = self.getCurrentGameTime()

    def setForceArrowInfo(self, avId, force, heading):
        if not self.hasLocalToon:
            return None

        self.updateForceArrow(avId, force, heading)

    def setupStartOfMatch(self):
        self.putAllTiresInStartingPositions()
        szId = self.getSafezoneId()
        self.numTreasures = IceGameGlobals.NumTreasures[szId]
        if self.treasures:
            for treasure in self.treasures:
                treasure.destroy()

            self.treasures = []

        index = 0
        treasureMargin = IceGameGlobals.TireRadius + 1.0
        while len(self.treasures) < self.numTreasures:
            xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5,
                                               IceGameGlobals.MaxWall[0] - 5)
            yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5,
                                               IceGameGlobals.MaxWall[1] - 5)
            self.notify.debug('yPos=%s' % yPos)
            pos = Point3(xPos, yPos, IceGameGlobals.TireRadius)
            newTreasure = IceTreasure.IceTreasure(self.treasureModel,
                                                  pos,
                                                  index,
                                                  self.doId,
                                                  penalty=False)
            goodSpot = True
            for obstacle in self.obstacles:
                if newTreasure.nodePath.getDistance(obstacle) < treasureMargin:
                    goodSpot = False
                    break
                    continue

            if goodSpot:
                for treasure in self.treasures:
                    if newTreasure.nodePath.getDistance(
                            treasure.nodePath) < treasureMargin:
                        goodSpot = False
                        break
                        continue

            if goodSpot:
                self.treasures.append(newTreasure)
                index += 1
                continue
            newTreasure.destroy()
        self.numPenalties = IceGameGlobals.NumPenalties[szId]
        if self.penalties:
            for penalty in self.penalties:
                penalty.destroy()

            self.penalties = []

        index = 0
        while len(self.penalties) < self.numPenalties:
            xPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[0] + 5,
                                               IceGameGlobals.MaxWall[0] - 5)
            yPos = self.randomNumGen.randrange(IceGameGlobals.MinWall[1] + 5,
                                               IceGameGlobals.MaxWall[1] - 5)
            self.notify.debug('yPos=%s' % yPos)
            pos = Point3(xPos, yPos, IceGameGlobals.TireRadius)
            newPenalty = IceTreasure.IceTreasure(self.penaltyModel,
                                                 pos,
                                                 index,
                                                 self.doId,
                                                 penalty=True)
            goodSpot = True
            for obstacle in self.obstacles:
                if newPenalty.nodePath.getDistance(obstacle) < treasureMargin:
                    goodSpot = False
                    break
                    continue

            if goodSpot:
                for treasure in self.treasures:
                    if newPenalty.nodePath.getDistance(
                            treasure.nodePath) < treasureMargin:
                        goodSpot = False
                        break
                        continue

            if goodSpot:
                for penalty in self.penalties:
                    if newPenalty.nodePath.getDistance(
                            penalty.nodePath) < treasureMargin:
                        goodSpot = False
                        break
                        continue

            if goodSpot:
                self.penalties.append(newPenalty)
                index += 1
                continue
            newPenalty.destroy()

    def toonHitSomething(self, entry):
        self.notify.debug('---- treasure Enter ---- ')
        self.notify.debug('%s' % entry)
        name = entry.getIntoNodePath().getName()
        parts = name.split('-')
        if len(parts) < 3:
            self.notify.debug('collided with %s, but returning' % name)
            return None

        if not int(parts[1]) == self.doId:
            self.notify.debug("collided with %s, but doId doesn't match" %
                              name)
            return None

        treasureNum = int(parts[2])
        if 'penalty' in parts[0]:
            self._DistributedIceGame__penaltyGrabbed(treasureNum)
        else:
            self._DistributedIceGame__treasureGrabbed(treasureNum)

    def _DistributedIceGame__treasureGrabbed(self, treasureNum):
        self.treasures[treasureNum].showGrab()
        self.treasureGrabSound.play()
        self.sendUpdate('claimTreasure', [treasureNum])

    def setTreasureGrabbed(self, avId, treasureNum):
        if not self.hasLocalToon:
            return None

        self.notify.debug('treasure %s grabbed by %s' % (treasureNum, avId))
        if avId != self.localAvId:
            self.treasures[treasureNum].showGrab()

        i = self.avIdList.index(avId)
        self.scores[i] += 1
        self.scorePanels[i].setScore(self.scores[i])

    def _DistributedIceGame__penaltyGrabbed(self, penaltyNum):
        self.penalties[penaltyNum].showGrab()
        self.sendUpdate('claimPenalty', [penaltyNum])

    def setPenaltyGrabbed(self, avId, penaltyNum):
        if not self.hasLocalToon:
            return None

        self.notify.debug('penalty %s grabbed by %s' % (penaltyNum, avId))
        if avId != self.localAvId:
            self.penalties[penaltyNum].showGrab()

        i = self.avIdList.index(avId)
        self.scores[i] -= 1
        self.scorePanels[i].setScore(self.scores[i])

    def postStep(self):
        DistributedIceWorld.DistributedIceWorld.postStep(self)
        for count in range(self.colCount):
            (c0, c1) = self.getOrderedContacts(count)
            if c1 in self.tireCollideIds:
                tireIndex = self.tireCollideIds.index(c1)
                if c0 in self.tireCollideIds:
                    self.tireSounds[tireIndex]['tireHit'].play()
                elif c0 == self.wallCollideId:
                    self.tireSounds[tireIndex]['wallHit'].play()
                elif c0 == self.obstacleCollideId:
                    self.tireSounds[tireIndex]['obstacleHit'].play()

            c0 in self.tireCollideIds

    def forceLocalToonToTire(self):
        toon = localAvatar
        if toon and self.localAvId in self.tireDict:
            tireNp = self.tireDict[self.localAvId]['tireNodePath']
            toon.reparentTo(tireNp)
            toon.setPosHpr(0, 0, 0, 0, 0, 0)
            toon.setY(1.0)
            toon.setZ(-3)
class PartyCog(FSM):
    notify = directNotify.newCategory('PartyCog')
    HpTextGenerator = TextNode('HpTextGenerator')
    hpText = None
    height = 7

    def __init__(self, parentNode, id, bounceSpeed = 3, bounceHeight = 1, rotateSpeed = 1, heightShift = 1, xMoveSpeed = 0, xMoveDistance = 0, bounceOffset = 0):
        self.id = id
        FSM.__init__(self, 'PartyCogFSM-%d' % self.id)
        self.showFacingStatus = False
        self.xMoveSpeed = xMoveSpeed
        self.xMoveDistance = xMoveDistance
        self.heightShift = heightShift
        self.bounceSpeed = bounceSpeed
        self.bounceHeight = bounceHeight
        self.rotateSpeed = rotateSpeed
        self.parentNode = parentNode
        self.bounceOffset = bounceOffset
        self.hitInterval = None
        self.kaboomTrack = None
        self.resetRollIval = None
        self.netTimeSentToStartByHit = 0
        self.load()
        self.request('Down')
        return

    def load(self):
        self.root = NodePath('PartyCog-%d' % self.id)
        self.root.reparentTo(self.parentNode)
        path = 'phase_13/models/parties/cogPinata_'
        self.actor = Actor(path + 'actor', {'idle': path + 'idle_anim',
         'down': path + 'down_anim',
         'up': path + 'up_anim',
         'bodyHitBack': path + 'bodyHitBack_anim',
         'bodyHitFront': path + 'bodyHitFront_anim',
         'headHitBack': path + 'headHitBack_anim',
         'headHitFront': path + 'headHitFront_anim'})
        self.actor.reparentTo(self.root)
        self.temp_transform = Mat4()
        self.head_locator = self.actor.attachNewNode('temphead')
        self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75)
        self.bodyColl.setTangible(1)
        self.bodyCollNode = CollisionNode('PartyCog-%d-Body-Collision' % self.id)
        self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.bodyCollNode.addSolid(self.bodyColl)
        self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode)
        self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5)
        self.headColl.setTangible(1)
        self.headCollNode = CollisionNode('PartyCog-%d-Head-Collision' % self.id)
        self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.headCollNode.addSolid(self.headColl)
        self.headCollNodePath = self.root.attachNewNode(self.headCollNode)
        self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0)
        self.arm1Coll.setTangible(1)
        self.arm1CollNode = CollisionNode('PartyCog-%d-Arm1-Collision' % self.id)
        self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.arm1CollNode.addSolid(self.arm1Coll)
        self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode)
        self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0)
        self.arm2Coll.setTangible(1)
        self.arm2CollNode = CollisionNode('PartyCog-%d-Arm2-Collision' % self.id)
        self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask)
        self.arm2CollNode.addSolid(self.arm2Coll)
        self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode)
        splatName = 'splat-creampie'
        self.splat = globalPropPool.getProp(splatName)
        self.splat.setBillboardPointEye()
        self.splatType = globalPropPool.getPropType(splatName)
        self.pieHitSound = globalBattleSoundCache.getSound('AA_wholepie_only.ogg')
        self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.ogg')
        self.hole = loader.loadModel('phase_13/models/parties/cogPinataHole')
        self.hole.setTransparency(True)
        self.hole.setP(-90.0)
        self.hole.setScale(3)
        self.hole.setBin('ground', 3)
        self.hole.reparentTo(self.parentNode)

    def unload(self):
        self.request('Off')
        self.clearHitInterval()
        if self.hole is not None:
            self.hole.removeNode()
            self.hole = None
        if self.actor is not None:
            self.actor.cleanup()
            self.actor.removeNode()
            self.actor = None
        if self.root is not None:
            self.root.removeNode()
            self.root = None
        if self.kaboomTrack is not None and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()
        self.kaboomTrack = None
        if self.resetRollIval is not None and self.resetRollIval.isPlaying():
            self.resetRollIval.finish()
        self.resetRollIval = None
        if self.hitInterval is not None and self.hitInterval.isPlaying():
            self.hitInterval.finish()
        self.hitInterval = None
        del self.upSound
        del self.pieHitSound
        return

    def enterStatic(self):
        pass

    def exitStatic(self):
        pass

    def enterActive(self, startTime):
        self.root.setR(0.0)
        updateTask = Task.Task(self.updateTask)
        updateTask.startTime = startTime
        taskMgr.add(updateTask, 'PartyCog.update-%d' % self.id)

    def exitActive(self):
        taskMgr.remove('PartyCog.update-%d' % self.id)
        taskMgr.remove('PartyCog.bounceTask-%d' % self.id)
        self.clearHitInterval()
        self.resetRollIval = self.root.hprInterval(0.5, Point3(self.root.getH(), 0.0, 0.0), blendType='easeInOut')
        self.resetRollIval.start()
        self.actor.stop()

    def enterDown(self):
        if self.oldState == 'Off':
            downAnimControl = self.actor.getAnimControl('down')
            self.actor.pose('down', downAnimControl.getNumFrames() - 1)
            return
        self.clearHitInterval()
        startScale = self.hole.getScale()
        endScale = Point3(5, 5, 5)
        self.hitInterval = Sequence(LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel(SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'down', loop=0)), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut'))
        self.hitInterval.start()

    def exitDown(self):
        self.root.setR(0.0)
        self.root.setH(0.0)
        self.targetDistance = 0.0
        self.targetFacing = 0.0
        self.currentT = 0.0
        self.setAlongSpline(0.0)
        self.clearHitInterval()
        startScale = self.hole.getScale()
        endScale = Point3(5, 5, 5)
        self.hitInterval = Sequence(LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel(SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'up', loop=0)), Func(self.actor.loop, 'idle'), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut'))
        self.hitInterval.start()

    def filterDown(self, request, args):
        if request == 'Down':
            return None
        else:
            return self.defaultFilter(request, args)
        return None

    def setEndPoints(self, start, end, amplitude = 1.7):
        self.sinAmplitude = amplitude
        self.sinPeriod = (end.getX() - start.getX()) / 2
        self.sinDisplacement = start.getY()
        self.startPoint = start
        self.endPoint = end
        self.currentT = 0.0
        self.targetDistance = 0.0
        self.currentFacing = 0.0
        self.targetFacing = 0.0
        self.setAlongSpline(self.currentT)
        self.hole.setPos(self.root.getPos())
        self.hole.setZ(0.02)

    def rockBackAndForth(self, task):
        t = task.startTime + task.time
        angle = math.sin(t) * 20.0
        self.root.setR(angle)
        return task.cont

    def updateDistance(self, distance):
        self.targetDistance = clamp(distance, -1.0, 1.0)

    def updateTask(self, task):
        self.rockBackAndForth(task)
        if self.targetDistance > self.currentT:
            self.currentT += min(0.01, self.targetDistance - self.currentT)
            self.setAlongSpline(self.currentT)
        elif self.targetDistance < self.currentT:
            self.currentT += max(-0.01, self.targetDistance - self.currentT)
            self.setAlongSpline(self.currentT)
        if self.currentT < 0.0:
            self.targetFacing = -90.0
        elif self.currentT > 0.0:
            self.targetFacing = 90.0
        else:
            self.targetFacing = 0.0
        if self.targetFacing > self.currentFacing:
            self.currentFacing += min(10, self.targetFacing - self.currentFacing)
        elif self.targetFacing < self.currentFacing:
            self.currentFacing += max(-10, self.targetFacing - self.currentFacing)
        self.root.setH(self.currentFacing)
        return task.cont

    def setAlongSpline(self, t):
        t = t + 1.0
        dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0
        x = self.startPoint.getX() + t * dist
        y = self.startPoint.getY() - math.sin(t * 2 * math.pi) * self.sinAmplitude
        self.root.setPos(x, y, 0)

    def startBounce(self):
        taskMgr.add(self.bounce, 'PartyCog.bounceTask-%d' % self.id)

    def bounce(self, task):
        self.root.setZ(math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight + self.heightShift)
        return task.cont

    def setPos(self, position):
        self.root.setPos(position)

    def respondToPieHit(self, timestamp, position, hot = False, direction = 1.0):
        if self.netTimeSentToStartByHit < timestamp:
            self.__showSplat(position, direction, hot)
            if self.netTimeSentToStartByHit < timestamp:
                self.netTimeSentToStartByHit = timestamp
        else:
            self.notify.debug('respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit)

    def clearHitInterval(self):
        if self.hitInterval is not None and self.hitInterval.isPlaying():
            self.hitInterval.clearToInitial()
        return

    def __showSplat(self, position, direction, hot = False):
        if self.kaboomTrack is not None and self.kaboomTrack.isPlaying():
            self.kaboomTrack.finish()
        self.clearHitInterval()
        splatName = 'splat-creampie'
        self.splat = globalPropPool.getProp(splatName)
        self.splat.setBillboardPointEye()
        self.splat.reparentTo(render)
        self.splat.setPos(self.root, position)
        self.splat.setAlphaScale(1.0)
        if not direction == 1.0:
            self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0])
            if self.currentFacing > 0.0:
                facing = 'HitFront'
            else:
                facing = 'HitBack'
        else:
            self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1])
            if self.currentFacing > 0.0:
                facing = 'HitBack'
            else:
                facing = 'HitFront'
        if hot:
            targetscale = 0.75
            part = 'head'
        else:
            targetscale = 0.5
            part = 'body'

        def setSplatAlpha(amount):
            self.splat.setAlphaScale(amount)

        self.hitInterval = Sequence(ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, 'idle'))
        self.hitInterval.start()
        self.kaboomTrack = Parallel(SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence(Func(self.splat.showThrough), Parallel(Sequence(LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Wait(0.175)), Sequence(Wait(0.1), LerpFunc(setSplatAlpha, duration=1.0, fromData=1.0, toData=0.0, blendType='easeOut'))), Func(self.splat.cleanup), Func(self.splat.removeNode)))
        self.kaboomTrack.start()
        return

    def showHitScore(self, number, scale = 1):
        if number <= 0:
            return
        if self.hpText:
            self.hideHitScore()
        self.HpTextGenerator.setFont(ToontownGlobals.getSignFont())
        if number < 0:
            self.HpTextGenerator.setText(str(number))
        else:
            self.HpTextGenerator.setText('+' + str(number))
        self.HpTextGenerator.clearShadow()
        self.HpTextGenerator.setAlign(TextNode.ACenter)
        r = 1
        g = 1
        b = 0
        a = 1
        self.HpTextGenerator.setTextColor(r, g, b, a)
        self.hpTextNode = self.HpTextGenerator.generate()
        self.hpText = render.attachNewNode(self.hpTextNode)
        self.hpText.setScale(scale)
        self.hpText.setBillboardPointEye()
        self.hpText.setBin('fixed', 100)
        self.hpText.setPos(self.root, 0, 0, self.height / 2)
        seq = Sequence(self.hpText.posInterval(0.25, Point3(self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), blendType='easeOut'), Wait(0.25), self.hpText.colorInterval(0.1, Vec4(r, g, b, 0)), Func(self.__hideHitScore))
        seq.start()

    def hideHitScore(self):
        if self.hpText:
            taskMgr.remove('PartyCogHpText' + str(self.id))
            self.hpText.removeNode()
            self.hpText = None
        return

    def getHeadLocation(self):
        self.actor.getJoints(jointName='head')[0].getNetTransform(self.temp_transform)
        self.head_locator.setMat(self.temp_transform)
        return self.head_locator.getZ(self.root)