Example #1
0
class JugglingBalls(ToonUpGag):

    def __init__(self):
        ToonUpGag.__init__(self, CIGlobals.JugglingBalls, 'phase_5/models/props/cubes-mod.bam', 90, 120, 100, GagGlobals.JUGGLE_SFX, 1, anim='phase_5/models/props/cubes-chan.bam')
        self.setImage('phase_3.5/maps/juggling-cubes.png')
        self.track = None
        self.soundInterval = None
        return

    def start(self):
        super(JugglingBalls, self).start()
        self.setupHips()
        self.build()
        self.placeProp(self.hips, self.gag)
        self.soundInterval = self.getSoundTrack(0.7, self.gag, 7.7)
        propInterval = Sequence()
        propInterval.append(ActorInterval(self.gag, 'chan'))
        if self.avatar == base.localAvatar:
            propInterval.append(Func(self.setHealAmount))
            propInterval.append(Func(self.healNearbyAvatars, 25))
        propInterval.append(Func(self.cleanupGag))
        propInterval.append(Func(self.reset))
        self.track = Parallel(ActorInterval(self.avatar, 'juggle'), propInterval, Func(self.soundInterval.start))
        self.track.start()

    def equip(self):
        super(JugglingBalls, self).equip()

    def unEquip(self):
        if self.track:
            self.soundInterval.finish()
            self.track.finish()
            self.track = None
        self.reset()
        return
Example #2
0
  def movementTask( self, task ):
    # show and hide depending on distance to camera
    if (base.camera.getPos( render ) - self.getPos()).length() > 100.0:
      self.pandaActor.hide()
    else:
      self.pandaActor.show()
    
    try:
      # calculate time passed / we cant use task.time in a doMethodLater
      deltaT = time.time() - self.oldTaskTime
      # save current time
      self.oldTaskTime = time.time()
    except:
      # save current time
      self.oldTaskTime = time.time()
      deltaT = 0.0
    
    # get future rotation and position
    rot = self.getRotation( UPDATETIME, random.randint( -10, 10) )
    pos = self.getForwardPos( UPDATETIME * (random.random()/2.0+1.0) )
    posZ = self.getHeight( (pos.getX(), pos.getY()) )
    pos.setZ( posZ )
    
    # create movement and rotation intervals
    myInterval1=self.posInterval(UPDATETIME*1.25,pos)
    myInterval2=self.hprInterval(UPDATETIME*1.25,rot)
#    myInterval1=self.globalPandaNode.posInterval(UPDATETIME*1.25,pos)
#    myInterval2=self.globalPandaNode.hprInterval(UPDATETIME*1.25,rot)
    myParallel=Parallel(myInterval1,myInterval2) 
    myParallel.start()
    
    return Task.again
    def getSwapVisibleIval(self, wait = 5.0, tFadeOut = 3.0, tFadeIn = 3.0):
        loader = base.cr.playGame.hood.loader
        npl = render.findAllMatches('**/=DNARoot=holiday_prop;+s')
        p = Parallel()
        for i in range(npl.getNumPaths()):
            np = npl.getPath(i)
            np.setTransparency(TransparencyAttrib.MDual, 1)
            if not np.hasTag('DNACode'):
                continue
            dnaCode = np.getTag('DNACode')
            dnaNode = self.dnaStore.findNode(dnaCode)
            if dnaNode.isEmpty():
                continue
            newNP = dnaNode.copyTo(np.getParent())
            newNP.setTag('DNARoot', 'holiday_prop')
            newNP.setTag('DNACode', dnaCode)
            newNP.setColorScale(1, 1, 1, 0)
            newNP.setTransparency(TransparencyAttrib.MDual, 1)
            if np.hasTag('transformIndex'):
                index = int(np.getTag('transformIndex'))
                transform = loader.holidayPropTransforms.get(index, TransformState.makeIdentity())
                newNP.setTransform(NodePath(), transform)
                newNP.setTag('transformIndex', `index`)
            s = Sequence(Wait(wait), np.colorScaleInterval(tFadeOut, Vec4(1, 1, 1, 0), startColorScale=Vec4(1, 1, 1, 1), blendType='easeInOut'), Func(np.detachNode), Func(np.clearTransparency), newNP.colorScaleInterval(tFadeOut, Vec4(1, 1, 1, 1), startColorScale=Vec4(1, 1, 1, 0), blendType='easeInOut'), Func(newNP.clearTransparency), Func(newNP.clearColorScale))
            p.append(s)

        return p
Example #4
0
 def doSpray(self, scaleUp, scaleDown, hold):
     base.audio3d.attachSoundToObject(self.spraySfx, self.gag)
     self.spraySfx.play()
     spraySequence = Sequence(Func(self.getSprayTrack(self.origin, self.sprayRange, scaleUp, hold, scaleDown).start))
     sprayParallel = Parallel()
     sprayParallel.append(Func(spraySequence.start))
     sprayParallel.start()
    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()
Example #6
0
 def activeAnim(self):
     self.cam_anim_enter = Parallel(name="cam gates enter")
     self.cam_anim_enter.append(camera.posInterval(1,Point3(0,-29,25)))
     self.cam_anim_enter.append(self.gates.posInterval(1,Point3(0,9,0)))
     self.cam_anim_exit = Parallel(name="cam gates exit")
     self.cam_anim_exit.append(camera.posInterval(1,Point3(0,-34,25)))
     self.cam_anim_exit.append(self.gates.posInterval(1,Point3(0,14,0)))
    def toggle(self):
        self.visible = not self.visible

        self.debug("Toggle buffer viewer")

        if self.currentGUIEffect is not None:
            self.currentGUIEffect.finish()

        if not self.visible:

            self.currentGUIEffect = Sequence(
                self.parent.colorScaleInterval(
                    0.12, Vec4(1, 1, 1, 0),
                    blendType="easeIn"),
                Func(self.parent.hide)

            )
            self.currentGUIEffect.start()

        else:
            self.renderBuffers()
            self.parent.show()
            self.currentGUIEffect = Parallel(
                self.parent.colorScaleInterval(
                    0.12, Vec4(1, 1, 1, 1),
                    blendType="easeIn"),
            )
            self.currentGUIEffect.start()
    def _toggleGUI(self):
        self.debug("Toggle overlay")

        if self.currentGUIEffect is not None:
            self.currentGUIEffect.finish()

        if not self.guiActive:
            self.currentGUIEffect = Parallel(
                self.watermark.posInterval(
                    0.4, self.watermark.getInitialPos() + Vec3(0, 0, 200), blendType="easeIn"),
                self.showDebugger.posInterval(
                    0.4, self.showDebugger.getInitialPos() + Vec3(0, 0, 400), blendType="easeIn"),
                self.debuggerParent.posInterval(
                    0.3, Vec3(0, 0, 0), blendType="easeOut"),
            )
            self.currentGUIEffect.start()

        else:
            self.currentGUIEffect = Parallel(
                self.watermark.posInterval(
                    0.4, self.watermark.getInitialPos(), blendType="easeOut"),
                self.showDebugger.posInterval(
                    0.4, self.showDebugger.getInitialPos(), blendType="easeOut"),
                self.debuggerParent.posInterval(
                    0.3, Vec3(-350, 0, 0), blendType="easeInOut"),
            )
            self.currentGUIEffect.start()

        self.guiActive = not self.guiActive
Example #9
0
    def getScaleBlendIntervals(self, props, duration, startScale, endScale, blendType):
        tracks = Parallel()
        if not isinstance(props, list):
            props = [props]
        for prop in props:
            tracks.append(LerpScaleInterval(prop, duration, endScale, startScale=startScale, blendType=blendType))

        return tracks
Example #10
0
    def getScaleTrack(self, props, duration, startScale, endScale):
        track = Parallel()
        if not isinstance(props, list):
            props = [props]
        for prop in props:
            track.append(LerpScaleInterval(prop, duration, endScale, startScale=startScale))

        return track
Example #11
0
	def showPath(self, fr, to):
		path = set()
		showSquareSequences = Parallel()
		if self.pieces[fr]:
			path.update(self.pieces[fr].path(to))
		for sq in path:
			showSquareSequences.append(self.showSquare(sq))
		return showSquareSequences
Example #12
0
 def AnimateIn(self, blade):
     x, y, z = blade.getPos()
     ending_position = (self.originals[blade])
     position1 = blade.posInterval(1, ending_position, (x, y, z))
     rotate1 = blade.hprInterval(1, (0, 0, 0), blade.getHpr())
     scale1 = blade.scaleInterval(1, (1, 1, 1), blade.getScale())
     move = Parallel(position1, rotate1, scale1, name="move")
     move.start()
     blade.setTag('state', 'in')
Example #13
0
 def AnimateOut(self, blade):
     x, y, z = blade.getPos()
     self.originals[blade] = (x, y, z)
     ending_position = (40 + random.uniform(0,120), y-(random.uniform(20,100)), z + random.uniform(-10,50))
     position1 = blade.posInterval(1, ending_position, (x, y, z))
     rotate1 = blade.hprInterval(1, (90, 0, 0), blade.getHpr())
     scale1 = blade.scaleInterval(1, (2, 2, 2), blade.getScale())
     move = Parallel(position1, rotate1, scale1, name="move")
     move.start()
     blade.setTag('state', 'out')
Example #14
0
    def start(self):
        SoundGag.start(self)
        tracks = Parallel()
        delay = 2.45
        INSTRUMENT_SCALE_MODIFIER = 0.5
        instrMin = Vec3(0.001, 0.001, 0.001)
        instrMax1 = Vec3(1.7, 1.7, 1.7)
        instrMax1 *= INSTRUMENT_SCALE_MODIFIER
        instrMax2 = Vec3(2.2, 2.2, 2.2)
        instrMax2 *= INSTRUMENT_SCALE_MODIFIER
        instrStretch = Vec3(0.4, 0.4, 0.4)
        instrStretch *= INSTRUMENT_SCALE_MODIFIER
        head = self.gag.find('**/opera_singer')
        head.setPos(0, 0, 0)

        def setInstrumentStats():
            newPos = Vec3(-0.8, -0.9, 0.2)
            newPos *= 1.3
            self.gag.setPos(newPos[0], newPos[1], newPos[2])
            self.gag.setHpr(145, 0, 90)
            self.gag.setScale(instrMin)

        megaphoneShow = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats))
        grow1 = self.getScaleBlendIntervals(self.gag, duration=1, startScale=instrMin, endScale=instrMax1, blendType='easeOut')
        grow2 = self.getScaleBlendIntervals(self.gag, duration=1.1, startScale=instrMax1, endScale=instrMax2, blendType='easeIn')
        shrink2 = self.getScaleIntervals(self.gag, duration=0.1, startScale=instrMax2, endScale=instrMin)
        instrumentAppear = Parallel(Sequence(grow1, grow2, Wait(6.0), shrink2, Wait(0.4), Func(self.finish)), SoundInterval(self.appearSfx, node=self.avatar))
        delayTime = delay
        megaphoneTrack = Sequence(megaphoneShow, Wait(delayTime + 1.0), instrumentAppear)
        tracks.append(megaphoneTrack)
        toonTrack = self.__createToonInterval(0)
        tracks.append(toonTrack)
        soundTrack = Sequence(Wait(delayTime), Parallel(SoundInterval(self.soundSfx, node=self.avatar), Func(self.damageCogsNearby)))
        tracks.append(soundTrack)
        tracks.start()
Example #15
0
 def append(self,text,width,height,spacing = 0, fadein = 0, fadeinType = 0):
     '''Add a NodePath that contains a generated text geom
     This method is called by SogalText
     '''
     self.__lock.acquire()
     
     self.items.append(text)
     text.reparentTo(self)
     textPos = self.currentPtr
     text.setPos(textPos)
     if fadein:
         interval = Parallel()
         if fadeinType == 0 or fadeinType == 'normal':
             interval.append(LerpFunc(_modifyAlphaScale,fadein,0,1,blendType = 'easeOut',extraArgs = [text]))
         if fadeinType == 1 or fadeinType == 'flyin':
             interval.append(LerpFunc(_modifyAlphaScale,fadein,0,1,blendType = 'easeOut',extraArgs = [text]))
             interval.append(LerpPosInterval(text,fadein,
                                             self.currentPtr,
                                             (self.currentPtr[0],self.currentPtr[1],self.currentPtr[2] -0.3),
                                             blendType = 'easeOut'))            
         interval.start()
         self.__lerpIntervals.append(interval)
         
     self.lineWidth = self.currentPtr[0] + width
     self.lineHeight = max(height, self.lineHeight)
     self.currentPtr = (self.lineWidth + spacing, 0, 0)
     
     self.__lock.release()
    def construct(self):
        track = Sequence()

        # First, set the avatar's initial rotational components:
        track.append(Func(self.avatar.setQuat, self.quatA))

        # Next, construct the rotate track:
        rotateTrack = Parallel()
        if self.animName is not None:
            rotateTrack.append(
                Func(self.avatar.setPlayRate, self.animPlayRate, self.animName)
            )
            rotateTrack.append(Func(self.avatar.loop, self.animName))
        if self.sfx is not None:
            rotateTrack.append(
                Func(base.playSfx, self.sfx, looping=1, node=self.avatar)
            )
        rotateTrack.append(self.getQuatInterval())
        track.append(rotateTrack)

        # Finally, clean up what is necessary:
        if self.animName is not None:
            track.append(Func(self.avatar.setPlayRate, 1, self.animName))
        if self.sfx is not None:
            track.append(Func(self.sfx.stop))

        return track
Example #17
0
    def start(self):
        SoundGag.start(self)
        tracks = Parallel()
        delayTime = 2.45
        delayUntilAppearSound = 1.0
        INSTRUMENT_SCALE_MODIFIER = 0.5
        instrMin = Vec3(0.001, 0.001, 0.001)
        instrMax1 = Vec3(0.1, 0.1, 0.1)
        instrMax1 *= INSTRUMENT_SCALE_MODIFIER
        instrMax2 = Vec3(0.3, 0.3, 0.3)
        instrMax2 *= INSTRUMENT_SCALE_MODIFIER
        instrStretch = Vec3(0.4, 0.4, 0.4)
        instrStretch *= INSTRUMENT_SCALE_MODIFIER

        def setInstrumentStats():
            self.gag.setPos(-0.8, -0.9, 0.2)
            self.gag.setHpr(145, 0, 0)
            self.gag.setScale(instrMin)

        megaphoneSh = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats))
        grow = self.getScaleIntervals(self.gag, duration=1, startScale=instrMin, endScale=instrMax1)
        instrumentAppear = Parallel(grow)
        stretchInstr = self.getScaleBlendIntervals(self.gag, duration=0.3, startScale=instrMax2, endScale=instrStretch, blendType='easeOut')
        backInstr = self.getScaleBlendIntervals(self.gag, duration=1.0, startScale=instrStretch, endScale=instrMin, blendType='easeIn')
        spinInstr = LerpHprInterval(self.gag, duration=1.5, startHpr=Vec3(145, 0, 0), hpr=Vec3(145, 0, 90), blendType='easeInOut')
        attackTrack = Parallel(Sequence(Wait(0.2), spinInstr), Sequence(stretchInstr, Wait(0.5), backInstr))
        megaphoneTrack = Sequence(megaphoneSh, Wait(delayUntilAppearSound), SoundInterval(self.appearSfx, node=self.avatar), Wait(delayTime + 1.0), instrumentAppear)
        tracks.append(megaphoneTrack)
        tracks.append(ActorInterval(self.avatar, 'sound'))
        soundTrack = Sequence(Wait(delayTime), Parallel(attackTrack, SoundInterval(self.soundSfx, node=self.avatar), Func(self.damageCogsNearby), Wait(0.4), Func(self.finish)))
        tracks.append(soundTrack)
        tracks.start()
 def handleMatch(self, cardA, cardB, withBonus):
     self.notify.debug('we got a match %d %d' % (cardA, cardB))
     self.matches += 1
     if cardA in self.faceUpList:
         self.faceUpList.remove(cardA)
     
     if cardB in self.faceUpList:
         self.faceUpList.remove(cardB)
     
     self.inactiveList.append(cardA)
     self.inactiveList.append(cardB)
     matchIval = Parallel()
     for card in [
         cardA,
         cardB]:
         self.cards[card].setTransparency(1)
         cardSeq = Sequence(LerpColorScaleInterval(self.cards[card], duration = 1, colorScale = Vec4(1.0, 1.0, 1.0, 0.0)), Func(self.cards[card].hide))
         matchIval.append(cardSeq)
     
     if withBonus:
         matchIval.append(SoundInterval(self.matchWithBonusSfx, node = self.cards[card], listenerNode = base.localAvatar, cutOff = 240))
     else:
         matchIval.append(SoundInterval(self.matchSfx, node = self.cards[card], listenerNode = base.localAvatar, cutOff = 240))
     matchIval.start()
     if len(self.inactiveList) == len(self.cards):
         self.sendUpdate('reportDone')
Example #19
0
    def start(self):
        SoundGag.start(self)
        INSTRUMENT_SCALE_MODIFIER = 0.5
        delayTime = 2.45
        delayUntilAppearSound = 1.0
        tracks = Parallel()
        instrMin = Vec3(0.001, 0.001, 0.001)
        instrMax = Vec3(0.2, 0.2, 0.2)
        instrMax *= INSTRUMENT_SCALE_MODIFIER
        instrStretch = Vec3(0.25, 0.25, 0.25)
        instrStretch *= INSTRUMENT_SCALE_MODIFIER

        def setInstrumentStats():
            self.gag.setPos(-1.2, -1.3, 0.1)
            self.gag.setHpr(145, 0, 85)
            self.gag.setScale(instrMin)

        megaphoneShow = Sequence(Func(self.placeProp, self.handJoint, self.megaphone), Func(self.placeProp, self.handJoint, self.gag), Func(setInstrumentStats))
        grow = self.getScaleIntervals(self.gag, duration=0.2, startScale=instrMin, endScale=instrMax)
        instrumentAppear = grow
        stretchInstr = self.getScaleBlendIntervals(self.gag, duration=0.2, startScale=instrMax, endScale=instrStretch, blendType='easeOut')
        backInstr = self.getScaleBlendIntervals(self.gag, duration=0.2, startScale=instrStretch, endScale=instrMax, blendType='easeIn')
        attackTrack = Sequence(stretchInstr, backInstr)
        megaphoneTrack = Sequence(megaphoneShow, Wait(delayUntilAppearSound), SoundInterval(self.appearSfx, node=self.avatar), instrumentAppear)
        tracks.append(megaphoneTrack)
        tracks.append(ActorInterval(self.avatar, 'sound'))
        instrumentshrink = self.getScaleIntervals(self.gag, duration=0.1, startScale=instrMax, endScale=instrMin)
        soundTrack = Sequence(Wait(delayTime), Parallel(attackTrack, SoundInterval(self.soundSfx, node=self.avatar), Wait(0.2), instrumentshrink, Func(self.damageCogsNearby), Wait(0.4), Func(self.finish)))
        tracks.append(soundTrack)
        tracks.start()
Example #20
0
    def startEntity(self, cog):
        if not cog:
            self.completeSquirt()
            return
        scaleUpPoint = Point3(1.5, 1.5, 1.5)
        rainDelay = 1
        effectDelay = 0.3
        cloudHold = 4.7
        tContact = 2.4
        if cog.isDead():
            cloudHold = 1.7
        cloud01, trickleFx, rainEffects, entity = self.buildEntity()
        cloud01.setZ(cog.suitPlan.getNametagZ() + 2)
        cloud01.reparentTo(cog)
        cloud02 = Actor(self.model, {'chan': GagGlobals.getProp(4, 'stormcloud-chan')})
        cloud02.reparentTo(cloud01)

        def damageCog():
            if self.isLocal():
                self.avatar.sendUpdate('suitHitByPie', [cog.doId, self.getID()])

        def __getCloudTrack(cloud, useEffect = 1):
            track = Sequence(Func(cloud.pose, 'chan', 0), LerpScaleInterval(cloud, 1.5, scaleUpPoint, startScale=GagGlobals.PNT3NEAR0), Wait(rainDelay))
            if useEffect == 1:
                pTrack = Parallel()
                delay = trickleDuration = cloudHold * 0.25
                trickleTrack = ParticleInterval(trickleFx, cloud, worldRelative=0, duration=trickleDuration, cleanup=True)
                track.append(trickleTrack)
                for i in range(0, 3):
                    dur = cloudHold - 2 * trickleDuration
                    pTrack.append(Sequence(Wait(delay), ParticleInterval(rainEffects[i], cloud, worldRelative=0, duration=dur, cleanup=True)))
                    delay += effectDelay

                pTrack.append(Sequence(Wait(3 * effectDelay), ActorInterval(cloud, 'chan', startTime=1, duration=cloudHold)))
                damageTrack = Sequence()
                if cog.getHealth() - self.getDamage() <= 0:
                    damageTrack.append(Func(cog.d_disableMovement, wantRay=True))
                    damageTrack.append(Func(damageCog))
                else:
                    damageTrack.append(Wait(tContact))
                    damageTrack.append(Func(damageCog))
                pTrack.append(damageTrack)
                track.append(pTrack)
            else:
                track.append(ActorInterval(cloud, 'chan', startTime=1, duration=cloudHold))
            track.append(LerpScaleInterval(cloud, 0.5, GagGlobals.PNT3NEAR0))
            track.append(Func(GagUtils.destroyProp, cloud))
            return track

        tracks = Parallel()
        soundTrack01 = self.getSoundTrack(1.3, self.avatar)
        soundTrack02 = self.getSoundTrack(3.4, self.avatar)
        tracks.append(soundTrack01)
        tracks.append(soundTrack02)
        cloud01Track = __getCloudTrack(cloud01)
        cloud02Track = __getCloudTrack(cloud02, useEffect=0)
        tracks.append(cloud01Track)
        tracks.append(cloud02Track)
        tracks.append(Func(self.destroyEntity, entity))
        tracks.start()
Example #21
0
    def __tickNearbyCogs(self):
        self.__selectNearbyCogs()
        tickTrack = Parallel()
        tickDuration = 0.4
        for cog in self.selectedCogs:
            if not cog.isDead():
                base.audio3d.attachSoundToObject(self.tickSfx, cog)
                tickTrack.append(Parallel(Sequence(LerpColorScaleInterval(cog, tickDuration, VBase4(1, 0, 0, 1)), Func(cog.clearColorScale), Func(cog.d_disableMovement)), SoundInterval(self.tickSfx, duration=tickDuration)))
            else:
                self.selectedCogs.remove(cog)

        return tickTrack
Example #22
0
class Megaphone(ToonUpGag):

    def __init__(self):
        ToonUpGag.__init__(self, CIGlobals.Megaphone, 'phase_5/models/props/megaphone.bam', 10, 20, 100, GagGlobals.TELLJOKE_SFX, 1)
        self.setImage('phase_3.5/maps/megaphone.png')
        self.track = None
        self.soundInterval = None
        return

    def start(self):
        super(Megaphone, self).start()
        if not self.gag:
            self.build()
        if self.avatar == base.localAvatar:
            question, answer = random.choice(CIGlobals.ToonHealJokes)
        self.setupHandJoints()
        self.placeProp(self.handJoint, self.gag)
        self.soundInterval = self.getSoundTrack(self.avatar.getDuration('shout', fromFrame=0, toFrame=18), self.gag, 5.5)
        propInterval = Sequence()
        propInterval.append(Wait(self.avatar.getDuration('shout', fromFrame=0, toFrame=25)))
        if self.avatar == base.localAvatar:
            propInterval.append(Func(base.localAvatar.b_setChat, question))
        propInterval.append(Wait(self.avatar.getDuration('shout', fromFrame=26, toFrame=75)))
        if self.avatar == base.localAvatar:
            propInterval.append(Func(base.localAvatar.b_setChat, answer))
        propInterval.append(Wait(self.avatar.getDuration('shout', fromFrame=76, toFrame=118)))
        if self.avatar == base.localAvatar:
            propInterval.append(Func(self.setHealAmount))
            propInterval.append(Func(self.healNearbyAvatars, 20))
        propInterval.append(Wait(self.avatar.getDuration('shout', fromFrame=118)))
        propInterval.append(Func(self.cleanupGag))
        propInterval.append(Func(self.reset))
        self.track = Parallel(propInterval, ActorInterval(self.avatar, 'shout'), self.soundInterval)
        self.track.start()

    def equip(self):
        super(Megaphone, self).equip()
        self.build()

    def unEquip(self):
        if self.track:
            self.track.finish()
            self.track = None
            self.soundInterval = None
        self.cleanupGag()
        self.reset()
        return

    def cleanupGag(self):
        if self.gag:
            self.gag.removeNode()
            self.gag = None
        return
Example #23
0
	def showPathIfVisible(self, fr, to):
		if self.pieces[fr]:
			path = set()
			showSquareSequences = Parallel()
			if self.pieces[fr]:
				path.update(self.pieces[fr].path(to))
			if any(self.isVisible(sq) for sq in path):
				for sq in path:
					showSquareSequences.append(self.showSquare(sq))
			return showSquareSequences
		else:
			return Parallel()
    def showSuitsFalling(self, suits, ts, name, callback):
        if self.bossCog is None:
            return
        suitTrack = Parallel()
        delay = 0
        for suit in suits:
            suit.setState('Battle')
            if suit.dna.dept == 'l':
                suit.reparentTo(self.bossCog)
                suit.setPos(0, 0, 0)
            if suit in self.joiningSuits:
                i = len(self.pendingSuits) + self.joiningSuits.index(suit)
                destPos, h = self.suitPendingPoints[i]
                destHpr = VBase3(h, 0, 0)
            else:
                destPos, destHpr = self.getActorPosHpr(suit, self.suits)
            startPos = destPos + Point3(0, 0, SuitTimings.fromSky *
                                        ToontownGlobals.SuitWalkSpeed)
            self.notify.debug('startPos for %s = %s' % (suit, startPos))
            suit.reparentTo(self)
            suit.setPos(startPos)
            suit.headsUp(self)
            moveIval = Sequence()
            chairInfo = self.bossCog.claimOneChair()
            if chairInfo:
                moveIval = self.createDinerMoveIval(suit, destPos, chairInfo)
            suitTrack.append(
                Track(
                    (delay,
                     Sequence(
                         moveIval,
                         Func(
                             suit.loop,
                             'neutral')))))
            delay += 1

        if self.hasLocalToon():
            camera.reparentTo(self)
            self.notify.debug('self.battleSide =%s' % self.battleSide)
            camHeading = -20
            camX = -4
            if self.battleSide == 0:
                camHeading = 20
                camX = 4
            camera.setPosHpr(camX, -15, 7, camHeading, 0, 0)
        done = Func(callback)
        track = Sequence(suitTrack, done, name=name)
        track.start(ts)
        self.storeInterval(track, name)
        return
class CogdoMazeSplattable:
    def __init__(self, object, name, collisionRadius):
        self.object = object
        self.splat = CogdoUtil.loadMazeModel('splash')
        self.splat.setBillboardPointEye()
        self.splat.setBin('fixed', 40)
        self.splat.setDepthTest(False)
        self.splat.setDepthWrite(False)
        self.splatTrack = None
        self._splatSfxIval = base.cogdoGameAudioMgr.createSfxIval('splat')
        self.initGagCollision(name, collisionRadius)
        return

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

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

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

    def doSplat(self):
        if self.splatTrack and self.splatTrack.isPlaying():
            self.splatTrack.finish()
        self.splat.reparentTo(render)
        self.splat.setPos(self.object, 0, 0, 3.0)
        self.splat.setY(self.splat.getY() - 1.0)
        self._splatSfxIval.node = self.splat
        self.splatTrack = Parallel(
            self._splatSfxIval,
            Sequence(
                Func(self.splat.showThrough),
                LerpScaleInterval(
                    self.splat,
                    duration=0.5,
                    scale=6,
                    startScale=1,
                    blendType='easeOut'), Func(self.splat.hide)))
        self.splatTrack.start()
    def showToonThrowingGag(self, heading, pos):
        gag = self.equippedGag
        if gag is None:
            return
        self.removeGag()
        tossTrack, flyTrack, object = self.getThrowInterval(gag, pos[0], pos[1], pos[2], heading, 0, 0)

        def matchRunningAnim(toon = self.toon):
            toon.playingAnim = None
            toon.setSpeed(toon.forwardSpeed, toon.rotateSpeed)

        newTossTrack = Sequence(tossTrack, Func(matchRunningAnim))
        throwTrack = Parallel(newTossTrack, flyTrack)
        throwTrack.start(0)
        return object
 def exitAnim(self):
     if len(self.gameObject.postAnimationList) > 0:
         self.animSeq = Parallel(*self.gameObject.postAnimationList)
         self.animSeq.start()
     
     self.gameObject.animationList = []
     self.gameObject.postAnimationList = []
    def startConclusion(self):
        DistributedPartyCatchActivity.notify.debug('startConclusion')
        for avId in self.toonIds:
            if self.toonSDs.has_key(avId):
                toonSD = self.toonSDs[avId]
                toonSD.fsm.request('notPlaying')

        self.destroyCatchCollisions()
        if base.localAvatar.doId not in self.toonIds:
            return
        else:
            self.localToonExiting()
        if self.fruitsCaught >= self.numFruits:
            finishText = TTLocalizer.PartyCatchActivityFinishPerfect
        else:
            finishText = TTLocalizer.PartyCatchActivityFinish
        perfectTextSubnode = hidden.attachNewNode(self.__genText(finishText))
        perfectText = hidden.attachNewNode('perfectText')
        perfectTextSubnode.reparentTo(perfectText)
        frame = self.__textGen.getCardActual()
        offsetY = -abs(frame[2] + frame[3]) / 2.0
        perfectTextSubnode.setPos(0, 0, offsetY)
        perfectText.setColor(1, 0.1, 0.1, 1)

        def fadeFunc(t, text = perfectText):
            text.setColorScale(1, 1, 1, t)

        def destroyText(text = perfectText):
            text.removeNode()

        textTrack = Sequence(Func(perfectText.reparentTo, aspect2d), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5))
        soundTrack = SoundInterval(self.sndPerfect)
        self.finishIval = Parallel(textTrack, soundTrack)
        self.finishIval.start()
Example #29
0
 def doAttack(self, ts = 0):
     self.loadAttack()
     if hasattr(self.suit, 'uniqueName'):
         name = self.suit.uniqueName('doHangupAttack')
     else:
         name = 'doHangupAttack'
     if self.suit.type == 'A':
         delay2playSound = 1.0
         delayAfterSoundToPlaceDownReceiver = 0.2
         delayAfterShootToIgnoreCollisions = 1.0
         delay2PickUpReceiver = 1.0
         receiverInHandPos = Point3(-0.5, 0.5, -1)
     elif self.suit.type == 'B':
         delay2playSound = 1.5
         delayAfterSoundToPlaceDownReceiver = 0.7
         delayAfterShootToIgnoreCollisions = 1.0
         delay2PickUpReceiver = 1.5
         receiverInHandPos = Point3(-0.3, 0.5, -0.8)
     elif self.suit.type == 'C':
         delay2playSound = 1.0
         delayAfterSoundToPlaceDownReceiver = 1.15
         delayAfterShootToIgnoreCollisions = 1.0
         delay2PickUpReceiver = 1.5
         receiverInHandPos = Point3(-0.3, 0.5, -0.8)
     self.suitTrack = Parallel(name=name)
     self.suitTrack.append(ActorInterval(self.suit, 'phone'))
     self.suitTrack.append(Sequence(Wait(delay2playSound), SoundInterval(self.phoneSfx, duration=2.1), Wait(delayAfterSoundToPlaceDownReceiver), Func(self.receiver.setPos, 0, 0, 0), Func(self.receiver.setH, 0.0), Func(self.receiver.reparentTo, self.phone), Func(self.acceptOnce, 'enter' + self.collNP.node().getName(), self.handleCollision), Func(self.shootOut), Parallel(SoundInterval(self.hangupSfx), Sequence(Wait(delayAfterShootToIgnoreCollisions), Func(self.ignore, 'enter' + self.collNP.node().getName())))))
     self.suitTrack.append(Sequence(Func(self.phone.reparentTo, self.suit.find('**/joint_Lhold')), Func(self.cord.reparentTo, render), Wait(delay2PickUpReceiver), Func(self.receiver.reparentTo, self.suit.find('**/joint_Rhold')), Func(self.receiver.setPos, receiverInHandPos), Func(self.receiver.setH, 270.0)))
     self.suitTrack.setDoneEvent(self.suitTrack.getName())
     self.acceptOnce(self.suitTrack.getDoneEvent(), self.finishedAttack)
     self.suitTrack.delayDelete = DelayDelete.DelayDelete(self.suit, name)
     self.suitTrack.start(ts)
 def __updateRewardCountdown(self, task):
     curTime = self.getCurrentGameTime()
     if self.clockStopTime is not None:
         if self.clockStopTime < curTime:
             self.notify.debug('self.clockStopTime < curTime %s %s' % (self.clockStopTime, curTime))
             self.__killRewardCountdown()
             curTime = self.clockStopTime
     if curTime > CTGG.GameTime:
         curTime = CTGG.GameTime
     score = int(self.scoreMult * CTGG.calcScore(curTime) + 0.5)
     if not hasattr(task, 'curScore'):
         task.curScore = score
     result = Task.cont
     if hasattr(self, 'rewardPanel'):
         self.rewardPanel['text'] = str(score)
         if task.curScore != score:
             if hasattr(self, 'jarIval'):
                 self.jarIval.finish()
             s = self.rewardPanel.getScale()
             self.jarIval = Parallel(Sequence(self.rewardPanel.scaleInterval(0.15, s * 3.0 / 4.0, blendType='easeOut'), self.rewardPanel.scaleInterval(0.15, s, blendType='easeIn')), SoundInterval(self.sndRewardTick), name='cogThiefGameRewardJarThrob')
             self.jarIval.start()
         task.curScore = score
     else:
         result = Task.done
     return result
Example #31
0
class CogThief(DirectObject):
    """This represents a single cog thief in the cog thief game"""
    notify = directNotify.newCategory("CogThief")
    DefaultSpeedWalkAnim = 4.
    CollisionRadius = 1.25
    MaxFriendsVisible = 4
    Infinity = 100000.0  # just a really big number
    SeparationDistance = 6.0
    MinUrgency = 0.5
    MaxUrgency = 0.75

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

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

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

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

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

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

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

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

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

        self.initCollisions()
        self.startWalkAnim()

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

        self.shutdownCollisions()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            self.suit.setPos(myPos)

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

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

        self.lastThinkTime = globalClock.getFrameTime()

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

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

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

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

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

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

        self.lastThinkTime = globalClock.getFrameTime()

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

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

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

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

        self.lastThinkTime = globalClock.getFrameTime()

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

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

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

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

        self.barrel = CTGG.NoBarrelCarried

        #
        #self.suit.setPos(cogPos)

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

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

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

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

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

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

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

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

        self.seeFriends()

        acc = Vec3(0, 0, 0)

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

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

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

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

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

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

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

        # now add in the acceleration

        self.velocity += acc

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

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

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

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

        return diff

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

        accumulator += valueToAdd

        return accumulator.length()

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

        self.clearVisibleList()

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

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

        return self.numFlockmatesSeen

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

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

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

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

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

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

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

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

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

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

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

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

        return change

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

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

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

        self.kaboomTrack = Parallel(
            SoundInterval(self.pieHitSound, volume=1.0),
            Sequence(
                Func(self.splat.showThrough),
                LerpScaleInterval(self.splat,
                                  duration=0.5,
                                  scale=1.75,
                                  startScale=Point3(0.1, 0.1, 0.1),
                                  blendType='easeOut'),
                Func(self.splat.hide),
            ))
        self.kaboomTrack.start()
    def run(self):

        boss = base.bspLoader.getPyEntityByTargetName("groom_boss_suit")
        boss.show()
        boss.cleanupPropeller()
        boss.animFSM.request('neutral')
        camera.reparentTo(boss)

        onBtn = base.bspLoader.getPyEntityByTargetName("powerovrd_on_button")

        # press animation (fingerwag): 1-31 32-1

        buttonPos = (-1105 / 16.0, 2683 / 16.0, 76 / 16.0)
        camBtnPosHpr = (-1027 / 16.0, 2638 / 16.0, 96 / 16.0, 135 - 90, 30, 0)
        camBtnPosHpr2 = (-1009 / 16.0, 2764 / 16.0, 169 / 16.0, 232 - 90, 0, 0)

        def __pingpongboss_speak():
            boss.pingpong("speak", fromFrame=95, toFrame=100)

        def __boss_pressseq():
            return Sequence(
                ActorInterval(boss, "fingerwag", startFrame=1, endFrame=31),
                Func(onBtn.d_requestPress),
                ActorInterval(boss, "fingerwag", startFrame=32, endFrame=1))

        def __localavplay_duck():
            base.localAvatar.setAnimState('off')
            base.localAvatar.play("duck", fromFrame=19)

        numGoons = 6

        goonWakeup = Parallel()
        for i in xrange(numGoons):
            delay = random.uniform(0.0, 0.5)
            goon = base.bspLoader.getPyEntityByTargetName(
                "groom_goon_{0}".format(i))
            goonWakeup.append(Sequence(Wait(delay), Func(goon.wakeup)))

        bdoor = base.bspLoader.getPyEntityByTargetName("to_groom_botdoor")
        tdoor = base.bspLoader.getPyEntityByTargetName("to_groom_topdoor")

        oldHpr = boss.getHpr(render)

        bossTrack = Parallel(
            Sequence(
                Wait(10.0),
                Func(boss.setHpr, oldHpr),
                ActorInterval(boss,
                              "speak",
                              startFrame=55,
                              endFrame=105,
                              playRate=1.5),
                #Func(__pingpongboss_speak),
                Wait(2.0),
                Func(boss.loop, "neutral")),
            Sequence(
                Func(boss.play, "speak"),
                Func(boss.setChat,
                     "What's this?! How did a Toon get down here?"), Wait(2.5),
                Func(
                    boss.setChat,
                    "The only place you'll be going is back to the playground."
                ), Func(boss.loop, "walk"), Func(boss.headsUp, *buttonPos),
                LerpPosInterval(boss, 2.5, buttonPos), __boss_pressseq(),
                Wait(2.5), Func(boss.setChat, "Goons, ATTACK!!!")))
        camTrack = Sequence(
            Func(camera.setPos, 2.5, 14, 7), Func(camera.lookAt, boss, 0, 0,
                                                  4), Wait(2.5),
            Func(camera.reparentTo, render),
            Func(camera.setPosHpr, *camBtnPosHpr), Wait(2.0),
            Func(camera.setPosHpr, *camBtnPosHpr2), Wait(0.5), Wait(3.0),
            Func(camera.setPosHpr, 4.351, 126.686, 5.5, -154.16, 16.11, 0),
            Wait(0.3), Func(bdoor.request, 'Closing'),
            Func(tdoor.request, 'Closing'), Func(__localavplay_duck),
            Wait(0.9), Func(base.doCamShake, 0.5, 0.35), Wait(0.9),
            Func(camera.reparentTo, boss), Func(camera.setPos, 2.5, 17, 7),
            Func(camera.lookAt, boss, 0, 0, 4),
            LerpPosHprInterval(camera,
                               duration=0.75,
                               blendType='easeOut',
                               pos=(1, 5, 4),
                               hpr=(165, 20, 0)), Wait(1.75),
            Func(camera.reparentTo, render),
            Func(camera.setPosHpr, 88 / 16.0, 2746 / 16.0, 127 / 16.0, 71 - 90,
                 -10, 0))
        goonTrack = Sequence(Wait(12.6), goonWakeup)

        self.ival = Parallel(camTrack, bossTrack, goonTrack)
        self.ival.start()
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.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.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.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.__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.75 - spacing * (self.numPlayers - 1 - i), 0.0, 0.875)
            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 = -.05
        lX = -.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 __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)
        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()

    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)
Example #34
0
    def loadNewBoard(self):
        self.progressLabel.stash()
        self.progressDescriptionLabel.stash()
        if self.totalScore >= self.config.totalPoints:
            if self.onDeckBoard:
                self.onDeckBoard.stash()

            self.progressDescriptionLabel.stash()
            taskMgr.remove('SawingGame.updateSawTask')
            self.request('Outro')
            return None

        self.currentBoard = self.onDeckBoard
        self.currentBoardIndex = self.onDeckBoardIndex
        self.piece1 = self.currentBoard.find('**/piece_1')
        self.piece1.setTransparency(1)
        self.piece2 = self.currentBoard.find('**/piece_2')
        self.piece2.setTransparency(1)
        self.cut = self.currentBoard.find('**/piece_cut')
        self.cut.setColor(self.config.cutColor)
        self.cut.setTransparency(1)
        self.board_left = self.piece1.find('**/board')
        self.board_left.setTransparency(1)
        self.zone1_left = self.piece1.find('**/zone_1')
        self.zone1_left.setTransparency(1)
        self.zone2_left = self.piece1.find('**/zone_2')
        self.zone2_left.setTransparency(1)
        self.board_right = self.piece2.find('**/board')
        self.board_right.setTransparency(1)
        self.zone1_right = self.piece2.find('**/zone_1')
        self.zone1_right.setTransparency(1)
        self.zone2_right = self.piece2.find('**/zone_2')
        self.zone2_right.setTransparency(1)
        self.board_left.setCollideMask(SAW_COLLIDE_MASK)
        self.board_right.setCollideMask(SAW_COLLIDE_MASK)
        self.cut.setCollideMask(SAW_COLLIDE_MASK)
        self.zone1_right.setCollideMask(SAW_COLLIDE_MASK)
        self.zone1_left.setCollideMask(SAW_COLLIDE_MASK)
        self.zone2_right.setCollideMask(SAW_COLLIDE_MASK)
        self.zone2_left.setCollideMask(SAW_COLLIDE_MASK)
        self.startPositions = (
            self.currentBoard.find('**/locator_start_0').getPos() +
            Point3(*self.config.activeBoardPosition),
            self.currentBoard.find('**/locator_start_1').getPos() +
            Point3(*self.config.activeBoardPosition))
        self.currentStartIndex = 0
        for waypoint in self.sawWaypoints:
            waypoint.removeNode()

        self.sawWaypoints = []
        locator = self.currentBoard.find('**/locator_0')
        index = 0
        while not locator.isEmpty():
            self.sawWaypoints.append(
                SawWaypoint(index, self.currentBoard, locator.getPos()))
            locator = self.currentBoard.find('**/locator_%i' % (index + 1))
            index += 1
        self.sawButton.deactivate()
        self.sawButton.setPos(self.startPositions[self.currentStartIndex])
        self.hitBoardPenalty = False
        self.hitZone1Penalty = False
        self.hitZone2Penalty = False
        self.lastMousePos = None
        self.moveDiffForSound = self.config.playSawingSoundDelta + 0.10000000000000001
        self.newBoardSequence = Sequence(
            Parallel(
                self.currentBoard.posInterval(
                    self.config.newBoardAnimTime,
                    Point3(*self.config.activeBoardPosition)),
                self.currentBoard.scaleInterval(self.config.newBoardAnimTime,
                                                1.0)),
            name='RepairSawingGame.newBoardSequence')
        if self.state in ['Game']:
            self.newBoardSequence.append(Func(self.sawButton.activate))

        self.newBoardSequence.append(Wait(0.5))
        self.newBoardSequence.append(Func(self.moveNewBoardOnDeck))
        self.newBoardSequence.start()
 def initIntervals(self):
     dur = Globals.LegalEagle.LiftOffTime
     nestPos = self.nest.getPos(render)
     airPos = nestPos + Vec3(0.0, 0.0, Globals.LegalEagle.LiftOffHeight)
     self.takeOffSeq = Sequence(Parallel(
         Sequence(
             Wait(dur * 0.6),
             LerpPosInterval(self.suit,
                             dur * 0.4,
                             startPos=nestPos,
                             pos=airPos,
                             blendType='easeInOut'))),
                                Wait(1.5),
                                Func(self.request, 'next'),
                                name='%s.takeOffSeq-%i' %
                                (self.__class__.__name__, self.index))
     self.landOnNestPosLerp = LerpPosInterval(self.suit,
                                              1.0,
                                              startPos=airPos,
                                              pos=nestPos,
                                              blendType='easeInOut')
     self.landingSeq = Sequence(Func(self.updateLandOnNestPosLerp),
                                Parallel(self.landOnNestPosLerp),
                                Func(self.request, 'next'),
                                name='%s.landingSeq-%i' %
                                (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.ChargeUpTime
     self.chargeUpPosLerp = LerpFunc(
         self.moveAlongChargeUpMopathFunc,
         fromData=0.0,
         toData=self.chargeUpMotionPath.getMaxT(),
         duration=dur,
         blendType='easeInOut')
     self.chargeUpAttackSeq = Sequence(
         Func(self.updateChargeUpPosLerp),
         self.chargeUpPosLerp,
         Func(self.request, 'next'),
         name='%s.chargeUpAttackSeq-%i' %
         (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.RetreatToNestTime
     self.retreatToNestPosLerp = LerpPosInterval(self.suit,
                                                 dur,
                                                 startPos=Vec3(0, 0, 0),
                                                 pos=airPos,
                                                 blendType='easeInOut')
     self.retreatToNestSeq = Sequence(Func(self.updateRetreatToNestPosLerp),
                                      self.retreatToNestPosLerp,
                                      Func(self.request, 'next'),
                                      name='%s.retreatToNestSeq-%i' %
                                      (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.RetreatToSkyTime
     self.retreatToSkyPosLerp = LerpFunc(
         self.moveAlongRetreatMopathFunc,
         fromData=0.0,
         toData=self.retreatToSkyMotionPath.getMaxT(),
         duration=dur,
         blendType='easeOut')
     self.retreatToSkySeq = Sequence(Func(self.updateRetreatToSkyPosLerp),
                                     self.retreatToSkyPosLerp,
                                     Func(self.request, 'next'),
                                     name='%s.retreatToSkySeq-%i' %
                                     (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.PreAttackTime
     self.preAttackLerpXY = LerpFunc(self.updateAttackXY,
                                     fromData=0.0,
                                     toData=1.0,
                                     duration=dur)
     self.preAttackLerpZ = LerpFunc(self.updateAttackZ,
                                    fromData=0.0,
                                    toData=1.0,
                                    duration=dur,
                                    blendType='easeOut')
     dur = Globals.LegalEagle.PostAttackTime
     self.postAttackPosLerp = LerpPosInterval(self.suit,
                                              dur,
                                              startPos=Vec3(0, 0, 0),
                                              pos=Vec3(0, 0, 0))
     self.attackSeq = Sequence(
         Parallel(self.preAttackLerpXY, self.preAttackLerpZ),
         Func(self.updatePostAttackPosLerp),
         self.postAttackPosLerp,
         Func(self.request, 'next'),
         name='%s.attackSeq-%i' % (self.__class__.__name__, self.index))
     dur = Globals.LegalEagle.CooldownTime
     self.cooldownSeq = Sequence(Wait(dur),
                                 Func(self.request, 'next'),
                                 name='%s.cooldownSeq-%i' %
                                 (self.__class__.__name__, self.index))
     self.propTrack = Sequence(
         ActorInterval(self.prop, 'propeller', startFrame=0, endFrame=14))
     self.hoverOverNestSeq = Sequence(
         ActorInterval(self.suit,
                       'landing',
                       startFrame=10,
                       endFrame=20,
                       playRate=0.5),
         ActorInterval(self.suit,
                       'landing',
                       startFrame=20,
                       endFrame=10,
                       playRate=0.5))
class BambooCane(ToonUpGag):
    def __init__(self):
        ToonUpGag.__init__(self, CIGlobals.BambooCane,
                           'phase_5/models/props/cane.bam', 40, 45, 100,
                           GagGlobals.BAMBOO_CANE_SFX, 1)
        self.setImage('phase_3.5/maps/bamboo-cane.png')
        self.hatPath = 'phase_5/models/props/hat.bam'
        self.hat = None
        self.track = None
        self.scaleDuration = 0.5
        self.scaleUp = None
        self.scaleDown = None
        self.soundInterval = None
        self.timeout = 5.0

    def buildHat(self):
        self.cleanupHat()
        self.hat = loader.loadModel(self.hatPath)

    def cleanupHat(self):
        if self.hat:
            self.hat.removeNode()

    def buildScaleTracks(self):
        props = []
        props.append(self.hat)
        props.append(self.gag)
        self.scaleUp = self.getScaleTrack(props, self.scaleDuration,
                                          self.PNTNEARZERO, self.PNTNORMAL)
        self.scaleDown = self.getScaleTrack(props, self.scaleDuration,
                                            self.PNTNORMAL, self.PNTNEARZERO)

    def start(self):
        super(BambooCane, self).start()
        if not self.hat:
            self.buildHat()
        if not self.gag:
            self.build()
        self.setupHandJoints()
        if not self.scaleUp:
            self.buildScaleTracks()
        self.placeProp(self.handJoint, self.hat, Point3(0.23, 0.09, 0.69),
                       Point3(180, 0, 0))
        self.placeProp(self.lHandJoint, self.gag, Point3(-0.28, 0.0, 0.14),
                       Point3(0.0, 0.0, -150.0))
        self.soundInterval = self.getSoundTrack(0.2, self.gag, 6.4)
        propInterval = Sequence()
        propInterval.append(self.scaleUp)
        propInterval.append(
            Wait(base.localAvatar.getDuration('happy-dance') - 2))
        if self.avatar == base.localAvatar:
            propInterval.append(Func(self.setHealAmount))
            propInterval.append(Func(self.healNearbyAvatars, 25))
        propInterval.append(self.scaleDown)
        propInterval.append(Func(self.cleanupGag))
        propInterval.append(Func(self.reset))
        self.track = Parallel(propInterval,
                              ActorInterval(self.avatar, 'happy-dance'),
                              Func(self.soundInterval.start))
        self.track.start()

    def equip(self):
        # self.gag returns the cane object.
        super(BambooCane, self).equip()
        self.build()
        self.buildHat()
        self.buildScaleTracks()

    def unEquip(self):
        if self.track:
            self.soundInterval.finish()
            self.track.finish()
            self.track = None
        self.reset()
        if self.scaleDown:
            Sequence(self.scaleDown, Func(self.cleanupGag)).start()

    def cleanupGag(self):
        if self.gag:
            self.gag.removeNode()
        self.cleanupHat()
    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()
Example #38
0
    def getTossPieInterval(self, toon, x, y, z, h, p, r, power, beginFlyIval = Sequence()):
        from toontown.toonbase import ToontownBattleGlobals
        from toontown.battle import BattleProps
        pie = toon.getPieModel()
        pie.setScale(0.9)
        flyPie = pie.copyTo(NodePath('a'))
        pieName = ToontownBattleGlobals.pieNames[toon.pieType]
        pieType = BattleProps.globalPropPool.getPropType(pieName)
        animPie = Sequence()
        if pieType == 'actor':
            animPie = ActorInterval(pie, pieName, startFrame=48)
        sound = loader.loadSfx('phase_3.5/audio/sfx/AA_pie_throw_only.mp3')
        t = power / 100.0
        dist = 100 - 70 * t
        time = 1 + 0.5 * t
        proj = ProjectileInterval(None, startPos=Point3(0, 0, 0), endPos=Point3(0, dist, 0), duration=time)
        relVel = proj.startVel

        def getVelocity(toon = toon, relVel = relVel):
            return render.getRelativeVector(toon, relVel) * 0.6

        toss = Track((0, Sequence(Func(toon.setPosHpr, x, y, z, h, p, r), Func(pie.reparentTo, toon.rightHand), Func(pie.setPosHpr, 0, 0, 0, 0, 0, 0), Parallel(ActorInterval(toon, 'throw', startFrame=48, partName='torso'), animPie), Func(toon.loop, 'neutral'))), (16.0 / 24.0, Func(pie.detachNode)))
        fly = Track((14.0 / 24.0, SoundInterval(sound, node=toon)), (16.0 / 24.0, Sequence(Func(flyPie.reparentTo, render), Func(flyPie.setPosHpr, toon, 0.52, 0.97, 2.24, 0, -45, 0), beginFlyIval, ProjectileInterval(flyPie, startVel=getVelocity, duration=6), Func(flyPie.detachNode))))
        return (toss, fly, flyPie)
Example #39
0
    def doDeathTrack(self):
        def removeDeathSuit(suit, deathSuit):
            if not deathSuit.isEmpty():
                deathSuit.detachNode()
                suit.cleanupLoseActor()

        self.deathSuit.reparentTo(self.suit.getParent())
        self.deathSuit.setScale(self.suit.getScale())
        self.deathSuit.setPos(render, self.suit.getPos(render))
        self.deathSuit.setHpr(render, self.suit.getHpr(render))
        self.suit.hide()
        self.collNodePath.reparentTo(self.deathSuit)
        gearPoint = Point3(0, 0, self.suit.height / 2.0 + 2.0)
        smallGears = BattleParticles.createParticleEffect(
            file='gearExplosionSmall')
        singleGear = BattleParticles.createParticleEffect('GearExplosion',
                                                          numParticles=1)
        smallGearExplosion = BattleParticles.createParticleEffect(
            'GearExplosion', numParticles=10)
        bigGearExplosion = BattleParticles.createParticleEffect(
            'BigGearExplosion', numParticles=30)
        smallGears.setPos(gearPoint)
        singleGear.setPos(gearPoint)
        smallGearExplosion.setPos(gearPoint)
        bigGearExplosion.setPos(gearPoint)
        smallGears.setDepthWrite(False)
        singleGear.setDepthWrite(False)
        smallGearExplosion.setDepthWrite(False)
        bigGearExplosion.setDepthWrite(False)
        suitTrack = Sequence(
            Func(self.collNodePath.stash),
            ActorInterval(self.deathSuit, 'lose', startFrame=80, endFrame=140),
            Func(removeDeathSuit,
                 self.suit,
                 self.deathSuit,
                 name='remove-death-suit'))
        explosionTrack = Sequence(
            Wait(1.5),
            MovieUtil.createKapowExplosionTrack(self.deathSuit,
                                                explosionPoint=gearPoint))
        gears1Track = Sequence(ParticleInterval(smallGears,
                                                self.deathSuit,
                                                worldRelative=0,
                                                duration=4.3,
                                                cleanup=True),
                               name='gears1Track')
        gears2MTrack = Track((0.0, explosionTrack),
                             (0.7,
                              ParticleInterval(singleGear,
                                               self.deathSuit,
                                               worldRelative=0,
                                               duration=5.7,
                                               cleanup=True)),
                             (5.2,
                              ParticleInterval(smallGearExplosion,
                                               self.deathSuit,
                                               worldRelative=0,
                                               duration=1.2,
                                               cleanup=True)),
                             (5.4,
                              ParticleInterval(bigGearExplosion,
                                               self.deathSuit,
                                               worldRelative=0,
                                               duration=1.0,
                                               cleanup=True)),
                             name='gears2MTrack')

        def removeParticle(particle):
            if particle and hasattr(particle, 'renderParent'):
                particle.cleanup()
                del particle

        removeParticles = Sequence(Func(removeParticle, smallGears),
                                   Func(removeParticle, singleGear),
                                   Func(removeParticle, smallGearExplosion),
                                   Func(removeParticle, bigGearExplosion))
        self.deathTrack = Sequence(
            Parallel(suitTrack, gears2MTrack, gears1Track,
                     self._deathSoundIval), removeParticles)
        self.deathTrack.start()
Example #40
0
    def makeToonReleaseInterval(self, toon):
        temp1 = self.waterPitcherNode.attachNewNode('temp1')
        temp1.setPos(self.toonPitcherPosition)
        temp2 = self.waterPitcherNode.attachNewNode('temp2')
        temp2.setPos(0, -10, -self.waterPitcherNode.getZ())
        startPos = temp1.getPos(render)
        endPos = temp2.getPos(render)
        temp1.removeNode()
        temp2.removeNode()

        def getSlideToPos(toon = toon):
            return render.getRelativePoint(toon, Point3(0, -10, 0))

        if self.gotHitByBoss:
            self.notify.debug('creating zap interval instead')
            grabIval = Sequence(Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1)))
        else:
            grabIval = Sequence(Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'jump'), Sequence(Wait(0.43), ProjectileInterval(toon, duration=0.9, startPos=startPos, endPos=endPos))))
        return grabIval
Example #41
0
 def makeToonGrabInterval(self, toon):
     toon.pose('leverNeutral', 0)
     toon.update()
     rightHandPos = toon.rightHand.getPos(toon)
     self.toonPitcherPosition = Point3(self.handPos[0] - rightHandPos[0], self.handPos[1] - rightHandPos[1], 0)
     destZScale = rightHandPos[2] / self.handPos[2]
     grabIval = Sequence(Func(toon.wrtReparentTo, self.waterPitcherNode), Func(toon.loop, 'neutral'), Parallel(ActorInterval(toon, 'jump'), Sequence(Wait(0.43), Parallel(ProjectileInterval(toon, duration=0.9, startPos=toon.getPos(self.waterPitcherNode), endPos=self.toonPitcherPosition), LerpHprInterval(toon, 0.9, Point3(0, 0, 0)), LerpScaleInterval(self.waterPitcherModel, 0.9, Point3(1, 1, destZScale))))), Func(toon.setPos, self.toonPitcherPosition), Func(toon.loop, 'leverNeutral'))
     return grabIval
Example #42
0
    def start(self):
        SoundGag.start(self)
        INSTRUMENT_SCALE_MODIFIER = 0.5
        delayTime = 2.45
        delayUntilAppearSound = 1.0
        tracks = Parallel()
        instrMin = Vec3(0.001, 0.001, 0.001)
        instrMax = Vec3(0.65, 0.65, 0.65)
        instrMax *= INSTRUMENT_SCALE_MODIFIER
        instrStretch = Vec3(0.6, 1.1, 0.6)
        instrStretch *= INSTRUMENT_SCALE_MODIFIER

        def setInstrumentStats():
            self.gag.setPos(-1.1, -1.4, 0.1)
            self.gag.setHpr(145, 0, 0)
            self.gag.setScale(instrMin)

        megaphoneShow = Sequence(
            Func(self.placeProp, self.handJoint, self.megaphone),
            Func(self.placeProp, self.handJoint, self.gag),
            Func(setInstrumentStats))
        grow = self.getScaleIntervals(self.gag,
                                      duration=0.2,
                                      startScale=instrMin,
                                      endScale=instrMax)
        instrumentAppear = grow
        stretchInstr = self.getScaleBlendIntervals(self.gag,
                                                   duration=0.2,
                                                   startScale=instrMax,
                                                   endScale=instrStretch,
                                                   blendType='easeOut')
        backInstr = self.getScaleBlendIntervals(self.gag,
                                                duration=0.2,
                                                startScale=instrStretch,
                                                endScale=instrMax,
                                                blendType='easeIn')
        stretchMega = self.getScaleBlendIntervals(
            self.megaphone,
            duration=0.2,
            startScale=self.megaphone.getScale(),
            endScale=0.9,
            blendType='easeOut')
        backMega = self.getScaleBlendIntervals(
            self.megaphone,
            duration=0.2,
            startScale=0.9,
            endScale=self.megaphone.getScale(),
            blendType='easeIn')
        attackTrack = Parallel(Sequence(stretchInstr, backInstr),
                               Sequence(stretchMega, backMega))
        megaphoneTrack = Sequence(
            megaphoneShow, Wait(delayUntilAppearSound),
            SoundInterval(self.appearSfx, node=self.avatar), instrumentAppear)
        tracks.append(megaphoneTrack)
        tracks.append(ActorInterval(self.avatar, 'sound'))
        instrumentshrink = self.getScaleIntervals(self.gag,
                                                  duration=0.1,
                                                  startScale=instrMax,
                                                  endScale=instrMin)
        soundTrack = Sequence(
            Wait(delayTime),
            Parallel(attackTrack, SoundInterval(self.soundSfx,
                                                node=self.avatar), Wait(0.2),
                     instrumentshrink, Func(self.damageCogsNearby), Wait(0.4),
                     Func(self.finish)))
        tracks.append(soundTrack)
        tracks.start()
        self.tracks = tracks
Example #43
0
 def setHillType(self, type):
     if self.isUp and (self.hillType == MoleFieldBase.HILL_MOLE
                       and type == MoleFieldBase.HILL_BOMB
                       or self.hillType == MoleFieldBase.HILL_BOMB
                       and type == MoleFieldBase.HILL_MOLE):
         return
     self.hillType = type
     self.moleHead.removeNode()
     if type == MoleFieldBase.HILL_MOLE:
         self.moleHead = loader.loadModel(
             'phase_12/models/bossbotHQ/mole_norm')
         self.moleColNodePath.setScale(3.0)
         self.moleHead.setH(0)
         self.mole.setBillboardAxis(localAvatar, 0)
     if type == MoleFieldBase.HILL_BOMB or type == MoleFieldBase.HILL_COGWHACKED:
         self.moleHead = loader.loadModel(
             'phase_12/models/bossbotHQ/mole_cog')
         self.moleColNodePath.setScale(1.0)
         self.mole.setBillboardAxis(localAvatar, 0)
         if type == MoleFieldBase.HILL_COGWHACKED:
             self.doMoleDown()
             BattleParticles.loadParticles()
             singleGear = BattleParticles.createParticleEffect(
                 'GearExplosion', numParticles=1)
             smallGearExplosion = BattleParticles.createParticleEffect(
                 'GearExplosion', numParticles=10)
             bigGearExplosion = BattleParticles.createParticleEffect(
                 'BigGearExplosion', numParticles=30)
             gears2MTrack = Track((0.0,
                                   ParticleInterval(singleGear,
                                                    self.hill,
                                                    worldRelative=1,
                                                    duration=5.7,
                                                    cleanup=True)),
                                  (0.0,
                                   ParticleInterval(smallGearExplosion,
                                                    self.hill,
                                                    worldRelative=0,
                                                    duration=1.2,
                                                    cleanup=True)),
                                  (0.3,
                                   ParticleInterval(bigGearExplosion,
                                                    self.hill,
                                                    worldRelative=0,
                                                    duration=1.0,
                                                    cleanup=True)),
                                  name='gears2MTrack')
             gears2MTrack.start()
             self.popIval = Sequence(
                 Parallel(
                     Sequence(
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(0.28, 0.0, 0.0)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(0.0, -0.23, 0.0)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(0.0, 0.0, 0.28)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(-0.35, 0.0, 0.0)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(0.0, 0.28, 0.0)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(0.31, 0.0, 0.0)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(0.0, -0.32, 0.0)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(0.0, 0.0, 0.48)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(-0.28, 0.0, 0.0)),
                         LerpPosInterval(self.moleHead, 0.05,
                                         Point3(0.0, 0.29, 0.0)))),
                 LerpPosInterval(self.mole, 0.5, Point3(0, 0, -2.5)),
                 Func(self.setHillType, MoleFieldBase.HILL_BOMB))
             self.popIval.start()
         else:
             self.moleHead.setH(0)
     if type == MoleFieldBase.HILL_WHACKED:
         self.moleHead = loader.loadModel(
             'phase_12/models/bossbotHQ/mole_hit')
         self.mole.setBillboardAxis(0)
         self.moleColNodePath.setScale(0.0)
         if self.popIval:
             self.popIval.finish()
         if self.downIval:
             self.downIval.finish()
         self.mole.setPos(0.0, 0.0, 0.0)
         self.popIval = Sequence(
             Parallel(
                 Sequence(
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.18, 0.0, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, -0.13, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, 0.0, 0.18)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(-0.15, 0.0, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, 0.18, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.11, 0.0, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, -0.12, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, 0.0, 0.18)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(-0.18, 0.0, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, 0.13, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.18, 0.0, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, -0.15, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, 0.0, 0.18)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(-0.16, 0.0, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, 0.18, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.11, 0.0, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, -0.18, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, 0.0, 0.17)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(-0.18, 0.0, 0.0)),
                     LerpPosInterval(self.moleHead, 0.05,
                                     Point3(0.0, 0.0, 0.0))),
                 Sequence(LerpScaleInterval(self.moleHead, 0.5, 3.5),
                          LerpScaleInterval(self.moleHead, 0.5, 1.0))),
             LerpPosInterval(self.mole, 0.5, Point3(0, 0, -2.5)),
             Func(self.setHillType, MoleFieldBase.HILL_MOLE))
         self.popIval.start()
     self.moleHead.reparentTo(self.mole)
class DistributedNPCToon(DistributedToon):
    notify = directNotify.newCategory('DistributedNPCToon')

    def __init__(self, cr):
        DistributedToon.__init__(self, cr)
        self.collisionNodePath = None
        self.cameraTrack = None
        self.originIndex = None
        self.npcId = None
        self.currentChatIndex = 0
        self.chatArray = None
        return

    def setLoadout(self, foo):
        pass

    def lookAtAvatar(self, avId):
        av = self.cr.doId2do.get(avId)
        if av:
            self.headsUp(av)

    def setNpcId(self, id):
        self.npcId = id

    def getNpcId(self):
        return self.npcId

    def setOriginIndex(self, index):
        self.originIndex = index

    def getOriginIndex(self):
        return self.originIndex

    def __setupCollisions(self):
        sphere = CollisionSphere(0, 0, 0, 4)
        sphere.setTangible(0)
        collisionNode = CollisionNode(self.uniqueName('NPCToonSphere'))
        collisionNode.addSolid(sphere)
        collisionNode.setCollideMask(CIGlobals.WallBitmask)
        self.collisionNodePath = self.attachNewNode(collisionNode)
        self.collisionNodePath.setY(1.5)

    def __removeCollisions(self):
        if self.collisionNodePath:
            self.collisionNodePath.removeNode()
            self.collisionNodePath = None
        return

    def handleEnterCollision(self, entry):
        self.cr.playGame.getPlace().fsm.request('stop')
        base.localAvatar.stopSmartCamera()
        self.sendUpdate('requestEnter', [])

    def doCameraNPCInteraction(self):
        currCamPos = camera.getPos()
        currCamHpr = camera.getHpr()
        camera.setX(camera.getX() + 5)
        camera.setY(camera.getY() + 5)
        camera.headsUp(self)
        newCamPos = camera.getPos()
        newCamHpr = camera.getHpr()
        camera.setPos(currCamPos)
        camera.setHpr(currCamHpr)
        self.cameraTrack = Parallel(
            LerpPosInterval(camera,
                            duration=1.0,
                            pos=newCamPos,
                            startPos=currCamPos,
                            blendType='easeOut'),
            LerpQuatInterval(camera,
                             duration=1.0,
                             quat=newCamHpr,
                             startHpr=currCamHpr,
                             blendType='easeOut'))
        self.cameraTrack.start()

    def stopCameraTrack(self):
        if self.cameraTrack:
            self.cameraTrack.finish()
            self.cameraTrack = None
        return

    def oneChatThenExit(self):
        self.acceptOnce('mouse1-up', self.d_requestExit)

    def enterAccepted(self):
        self.doCameraNPCInteraction()
        questData = base.localAvatar.questManager.getQuestAndIdWhereCurrentObjectiveIsToVisit(
            self.npcId)
        if questData:
            quest = questData[1]
            self.currentQuestObjective = quest.currentObjectiveIndex
            self.currentQuestId = questData[0]
            self.currentChatIndex = 0
            if CIGlobals.NPCToonDict[self.npcId][3] == CIGlobals.NPC_HQ:
                if not quest.isComplete():
                    self.doNPCChat(array=Quests.QuestHQOfficerDialogue)
            if CIGlobals.NPCToonDict[self.npcId][3] == CIGlobals.NPC_REGULAR:
                self.doNPCChat(array=Quests.QuestNPCDialogue)

    def doNPCChat(self, array=Quests.QuestNPCDialogue, chat=None):
        if array and not chat:
            self.chatArray = array
            self.b_setChat(array[self.currentQuestId][
                self.currentQuestObjective][self.currentChatIndex])
            self.currentChatIndex += 1
            Sequence(Wait(0.1),
                     Func(self.acceptOnce, 'mouse1-up',
                          self.doNextNPCChat)).start()
        else:
            if chat and not array:
                self.b_setChat(chat)
                Sequence(
                    Wait(0.1),
                    Func(self.acceptOnce, 'mouse1-up',
                         self.d_requestExit)).start()

    def d_requestExit(self):
        self.sendUpdate('requestExit', [])

    def doNextNPCChat(self):
        if self.currentChatIndex >= len(self.chatArray[self.currentQuestId][
                self.currentQuestObjective]):
            self.chatArray = None
            self.d_requestExit()
        else:
            self.doNPCChat(self.chatArray)
        return

    def rejectEnter(self):
        self.exitAccepted()

    def exitAccepted(self):
        self.stopCameraTrack()
        self.cr.playGame.getPlace().fsm.request('walk')
        self.acceptCollisions()

    def acceptCollisions(self):
        self.acceptOnce('enter' + self.uniqueName('NPCToonSphere'),
                        self.handleEnterCollision)

    def ignoreCollisions(self):
        self.ignore('enter' + self.uniqueName('NPCToonSphere'))

    def __npcOriginPoll(self, task):
        if task.time > 4.0:
            self.notify.warning(
                'Giving up waiting for npc origin after %d seconds. Will parent to render.'
                % task.time)
            self.reparentTo(render)
            return task.done
        npcOrigin = render.find('**/npc_origin_' + str(self.originIndex))
        if not npcOrigin.isEmpty():
            self.reparentTo(npcOrigin)
            return task.done
        return task.cont

    def startNPCOriginPoll(self):
        base.taskMgr.add(self.__npcOriginPoll,
                         self.uniqueName('NPCOriginPoll'))

    def stopNPCOriginPoll(self):
        base.taskMgr.remove(self.uniqueName('NPCOriginPoll'))

    def setupNameTag(self, tempName=None):
        DistributedToon.setupNameTag(self, tempName)
        self.nametag.setNametagColor(
            NametagGlobals.NametagColors[NametagGlobals.CCNPC])
        self.nametag.setActive(0)
        self.nametag.updateAll()

    def announceGenerate(self):
        DistributedToon.announceGenerate(self)
        self.startLookAround()
        self.__setupCollisions()
        npcOrigin = render.find('**/npc_origin_' + str(self.originIndex))
        if not npcOrigin.isEmpty():
            self.reparentTo(npcOrigin)
        else:
            self.startNPCOriginPoll()
        self.acceptCollisions()

    def disable(self):
        self.ignore('mouse1-up')
        self.stopLookAround()
        self.stopNPCOriginPoll()
        self.chatArray = None
        self.originIndex = None
        self.npcId = None
        self.stopCameraTrack()
        self.ignoreCollisions()
        self.__removeCollisions()
        DistributedToon.disable(self)
        return
Example #45
0
 def splitBoard(self):
     self.sawingLine.reset()
     board = self.currentBoard
     boardIndex = self.currentBoardIndex
     if self.hitZone2Penalty:
         boardSplitAnim = Parallel(
             LerpPosInterval(self.board_left,
                             duration=self.config.splitBoardAnimTime,
                             pos=Point3(-2.0, 0.0, 0.0)),
             LerpPosInterval(self.board_right,
                             duration=self.config.splitBoardAnimTime,
                             pos=Point3(2.0, 0.0, 0.0)),
             LerpFunc(self.zone2_left.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0),
             LerpFunc(self.zone2_right.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0),
             LerpFunc(self.zone1_left.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0),
             LerpFunc(self.zone1_right.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0),
             LerpFunc(self.cut.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0))
     elif self.hitZone1Penalty:
         boardSplitAnim = Parallel(
             LerpPosInterval(self.board_left,
                             duration=self.config.splitBoardAnimTime,
                             pos=Point3(-2.0, 0.0, 0.0)),
             LerpPosInterval(self.board_right,
                             duration=self.config.splitBoardAnimTime,
                             pos=Point3(2.0, 0.0, 0.0)),
             LerpPosInterval(self.zone2_left,
                             duration=self.config.splitBoardAnimTime,
                             pos=Point3(-2.0, 0.0, 0.0)),
             LerpPosInterval(self.zone2_right,
                             duration=self.config.splitBoardAnimTime,
                             pos=Point3(2.0, 0.0, 0.0)),
             LerpFunc(self.zone1_left.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0),
             LerpFunc(self.zone1_right.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0),
             LerpFunc(self.cut.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0))
     else:
         boardSplitAnim = Parallel(
             LerpPosInterval(self.piece1,
                             duration=self.config.splitBoardAnimTime,
                             pos=Point3(-2.0, self.config.boardYDist, 0.0)),
             LerpPosInterval(self.piece2,
                             duration=self.config.splitBoardAnimTime,
                             pos=Point3(2.0, self.config.boardYDist, 0.0)),
             LerpFunc(self.cut.setSa,
                      duration=self.config.splitBoardAnimTime / 2.0,
                      fromData=1.0,
                      toData=0.0))
     self.splitBoardSequence = Sequence(
         Func(self.updateScore),
         Func(self.boardComplete.play),
         boardSplitAnim,
         Func(board.stash),
         Func(self.piece1.setPos, self.piece1.getPos()),
         Func(self.piece2.setPos, self.piece2.getPos()),
         Func(self.board_right.setPos, self.board_right.getPos()),
         Func(self.board_left.setPos, self.board_left.getPos()),
         Func(self.zone2_right.setPos, self.zone2_right.getPos()),
         Func(self.zone2_left.setPos, self.zone2_left.getPos()),
         Func(self.zone1_right.setPos, self.zone1_right.getPos()),
         Func(self.zone1_left.setPos, self.zone1_left.getPos()),
         Func(self.cut.setSa, 1.0),
         Func(self.zone1_right.setSa, 1.0),
         Func(self.zone1_left.setSa, 1.0),
         Func(self.zone2_right.setSa, 1.0),
         Func(self.zone2_left.setSa, 1.0),
         Func(self.board_right.setSa, 1.0),
         Func(self.board_left.setSa, 1.0),
         Func(self.loadNewBoard),
         Func(self.addBoardBackToPool, board, boardIndex),
         name='RepairSawGame.splitBoardSequence')
     self.splitBoardSequence.start()
Example #46
0
 def fillSlot(self, index, avId, wantBoardingShow=0):
     self.notify.debug('%s.fillSlot(%s, %s, ... %s)' %
                       (self.doId, index, avId, globalClock.getRealTime()))
     request = self.toonRequests.get(index)
     if request:
         self.cr.relatedObjectMgr.abortRequest(request)
         del self.toonRequests[index]
     if avId == 0:
         pass
     elif avId not in self.cr.doId2do:
         func = PythonUtil.Functor(self.gotToon, index, avId)
         self.toonRequests[index] = self.cr.relatedObjectMgr.requestObjects(
             [avId], allCallback=func)
     elif not self.isSetup:
         self.deferredSlots.append((index, avId, wantBoardingShow))
     else:
         if avId == base.localAvatar.getDoId():
             place = base.cr.playGame.getPlace()
             if not place:
                 return
             elevator = self.getPlaceElevator()
             if elevator == None:
                 place.fsm.request('elevator')
                 elevator = self.getPlaceElevator()
             if not elevator:
                 return
             self.localToonOnBoard = 1
             if hasattr(localAvatar,
                        'boardingParty') and localAvatar.boardingParty:
                 localAvatar.boardingParty.forceCleanupInviteePanel()
                 localAvatar.boardingParty.forceCleanupInviterPanels()
             if hasattr(base.localAvatar, 'elevatorNotifier'):
                 base.localAvatar.elevatorNotifier.cleanup()
             cameraTrack = Sequence()
             cameraTrack.append(
                 Func(elevator.fsm.request, 'boarding',
                      [self.getElevatorModel()]))
             cameraTrack.append(Func(elevator.fsm.request, 'boarded'))
         toon = self.cr.doId2do[avId]
         toon.stopSmooth()
         toon.wrtReparentTo(self.golfKart)
         sitStartDuration = toon.getDuration('sit-start')
         jumpTrack = self.generateToonJumpTrack(toon, index)
         track = Sequence(jumpTrack,
                          Func(toon.setAnimState, 'Sit', 1.0),
                          Func(self.clearToonTrack, avId),
                          name=toon.uniqueName('fillElevator'),
                          autoPause=1)
         if wantBoardingShow:
             boardingTrack, boardingTrackType = self.getBoardingTrack(
                 toon, index, True)
             track = Sequence(boardingTrack, track)
             if avId == base.localAvatar.getDoId():
                 cameraWaitTime = 2.5
                 if boardingTrackType == BoardingGroupShow.TRACK_TYPE_RUN:
                     cameraWaitTime = 0.5
                 cameraTrack = Sequence(Wait(cameraWaitTime), cameraTrack)
         if self.canHideBoardingQuitBtn(avId):
             track = Sequence(
                 Func(localAvatar.boardingParty.groupPanel.disableQuitButton
                      ), track)
         if avId == base.localAvatar.getDoId():
             track = Parallel(cameraTrack, track)
         track.delayDelete = DelayDelete.DelayDelete(
             toon, 'CogKart.fillSlot')
         self.storeToonTrack(avId, track)
         track.start()
         self.fillSlotTrack = track
         self.boardedAvIds[avId] = None
     return
Example #47
0
    def createOnePlayerSequence(self, index, duration):
        numVotes = self.votes[index]
        direction = self.directions[index]

        def ticketTicker(t,
                         label=self.entryList[index][direction + 1],
                         startVotes=0,
                         endVotes=numVotes):
            label['text'] = str(int(t * endVotes + startVotes))

        track = Parallel()
        startVotes = 0
        for prev in range(index):
            if self.directions[prev] == direction:
                startVotes += self.votes[prev]

        def totalTicker(t,
                        label=self.totalVotesLabels[direction],
                        startVotes=startVotes,
                        additionalVotes=numVotes):
            label['text'] = str(int(t * additionalVotes + startVotes))

        track.append(
            LerpFunc(totalTicker,
                     duration=duration,
                     name='countTotal %d' % index))
        if index in self.avVotesLabel:

            def avVotesTicker(t,
                              label=self.avVotesLabel[index],
                              startVotes=0,
                              endVotes=numVotes,
                              direction=direction):
                oldValue = label['text']
                newValue = int(t * endVotes + startVotes)
                label['text'] = str(newValue)
                if not oldValue == label['text']:
                    if newValue:
                        if direction == 0:
                            self.upArrowSfx[self.curArrowSfxIndex].play()
                        else:
                            self.downArrowSfx[self.curArrowSfxIndex].play()
                            self.curArrowSfxIndex += 1
                        if self.curArrowSfxIndex >= len(self.upArrowSfx):
                            self.curArrowSfxIndex = 0

            label = self.avVotesLabel[index]
            track.append(
                Func(self.avVotesLabel[index].show,
                     name='showName %d' % index))
            if index in self.avArrows:
                track.append(
                    Func(self.avArrows[index].show,
                         name='showArrow %d' % index))
            if direction == 0 and numVotes:
                pass
            elif direction == 1 and numVotes:
                pass
            else:
                track.append(SoundInterval(self.noVoteSfx))
            track.append(
                LerpFunc(avVotesTicker,
                         duration=duration,
                         name='countAvVotes %d' % index))
        return track
Example #48
0
class DistributedCogThiefGame(DistributedMinigame):
    notify = directNotify.newCategory('DistributedCogThiefGame')
    ToonSpeed = CTGG.ToonSpeed
    StageHalfWidth = 200.0
    StageHalfHeight = 100.0
    BarrelScale = 0.25
    TOON_Z = 0
    UPDATE_SUITS_TASK = 'CogThiefGameUpdateSuitsTask'
    REWARD_COUNTDOWN_TASK = 'cogThiefGameRewardCountdown'
    ControlKeyLimitTime = 1.0

    def __init__(self, cr):
        DistributedMinigame.__init__(self, cr)
        self.gameFSM = ClassicFSM.ClassicFSM('DistributedCogThiefGame', [
            State.State('off', self.enterOff, self.exitOff, ['play']),
            State.State('play', self.enterPlay, self.exitPlay, ['cleanup']),
            State.State('cleanup', self.enterCleanup, self.exitCleanup, [])
        ], 'off', 'cleanup')
        self.addChildGameFSM(self.gameFSM)
        self.cameraTopView = (0, 0, 55, 0, -90.0, 0)
        self.barrels = []
        self.cogInfo = {}
        self.lastTimeControlPressed = 0
        self.stolenBarrels = []
        self.useOrthoWalk = base.config.GetBool('cog-thief-ortho', 1)
        self.resultIval = None
        self.gameIsEnding = False
        self.__textGen = TextNode('cogThiefGame')
        self.__textGen.setFont(ToontownGlobals.getSignFont())
        self.__textGen.setAlign(TextNode.ACenter)
        return

    def getTitle(self):
        return TTLocalizer.CogThiefGameTitle

    def getInstructions(self):
        return TTLocalizer.CogThiefGameInstructions

    def getMaxDuration(self):
        return 0

    def load(self):
        self.notify.debug('load')
        DistributedMinigame.load(self)
        self.music = base.loadMusic('phase_4/audio/bgm/MG_CogThief.ogg')
        self.initCogInfo()
        for barrelIndex in xrange(CTGG.NumBarrels):
            barrel = loader.loadModel(
                'phase_4/models/minigames/cogthief_game_gagTank')
            barrel.setPos(CTGG.BarrelStartingPositions[barrelIndex])
            barrel.setScale(self.BarrelScale)
            barrel.reparentTo(render)
            barrel.setTag('barrelIndex', str(barrelIndex))
            collSphere = CollisionSphere(0, 0, 0, 4)
            collSphere.setTangible(0)
            name = 'BarrelSphere-%d' % barrelIndex
            collSphereName = self.uniqueName(name)
            collNode = CollisionNode(collSphereName)
            collNode.setFromCollideMask(CTGG.BarrelBitmask)
            collNode.addSolid(collSphere)
            colNp = barrel.attachNewNode(collNode)
            handler = CollisionHandlerEvent()
            handler.setInPattern('barrelHit-%fn')
            base.cTrav.addCollider(colNp, handler)
            self.accept('barrelHit-' + collSphereName, self.handleEnterBarrel)
            nodeToHide = '**/gagMoneyTen'
            if barrelIndex % 2:
                nodeToHide = '**/gagMoneyFive'
            iconToHide = barrel.find(nodeToHide)
            if not iconToHide.isEmpty():
                iconToHide.hide()
            self.barrels.append(barrel)

        self.gameBoard = loader.loadModel(
            'phase_4/models/minigames/cogthief_game')
        self.gameBoard.find('**/floor_TT').hide()
        self.gameBoard.find('**/floor_DD').hide()
        self.gameBoard.find('**/floor_DG').hide()
        self.gameBoard.find('**/floor_MM').hide()
        self.gameBoard.find('**/floor_BR').hide()
        self.gameBoard.find('**/floor_DL').hide()
        zone = self.getSafezoneId()
        if zone == ToontownGlobals.ToontownCentral:
            self.gameBoard.find('**/floor_TT').show()
        elif zone == ToontownGlobals.DonaldsDock:
            self.gameBoard.find('**/floor_DD').show()
        elif zone == ToontownGlobals.DaisyGardens:
            self.gameBoard.find('**/floor_DG').show()
        elif zone == ToontownGlobals.MinniesMelodyland:
            self.gameBoard.find('**/floor_MM').show()
        elif zone == ToontownGlobals.TheBrrrgh:
            self.gameBoard.find('**/floor_BR').show()
        elif zone == ToontownGlobals.DonaldsDreamland:
            self.gameBoard.find('**/floor_DL').show()
        else:
            self.gameBoard.find('**/floor_TT').show()
        self.gameBoard.setPosHpr(0, 0, 0, 0, 0, 0)
        self.gameBoard.setScale(1.0)
        self.toonSDs = {}
        avId = self.localAvId
        toonSD = CogThiefGameToonSD.CogThiefGameToonSD(avId, self)
        self.toonSDs[avId] = toonSD
        toonSD.load()
        self.loadCogs()
        self.toonHitTracks = {}
        self.toonPieTracks = {}
        self.sndOof = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg')
        self.sndRewardTick = base.loadSfx(
            'phase_3.5/audio/sfx/tick_counter.ogg')
        self.sndPerfect = base.loadSfx('phase_4/audio/sfx/ring_perfect.ogg')
        self.timer = ToontownTimer.ToontownTimer()
        self.timer.posInTopRightCorner()
        self.timer.hide()
        purchaseModels = loader.loadModel('phase_4/models/gui/purchase_gui')
        self.jarImage = purchaseModels.find('**/Jar')
        self.jarImage.reparentTo(hidden)
        self.rewardPanel = DirectLabel(parent=hidden,
                                       relief=None,
                                       pos=(-0.173, 0.0, -0.55),
                                       scale=0.65,
                                       text='',
                                       text_scale=0.2,
                                       text_fg=(0.95, 0.95, 0, 1),
                                       text_pos=(0, -.13),
                                       text_font=ToontownGlobals.getSignFont(),
                                       image=self.jarImage)
        self.rewardPanelTitle = DirectLabel(parent=self.rewardPanel,
                                            relief=None,
                                            pos=(0, 0, 0.06),
                                            scale=0.08,
                                            text=TTLocalizer.CannonGameReward,
                                            text_fg=(0.95, 0.95, 0, 1),
                                            text_shadow=(0, 0, 0, 1))
        return

    def unload(self):
        self.notify.debug('unload')
        DistributedMinigame.unload(self)
        del self.music
        self.removeChildGameFSM(self.gameFSM)
        del self.gameFSM
        self.gameBoard.removeNode()
        del self.gameBoard
        for barrel in self.barrels:
            barrel.removeNode()

        del self.barrels
        for avId in self.toonSDs.keys():
            toonSD = self.toonSDs[avId]
            toonSD.unload()

        del self.toonSDs
        self.timer.destroy()
        del self.timer
        self.rewardPanel.destroy()
        del self.rewardPanel
        self.jarImage.removeNode()
        del self.jarImage
        del self.sndRewardTick

    def onstage(self):
        self.notify.debug('onstage')
        DistributedMinigame.onstage(self)
        self.gameBoard.reparentTo(render)
        lt = base.localAvatar
        lt.reparentTo(render)
        self.__placeToon(self.localAvId)
        lt.setSpeed(0, 0)
        self.moveCameraToTop()
        toonSD = self.toonSDs[self.localAvId]
        toonSD.enter()
        toonSD.fsm.request('normal')
        self.stopGameWalk()
        for cogIndex in xrange(self.getNumCogs()):
            suit = self.cogInfo[cogIndex]['suit'].suit
            pos = self.cogInfo[cogIndex]['pos']
            suit.reparentTo(self.gameBoard)
            suit.setPos(pos)
            suit.nametag.setNametag2d(None)
            suit.nametag.setNametag3d(None)

        for avId in self.avIdList:
            self.toonHitTracks[avId] = Wait(0.1)

        self.toonRNGs = []
        for i in xrange(self.numPlayers):
            self.toonRNGs.append(RandomNumGen.RandomNumGen(self.randomNumGen))

        self.sndTable = {
            'hitBySuit': [None] * self.numPlayers,
            'falling': [None] * self.numPlayers
        }
        for i in xrange(self.numPlayers):
            self.sndTable['hitBySuit'][i] = base.loadSfx(
                'phase_4/audio/sfx/MG_Tag_C.ogg')
            self.sndTable['falling'][i] = base.loadSfx(
                'phase_4/audio/sfx/MG_cannon_whizz.ogg')

        base.playMusic(self.music, looping=1, volume=0.8)
        self.introTrack = self.getIntroTrack()
        self.introTrack.start()
        return

    def offstage(self):
        self.notify.debug('offstage')
        self.gameBoard.hide()
        self.music.stop()
        for barrel in self.barrels:
            barrel.hide()

        for avId in self.toonSDs.keys():
            self.toonSDs[avId].exit()

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

        self.timer.reparentTo(hidden)
        self.rewardPanel.reparentTo(hidden)
        if self.introTrack.isPlaying():
            self.introTrack.finish()
        del self.introTrack
        DistributedMinigame.offstage(self)

    def handleDisabledAvatar(self, avId):
        self.notify.debug('handleDisabledAvatar')
        self.notify.debug('avatar ' + str(avId) + ' disabled')
        self.toonSDs[avId].exit(unexpectedExit=True)
        del self.toonSDs[avId]
        DistributedMinigame.handleDisabledAvatar(self, avId)

    def setGameReady(self):
        if not self.hasLocalToon:
            return
        self.notify.debug('setGameReady')
        if DistributedMinigame.setGameReady(self):
            return
        for avId in self.remoteAvIdList:
            toon = self.getAvatar(avId)
            if toon:
                toon.reparentTo(render)
                self.__placeToon(avId)
                toon.useLOD(1000)
                toonSD = CogThiefGameToonSD.CogThiefGameToonSD(avId, self)
                self.toonSDs[avId] = toonSD
                toonSD.load()
                toonSD.enter()
                toonSD.fsm.request('normal')
                toon.startSmooth()

    def setGameStart(self, timestamp):
        if not self.hasLocalToon:
            return
        self.notify.debug('setGameStart')
        DistributedMinigame.setGameStart(self, timestamp)
        if not base.config.GetBool('cog-thief-endless', 0):
            self.timer.show()
            self.timer.countdown(CTGG.GameTime, self.__gameTimerExpired)
        self.clockStopTime = None
        self.rewardPanel.reparentTo(base.a2dTopRight)
        self.scoreMult = MinigameGlobals.getScoreMult(self.cr.playGame.hood.id)
        self.__startRewardCountdown()
        if self.introTrack.isPlaying():
            self.introTrack.finish()
        self.gameFSM.request('play')
        return

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

    def exitOff(self):
        pass

    def enterPlay(self):
        self.notify.debug('enterPlay')
        self.startGameWalk()
        self.spawnUpdateSuitsTask()
        self.accept('control', self.controlKeyPressed)
        self.pieHandler = CollisionHandlerEvent()
        self.pieHandler.setInPattern('pieHit-%fn')

    def exitPlay(self):
        self.ignore('control')
        if self.resultIval and self.resultIval.isPlaying():
            self.resultIval.finish()
            self.resultIval = None
        return

    def enterCleanup(self):
        self.__killRewardCountdown()
        if hasattr(self, 'jarIval'):
            self.jarIval.finish()
            del self.jarIval
        for key in self.toonHitTracks:
            ival = self.toonHitTracks[key]
            if ival.isPlaying():
                ival.finish()

        self.toonHitTracks = {}
        for key in self.toonPieTracks:
            ival = self.toonPieTracks[key]
            if ival.isPlaying():
                ival.finish()

        self.toonPieTracks = {}
        for key in self.cogInfo:
            cogThief = self.cogInfo[key]['suit']
            cogThief.cleanup()

        self.removeUpdateSuitsTask()
        self.notify.debug('enterCleanup')

    def exitCleanup(self):
        pass

    def __placeToon(self, avId):
        toon = self.getAvatar(avId)
        if toon:
            index = self.avIdList.index(avId)
            toon.setPos(CTGG.ToonStartingPositions[index])
            toon.setHpr(0, 0, 0)

    def moveCameraToTop(self):
        camera.reparentTo(render)
        p = self.cameraTopView
        camera.setPosHpr(p[0], p[1], p[2], p[3], p[4], p[5])
        base.camLens.setMinFov(46 / (4. / 3.))
        camera.setZ(camera.getZ() +
                    base.config.GetFloat('cog-thief-z-camera-adjust', 0.0))

    def destroyGameWalk(self):
        self.notify.debug('destroyOrthoWalk')
        if self.useOrthoWalk:
            self.gameWalk.destroy()
            del self.gameWalk
        else:
            self.notify.debug('TODO destroyGameWalk')

    def initGameWalk(self):
        self.notify.debug('startOrthoWalk')
        if self.useOrthoWalk:

            def doCollisions(oldPos, newPos, self=self):
                x = bound(newPos[0], CTGG.StageHalfWidth, -CTGG.StageHalfWidth)
                y = bound(newPos[1], CTGG.StageHalfHeight,
                          -CTGG.StageHalfHeight)
                newPos.setX(x)
                newPos.setY(y)
                return newPos

            orthoDrive = OrthoDrive(self.ToonSpeed,
                                    customCollisionCallback=doCollisions,
                                    instantTurn=True)
            self.gameWalk = OrthoWalk(orthoDrive,
                                      broadcast=not self.isSinglePlayer())
        else:
            self.gameWalk = CogThiefWalk.CogThiefWalk('walkDone')
            forwardSpeed = self.ToonSpeed / 2.0
            base.mouseInterfaceNode.setForwardSpeed(forwardSpeed)
            multiplier = forwardSpeed / ToontownGlobals.ToonForwardSpeed
            base.mouseInterfaceNode.setRotateSpeed(
                ToontownGlobals.ToonRotateSpeed * 4)

    def initCogInfo(self):
        for cogIndex in xrange(self.getNumCogs()):
            self.cogInfo[cogIndex] = {
                'pos': Point3(CTGG.CogStartingPositions[cogIndex]),
                'goal': CTGG.NoGoal,
                'goalId': CTGG.InvalidGoalId,
                'suit': None
            }

        return

    def loadCogs(self):
        suitTypes = ['ds', 'ac', 'bc', 'ms']
        for suitIndex in xrange(self.getNumCogs()):
            st = self.randomNumGen.choice(suitTypes)
            suit = CogThief.CogThief(suitIndex, st, self, self.getCogSpeed())
            self.cogInfo[suitIndex]['suit'] = suit

    def handleEnterSphere(self, colEntry):
        if self.gameIsEnding:
            return
        intoName = colEntry.getIntoNodePath().getName()
        fromName = colEntry.getFromNodePath().getName()
        debugInto = intoName.split('/')
        debugFrom = fromName.split('/')
        self.notify.debug(
            'handleEnterSphere gametime=%s %s into %s' %
            (self.getCurrentGameTime(), debugFrom[-1], debugInto[-1]))
        intoName = colEntry.getIntoNodePath().getName()
        if 'CogThiefSphere' in intoName:
            parts = intoName.split('-')
            suitNum = int(parts[1])
            self.localToonHitBySuit(suitNum)

    def localToonHitBySuit(self, suitNum):
        self.notify.debug('localToonHitBySuit %d' % suitNum)
        timestamp = globalClockDelta.localToNetworkTime(
            globalClock.getFrameTime(), bits=32)
        pos = self.cogInfo[suitNum]['suit'].suit.getPos()
        self.sendUpdate(
            'hitBySuit',
            [self.localAvId, timestamp, suitNum, pos[0], pos[1], pos[2]])
        self.showToonHitBySuit(self.localAvId, timestamp)
        self.makeSuitRespondToToonHit(timestamp, suitNum)

    def hitBySuit(self, avId, timestamp, suitNum, x, y, z):
        if not self.hasLocalToon:
            return
        if self.gameFSM.getCurrentState().getName() not in ['play']:
            self.notify.warning('ignoring msg: av %s hit by suit' % avId)
            return
        if self.gameIsEnding:
            return
        self.notify.debug('avatar ' + ` avId ` + ' hit by a suit')
        if avId != self.localAvId:
            self.showToonHitBySuit(avId, timestamp)
            self.makeSuitRespondToToonHit(timestamp, suitNum)

    def showToonHitBySuit(self, avId, timestamp):
        toon = self.getAvatar(avId)
        if toon == None:
            return
        rng = self.toonRNGs[self.avIdList.index(avId)]
        curPos = toon.getPos(render)
        oldTrack = self.toonHitTracks[avId]
        if oldTrack.isPlaying():
            oldTrack.finish()
        toon.setPos(curPos)
        toon.setZ(self.TOON_Z)
        parentNode = render.attachNewNode('mazeFlyToonParent-' + ` avId `)
        parentNode.setPos(toon.getPos())
        toon.reparentTo(parentNode)
        toon.setPos(0, 0, 0)
        startPos = parentNode.getPos()
        dropShadow = toon.dropShadow.copyTo(parentNode)
        dropShadow.setScale(toon.dropShadow.getScale(render))
        trajectory = Trajectory.Trajectory(0,
                                           Point3(0, 0, 0),
                                           Point3(0, 0, 50),
                                           gravMult=1.0)
        oldFlyDur = trajectory.calcTimeOfImpactOnPlane(0.0)
        trajectory = Trajectory.Trajectory(0,
                                           Point3(0, 0, 0),
                                           Point3(0, 0, 50),
                                           gravMult=0.55)
        flyDur = trajectory.calcTimeOfImpactOnPlane(0.0)
        avIndex = self.avIdList.index(avId)
        endPos = CTGG.ToonStartingPositions[avIndex]

        def flyFunc(t,
                    trajectory,
                    startPos=startPos,
                    endPos=endPos,
                    dur=flyDur,
                    moveNode=parentNode,
                    flyNode=toon):
            u = t / dur
            moveNode.setX(startPos[0] + u * (endPos[0] - startPos[0]))
            moveNode.setY(startPos[1] + u * (endPos[1] - startPos[1]))
            flyNode.setPos(trajectory.getPos(t))

        flyTrack = Sequence(LerpFunctionInterval(flyFunc,
                                                 fromData=0.0,
                                                 toData=flyDur,
                                                 duration=flyDur,
                                                 extraArgs=[trajectory]),
                            name=toon.uniqueName('hitBySuit-fly'))
        geomNode = toon.getGeomNode()
        startHpr = geomNode.getHpr()
        destHpr = Point3(startHpr)
        hRot = rng.randrange(1, 8)
        if rng.choice([0, 1]):
            hRot = -hRot
        destHpr.setX(destHpr[0] + hRot * 360)
        spinHTrack = Sequence(LerpHprInterval(geomNode,
                                              flyDur,
                                              destHpr,
                                              startHpr=startHpr),
                              Func(geomNode.setHpr, startHpr),
                              name=toon.uniqueName('hitBySuit-spinH'))
        parent = geomNode.getParent()
        rotNode = parent.attachNewNode('rotNode')
        geomNode.reparentTo(rotNode)
        rotNode.setZ(toon.getHeight() / 2.0)
        oldGeomNodeZ = geomNode.getZ()
        geomNode.setZ(-toon.getHeight() / 2.0)
        startHpr = rotNode.getHpr()
        destHpr = Point3(startHpr)
        pRot = rng.randrange(1, 3)
        if rng.choice([0, 1]):
            pRot = -pRot
        destHpr.setY(destHpr[1] + pRot * 360)
        spinPTrack = Sequence(LerpHprInterval(rotNode,
                                              flyDur,
                                              destHpr,
                                              startHpr=startHpr),
                              Func(rotNode.setHpr, startHpr),
                              name=toon.uniqueName('hitBySuit-spinP'))
        i = self.avIdList.index(avId)
        soundTrack = Sequence(Func(base.playSfx,
                                   self.sndTable['hitBySuit'][i]),
                              Wait(flyDur * (2.0 / 3.0)),
                              SoundInterval(self.sndTable['falling'][i],
                                            duration=flyDur * (1.0 / 3.0)),
                              name=toon.uniqueName('hitBySuit-soundTrack'))

        def preFunc(self=self, avId=avId, toon=toon, dropShadow=dropShadow):
            forwardSpeed = toon.forwardSpeed
            rotateSpeed = toon.rotateSpeed
            if avId == self.localAvId:
                self.stopGameWalk()
            else:
                toon.stopSmooth()
            if forwardSpeed or rotateSpeed:
                toon.setSpeed(forwardSpeed, rotateSpeed)
            toon.dropShadow.hide()

        def postFunc(self=self,
                     avId=avId,
                     oldGeomNodeZ=oldGeomNodeZ,
                     dropShadow=dropShadow,
                     parentNode=parentNode):
            if avId == self.localAvId:
                base.localAvatar.setPos(endPos)
                if hasattr(self, 'gameWalk'):
                    toon = base.localAvatar
                    toon.setSpeed(0, 0)
                    self.startGameWalk()
            dropShadow.removeNode()
            del dropShadow
            toon = self.getAvatar(avId)
            if toon:
                toon.dropShadow.show()
                geomNode = toon.getGeomNode()
                rotNode = geomNode.getParent()
                baseNode = rotNode.getParent()
                geomNode.reparentTo(baseNode)
                rotNode.removeNode()
                del rotNode
                geomNode.setZ(oldGeomNodeZ)
            if toon:
                toon.reparentTo(render)
                toon.setPos(endPos)
            parentNode.removeNode()
            del parentNode
            if avId != self.localAvId:
                if toon:
                    toon.startSmooth()

        preFunc()
        slipBack = Parallel(
            Sequence(ActorInterval(toon, 'slip-backward', endFrame=24),
                     Wait(CTGG.LyingDownDuration - (flyDur - oldFlyDur)),
                     ActorInterval(toon, 'slip-backward', startFrame=24)))
        if toon.doId == self.localAvId:
            slipBack.append(SoundInterval(self.sndOof))
        hitTrack = Sequence(Parallel(flyTrack, spinHTrack, spinPTrack,
                                     soundTrack),
                            slipBack,
                            Func(postFunc),
                            name=toon.uniqueName('hitBySuit'))
        self.notify.debug('hitTrack duration = %s' % hitTrack.getDuration())
        self.toonHitTracks[avId] = hitTrack
        hitTrack.start(globalClockDelta.localElapsedTime(timestamp))
        return

    def updateSuitGoal(self, timestamp, inResponseToClientStamp, suitNum,
                       goalType, goalId, x, y, z):
        if not self.hasLocalToon:
            return
        self.notify.debug(
            'updateSuitGoal gameTime=%s timeStamp=%s cog=%s goal=%s goalId=%s (%.1f, %.1f,%.1f)'
            % (self.getCurrentGameTime(), timestamp, suitNum,
               CTGG.GoalStr[goalType], goalId, x, y, z))
        cog = self.cogInfo[suitNum]
        cog['goal'] = goalType
        cog['goalId'] = goalId
        newPos = Point3(x, y, z)
        cog['pos'] = newPos
        suit = cog['suit']
        suit.updateGoal(timestamp, inResponseToClientStamp, goalType, goalId,
                        newPos)

    def spawnUpdateSuitsTask(self):
        self.notify.debug('spawnUpdateSuitsTask')
        for cogIndex in self.cogInfo:
            suit = self.cogInfo[cogIndex]['suit']
            suit.gameStart(self.gameStartTime)

        taskMgr.remove(self.UPDATE_SUITS_TASK)
        taskMgr.add(self.updateSuitsTask, self.UPDATE_SUITS_TASK)

    def removeUpdateSuitsTask(self):
        taskMgr.remove(self.UPDATE_SUITS_TASK)

    def updateSuitsTask(self, task):
        if self.gameIsEnding:
            return task.done
        for cogIndex in self.cogInfo:
            suit = self.cogInfo[cogIndex]['suit']
            suit.think()

        return task.cont

    def makeSuitRespondToToonHit(self, timestamp, suitNum):
        cog = self.cogInfo[suitNum]['suit']
        cog.respondToToonHit(timestamp)

    def handleEnterBarrel(self, colEntry):
        if self.gameIsEnding:
            return
        intoName = colEntry.getIntoNodePath().getName()
        fromName = colEntry.getFromNodePath().getName()
        debugInto = intoName.split('/')
        debugFrom = fromName.split('/')
        self.notify.debug(
            'handleEnterBarrel gameTime=%s %s into %s' %
            (self.getCurrentGameTime(), debugFrom[-1], debugInto[-1]))
        if 'CogThiefSphere' in intoName:
            parts = intoName.split('-')
            cogIndex = int(parts[1])
            barrelName = colEntry.getFromNodePath().getName()
            barrelParts = barrelName.split('-')
            barrelIndex = int(barrelParts[1])
            cog = self.cogInfo[cogIndex]['suit']
            if cog.barrel == CTGG.NoBarrelCarried and barrelIndex not in self.stolenBarrels:
                timestamp = globalClockDelta.localToNetworkTime(
                    globalClock.getFrameTime(), bits=32)
                if cog.suit:
                    cogPos = cog.suit.getPos()
                    collisionPos = colEntry.getContactPos(render)
                    if (cogPos - collisionPos).length() > 4:
                        import pdb
                        pdb.set_trace()
                    self.sendUpdate('cogHitBarrel', [
                        timestamp, cogIndex, barrelIndex, cogPos[0], cogPos[1],
                        cogPos[2]
                    ])

    def makeCogCarryBarrel(self, timestamp, inResponseToClientStamp, cogIndex,
                           barrelIndex, x, y, z):
        if not self.hasLocalToon:
            return
        if self.gameIsEnding:
            return
        self.notify.debug(
            'makeCogCarryBarrel gameTime=%s timeStamp=%s cog=%s barrel=%s (%.1f, %.1f,%.1f)'
            % (self.getCurrentGameTime(), timestamp, cogIndex, barrelIndex, x,
               y, z))
        barrel = self.barrels[barrelIndex]
        self.notify.debug('barrelPos= %s' % barrel.getPos())
        cog = self.cogInfo[cogIndex]['suit']
        cogPos = Point3(x, y, z)
        cog.makeCogCarryBarrel(timestamp, inResponseToClientStamp, barrel,
                               barrelIndex, cogPos)

    def makeCogDropBarrel(self, timestamp, inResponseToClientStamp, cogIndex,
                          barrelIndex, x, y, z):
        if not self.hasLocalToon:
            return
        self.notify.debug(
            'makeCogDropBarrel gameTime=%s timeStamp=%s cog=%s barrel=%s (%.1f, %.1f,%.1f)'
            % (self.getCurrentGameTime(), timestamp, cogIndex, barrelIndex, x,
               y, z))
        barrel = self.barrels[barrelIndex]
        self.notify.debug('barrelPos= %s' % barrel.getPos())
        cog = self.cogInfo[cogIndex]['suit']
        cogPos = Point3(x, y, z)
        cog.makeCogDropBarrel(timestamp, inResponseToClientStamp, barrel,
                              barrelIndex, cogPos)

    def controlKeyPressed(self):
        if self.isToonPlayingHitTrack(self.localAvId):
            return
        if self.gameIsEnding:
            return
        if self.getCurrentGameTime(
        ) - self.lastTimeControlPressed > self.ControlKeyLimitTime:
            self.lastTimeControlPressed = self.getCurrentGameTime()
            self.notify.debug('controlKeyPressed')
            toonSD = self.toonSDs[self.localAvId]
            curState = toonSD.fsm.getCurrentState().getName()
            toon = self.getAvatar(self.localAvId)
            timestamp = globalClockDelta.localToNetworkTime(
                globalClock.getFrameTime(), bits=32)
            pos = toon.getPos()
            heading = toon.getH()
            self.sendUpdate(
                'throwingPie',
                [self.localAvId, timestamp, heading, pos[0], pos[1], pos[2]])
            self.showToonThrowingPie(self.localAvId, timestamp, heading, pos)

    def throwingPie(self, avId, timestamp, heading, x, y, z):
        if not self.hasLocalToon:
            return
        if self.gameFSM.getCurrentState().getName() not in ['play']:
            self.notify.warning('ignoring msg: av %s hit by suit' % avId)
            return
        self.notify.debug('avatar ' + ` avId ` + ' throwing pie')
        if avId != self.localAvId:
            pos = Point3(x, y, z)
            self.showToonThrowingPie(avId, timestamp, heading, pos)

    def showToonThrowingPie(self, avId, timestamp, heading, pos):
        toon = self.getAvatar(avId)
        if toon:
            tossTrack, pieTrack, flyPie = self.getTossPieInterval(
                toon, pos[0], pos[1], pos[2], heading, 0, 0, 0)

            def removePieFromTraverser(flyPie=flyPie):
                if base.cTrav:
                    if flyPie:
                        base.cTrav.removeCollider(flyPie)

            if avId == self.localAvId:
                flyPie.setTag('throwerId', str(avId))
                collSphere = CollisionSphere(0, 0, 0, 0.5)
                collSphere.setTangible(0)
                name = 'PieSphere-%d' % avId
                collSphereName = self.uniqueName(name)
                collNode = CollisionNode(collSphereName)
                collNode.setFromCollideMask(ToontownGlobals.PieBitmask)
                collNode.addSolid(collSphere)
                colNp = flyPie.attachNewNode(collNode)
                colNp.show()
                base.cTrav.addCollider(colNp, self.pieHandler)
                self.accept('pieHit-' + collSphereName, self.handlePieHitting)

            def matchRunningAnim(toon=toon):
                toon.playingAnim = None
                toon.setSpeed(toon.forwardSpeed, toon.rotateSpeed)
                return

            newTossTrack = Sequence(tossTrack, Func(matchRunningAnim))
            pieTrack = Parallel(newTossTrack, pieTrack)
            elapsedTime = globalClockDelta.localElapsedTime(timestamp)
            if elapsedTime < 16.0 / 24.0:
                elapsedTime = 16.0 / 24.0
            pieTrack.start(elapsedTime)
            self.toonPieTracks[avId] = pieTrack

    def getTossPieInterval(self,
                           toon,
                           x,
                           y,
                           z,
                           h,
                           p,
                           r,
                           power,
                           beginFlyIval=Sequence()):
        from toontown.toonbase import ToontownBattleGlobals
        from toontown.battle import BattleProps
        pie = toon.getPieModel()
        pie.setScale(0.9)
        flyPie = pie.copyTo(NodePath('a'))
        pieName = ToontownBattleGlobals.pieNames[toon.pieType]
        pieType = BattleProps.globalPropPool.getPropType(pieName)
        animPie = Sequence()
        if pieType == 'actor':
            animPie = ActorInterval(pie, pieName, startFrame=48)
        sound = loader.loadSfx('phase_3.5/audio/sfx/AA_pie_throw_only.ogg')
        t = power / 100.0
        dist = 100 - 70 * t
        time = 1 + 0.5 * t
        proj = ProjectileInterval(None,
                                  startPos=Point3(0, 0, 0),
                                  endPos=Point3(0, dist, 0),
                                  duration=time)
        relVel = proj.startVel

        def getVelocity(toon=toon, relVel=relVel):
            return render.getRelativeVector(toon, relVel) * 0.6

        toss = Track(
            (0,
             Sequence(
                 Func(toon.setPosHpr, x, y, z, h, p, r),
                 Func(pie.reparentTo, toon.rightHand),
                 Func(pie.setPosHpr, 0, 0, 0, 0, 0, 0),
                 Parallel(
                     ActorInterval(
                         toon, 'throw', startFrame=48, partName='torso'),
                     animPie), Func(toon.loop, 'neutral'))),
            (16.0 / 24.0, Func(pie.detachNode)))
        fly = Track(
            (14.0 / 24.0, SoundInterval(sound, node=toon)),
            (16.0 / 24.0,
             Sequence(
                 Func(flyPie.reparentTo, render),
                 Func(flyPie.setPosHpr, toon, 0.52, 0.97, 2.24, 0, -45, 0),
                 beginFlyIval,
                 ProjectileInterval(flyPie, startVel=getVelocity, duration=6),
                 Func(flyPie.detachNode))))
        return (toss, fly, flyPie)

    def handlePieHitting(self, colEntry):
        if self.gameIsEnding:
            return
        into = colEntry.getIntoNodePath()
        intoName = into.getName()
        if 'CogThiefPieSphere' in intoName:
            timestamp = globalClockDelta.localToNetworkTime(
                globalClock.getFrameTime(), bits=32)
            parts = intoName.split('-')
            suitNum = int(parts[1])
            pos = self.cogInfo[suitNum]['suit'].suit.getPos()
            if pos in CTGG.CogStartingPositions:
                self.notify.debug('Cog %d hit at starting pos %s, ignoring' %
                                  (suitNum, pos))
            else:
                self.sendUpdate('pieHitSuit', [
                    self.localAvId, timestamp, suitNum, pos[0], pos[1], pos[2]
                ])
                self.makeSuitRespondToPieHit(timestamp, suitNum)

    def pieHitSuit(self, avId, timestamp, suitNum, x, y, z):
        if not self.hasLocalToon:
            return
        if self.gameFSM.getCurrentState().getName() not in ['play']:
            self.notify.warning('ignoring msg: av %s hit by suit' % avId)
            return
        if self.gameIsEnding:
            return
        self.notify.debug('avatar ' + ` avId ` + ' hit by a suit')
        if avId != self.localAvId:
            self.makeSuitRespondToPieHit(timestamp, suitNum)

    def makeSuitRespondToPieHit(self, timestamp, suitNum):
        cog = self.cogInfo[suitNum]['suit']
        cog.respondToPieHit(timestamp)

    def sendCogAtReturnPos(self, cogIndex, barrelIndex):
        timestamp = globalClockDelta.localToNetworkTime(
            globalClock.getFrameTime(), bits=32)
        self.sendUpdate('cogAtReturnPos', [timestamp, cogIndex, barrelIndex])

    def markBarrelStolen(self, timestamp, inResponseToClientStamp,
                         barrelIndex):
        if not self.hasLocalToon:
            return
        if barrelIndex not in self.stolenBarrels:
            self.stolenBarrels.append(barrelIndex)
            barrel = self.barrels[barrelIndex]
            barrel.hide()
        if base.config.GetBool('cog-thief-check-barrels', 1):
            if not base.config.GetBool('cog-thief-endless', 0):
                if len(self.stolenBarrels) == len(self.barrels):
                    localStamp = globalClockDelta.networkToLocalTime(timestamp,
                                                                     bits=32)
                    gameTime = self.local2GameTime(localStamp)
                    self.clockStopTime = gameTime
                    self.notify.debug('clockStopTime = %s' % gameTime)
                    score = int(self.scoreMult * CTGG.calcScore(gameTime) +
                                0.5)
                    self.rewardPanel['text'] = str(score)
                    self.showResults()

    def __gameTimerExpired(self):
        self.notify.debug('game timer expired')
        self.showResults()

    def __startRewardCountdown(self):
        taskMgr.remove(self.REWARD_COUNTDOWN_TASK)
        taskMgr.add(self.__updateRewardCountdown, self.REWARD_COUNTDOWN_TASK)

    def __killRewardCountdown(self):
        taskMgr.remove(self.REWARD_COUNTDOWN_TASK)

    def __updateRewardCountdown(self, task):
        curTime = self.getCurrentGameTime()
        if self.clockStopTime is not None:
            if self.clockStopTime < curTime:
                self.notify.debug('self.clockStopTime < curTime %s %s' %
                                  (self.clockStopTime, curTime))
                self.__killRewardCountdown()
                curTime = self.clockStopTime
        if curTime > CTGG.GameTime:
            curTime = CTGG.GameTime
        score = int(self.scoreMult * CTGG.calcScore(curTime) + 0.5)
        if not hasattr(task, 'curScore'):
            task.curScore = score
        result = Task.cont
        if hasattr(self, 'rewardPanel'):
            self.rewardPanel['text'] = str(score)
            if task.curScore != score:
                if hasattr(self, 'jarIval'):
                    self.jarIval.finish()
                s = self.rewardPanel.getScale()
                self.jarIval = Parallel(Sequence(
                    self.rewardPanel.scaleInterval(0.15,
                                                   s * 3.0 / 4.0,
                                                   blendType='easeOut'),
                    self.rewardPanel.scaleInterval(0.15, s,
                                                   blendType='easeIn')),
                                        SoundInterval(self.sndRewardTick),
                                        name='cogThiefGameRewardJarThrob')
                self.jarIval.start()
            task.curScore = score
        else:
            result = Task.done
        return result

    def startGameWalk(self):
        if self.useOrthoWalk:
            self.gameWalk.start()
        else:
            self.gameWalk.enter()
            self.gameWalk.fsm.request('walking')

    def stopGameWalk(self):
        if self.useOrthoWalk:
            self.gameWalk.stop()
        else:
            self.gameWalk.exit()

    def getCogThief(self, cogIndex):
        return self.cogInfo[cogIndex]['suit']

    def isToonPlayingHitTrack(self, avId):
        if avId in self.toonHitTracks:
            track = self.toonHitTracks[avId]
            if track.isPlaying():
                return True
        return False

    def getNumCogs(self):
        result = base.config.GetInt('cog-thief-num-cogs', 0)
        if not result:
            safezone = self.getSafezoneId()
            result = CTGG.calculateCogs(self.numPlayers, safezone)
        return result

    def getCogSpeed(self):
        result = 6.0
        safezone = self.getSafezoneId()
        result = CTGG.calculateCogSpeed(self.numPlayers, safezone)
        return result

    def showResults(self):
        if not self.gameIsEnding:
            self.gameIsEnding = True
            for barrel in self.barrels:
                barrel.wrtReparentTo(render)

            for key in self.cogInfo:
                thief = self.cogInfo[key]['suit']
                thief.suit.setPos(100, 0, 0)
                thief.suit.hide()

            self.__killRewardCountdown()
            self.stopGameWalk()
            numBarrelsSaved = len(self.barrels) - len(self.stolenBarrels)
            resultStr = ''
            if numBarrelsSaved == len(self.barrels):
                resultStr = TTLocalizer.CogThiefPerfect
            elif numBarrelsSaved > 1:
                resultStr = TTLocalizer.CogThiefBarrelsSaved % {
                    'num': numBarrelsSaved
                }
            elif numBarrelsSaved == 1:
                resultStr = TTLocalizer.CogThiefBarrelSaved % {
                    'num': numBarrelsSaved
                }
            else:
                resultStr = TTLocalizer.CogThiefNoBarrelsSaved
            perfectTextSubnode = hidden.attachNewNode(
                self.__genText(resultStr))
            perfectText = hidden.attachNewNode('perfectText')
            perfectTextSubnode.reparentTo(perfectText)
            frame = self.__textGen.getCardActual()
            offsetY = -abs(frame[2] + frame[3]) / 2.0
            perfectTextSubnode.setPos(0, 0, offsetY)
            perfectText.setColor(1, 0.1, 0.1, 1)

            def fadeFunc(t, text=perfectText):
                text.setColorScale(1, 1, 1, t)

            def destroyText(text=perfectText):
                text.removeNode()

            def safeGameOver(self=self):
                if not self.frameworkFSM.isInternalStateInFlux():
                    self.gameOver()

            textTrack = Sequence(
                Func(perfectText.reparentTo, aspect2d),
                Parallel(
                    LerpScaleInterval(perfectText,
                                      duration=0.5,
                                      scale=0.3,
                                      startScale=0.0),
                    LerpFunctionInterval(fadeFunc,
                                         fromData=0.0,
                                         toData=1.0,
                                         duration=0.5)), Wait(2.0),
                Parallel(
                    LerpScaleInterval(perfectText, duration=0.5, scale=1.0),
                    LerpFunctionInterval(fadeFunc,
                                         fromData=1.0,
                                         toData=0.0,
                                         duration=0.5,
                                         blendType='easeIn')),
                Func(destroyText), WaitInterval(0.5), Func(safeGameOver))
            if numBarrelsSaved == len(self.barrels):
                soundTrack = SoundInterval(self.sndPerfect)
            else:
                soundTrack = Sequence()
            self.resultIval = Parallel(textTrack, soundTrack)
            self.resultIval.start()

    def __genText(self, text):
        self.__textGen.setText(text)
        return self.__textGen.generate()

    def getIntroTrack(self):
        base.camera.setPosHpr(0, -13.66, 13.59, 0, -51.6, 0)
        result = Sequence(
            Wait(2),
            LerpPosHprInterval(base.camera,
                               13,
                               Point3(self.cameraTopView[0],
                                      self.cameraTopView[1],
                                      self.cameraTopView[2]),
                               Point3(self.cameraTopView[3],
                                      self.cameraTopView[4],
                                      self.cameraTopView[5]),
                               blendType='easeIn'))
        return result
class DistributedPieTurret(DistributedAvatar, DistributedSmoothNode):
    notify = directNotify.newCategory('DistributedPieTurret')

    def __init__(self, cr):
        DistributedAvatar.__init__(self, cr)
        DistributedSmoothNode.__init__(self, cr)
        self.fsm = ClassicFSM(
            'DistributedPieTurret',
            [
                State('off', self.enterOff, self.exitOff),
                State('scan', self.enterScan, self.exitScan),
                State('shoot', self.enterShoot, self.exitShoot)
             ],
             'off', 'off'
         )
        self.fsm.enterInitialState()
        self.reloadTime = 0.25
        self.cannon = None
        self.track = None
        self.owner = None
        self.gag = None
        self.readyGag = None
        self.hitGag = None
        self.explosion = None
        self.wallCollNode = None
        self.eventCollNode = None
        self.event = None
        self.suit = None
        self.eventId = None
        self.entities = []
        self.upgradeID = None
        self.deathEvent = None

    def setOwner(self, avatar):
        self.owner = avatar

    def getOwner(self):
        return self.owner

    def setGag(self, upgradeId):
        gags = {0 : CIGlobals.WholeCreamPie, 1 : CIGlobals.WholeFruitPie, 2 : CIGlobals.BirthdayCake, 3 : CIGlobals.WeddingCake}
        self.gag = gags.get(upgradeId)
        if not self.readyGag:
            self.loadGagInTurret()

    def b_setGag(self, upgradeId):
        self.sendUpdate('setGag', [upgradeId])
        self.setGag(upgradeId)
        self.upgradeID = upgradeId

    def getGag(self):
        return self.gag

    def getGagID(self):
        return self.upgradeID

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

    def announceGenerate(self):
        DistributedAvatar.announceGenerate(self)
        DistributedSmoothNode.announceGenerate(self)
        self.healthLabel.setScale(1.1)
        self.deathEvent = self.uniqueName('DistributedPieTurret-death')
        self.makeTurret()

    def disable(self):
        self.fsm.requestFinalState()
        del self.fsm

        # This should fix crashes related to Sequences.
        if self.track:
            self.track.pause()
            self.track = None

        # Cleanup entities.
        for ent in self.entities:
            ent.cleanup()
        self.entities = None

        # Get rid of explosions.
        if self.explosion:
            self.explosion.removeNode()
            self.explosion = None

        self.removeTurret()
        DistributedSmoothNode.disable(self)
        DistributedAvatar.disable(self)

    def showAndMoveHealthLabel(self):
        self.unstashHpLabel()
        self.stopMovingHealthLabel()
        moveTrack = LerpPosInterval(self.healthLabel,
                                duration = 0.5,
                                pos = Point3(0, 0, 5),
                                startPos = Point3(0, 0, 0),
                                blendType = 'easeOut')
        self.healthLabelTrack = Sequence(moveTrack, Wait(1.0), Func(self.stashHpLabel))
        self.healthLabelTrack.start()

    # BEGIN STATES

    def enterShoot(self, suitId):
        if self.cannon:
            smoke = loader.loadModel("phase_4/models/props/test_clouds.bam")
            smoke.setBillboardPointEye()
            smoke.reparentTo(self.cannon.find('**/cannon'))
            smoke.setPos(0, 6, -3)
            smoke.setScale(0.5)
            smoke.wrtReparentTo(render)
            self.suit = self.cr.doId2do.get(suitId)
            self.cannon.find('**/cannon').lookAt(self.suit.find('**/joint_head'))
            self.cannon.find('**/square_drop_shadow').headsUp(self.suit.find('**/joint_head'))
            self.track = Sequence(Parallel(LerpScaleInterval(smoke, 0.5, 3), LerpColorScaleInterval(smoke, 0.5, Vec4(2, 2, 2, 0))), Func(smoke.removeNode))
            self.track.start()
            self.createAndShootGag()

    def exitShoot(self):
        if hasattr(self, 'suit'):
            del self.suit

    def shoot(self, suitId):
        self.fsm.request('shoot', [suitId])

    def scan(self, timestamp = None, afterShooting = 0):
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)

        self.fsm.request('scan', [ts, afterShooting])
        
    def buildScanTrack(self, ts = None):
        if self.track:
            self.track.pause()
            self.track = None
        self.track = Parallel(
            Sequence(
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (60, 0, 0),
                    startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
                    startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
            ),
            Sequence(
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (60, 0, 0),
                    startHpr = Vec3(-60, 0, 0), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
                    startHpr = Vec3(60, 0, 0), blendType = 'easeInOut'),
            )
        )
        if ts:
            self.track.loop(ts)
        else:
            self.track.loop()

    def enterScan(self, ts = 0, afterShooting = 0):
        if afterShooting:
            self.track = Parallel(
                LerpQuatInterval(self.cannon.find('**/cannon'), duration = 3, quat = (-60, 0, 0),
                    startHpr = self.cannon.find('**/cannon').getHpr(), blendType = 'easeInOut'),
                LerpQuatInterval(self.cannon.find('**/square_drop_shadow'), duration = 3, quat = (-60, 0, 0),
                    startHpr = self.cannon.find('**/square_drop_shadow').getHpr(), blendType = 'easeInOut'),
                name = "afterShootTrack" + str(id(self))
            )
            self.track.setDoneEvent(self.track.getName())
            self.acceptOnce(self.track.getDoneEvent(), self._afterShootTrackDone)
            self.track.start(ts)
        else:
            self.buildScanTrack(ts)

    def exitScan(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    # END STATES

    def _afterShootTrackDone(self):
        self.buildScanTrack()

    def makeTurret(self):
        self.cannon = loader.loadModel('phase_4/models/minigames/toon_cannon.bam')
        self.cannon.reparentTo(self)
        self.loadGagInTurret()
        self.setupWallSphere()
        if self.isLocal():
            self.setupEventSphere()

    def removeTurret(self):
        self.removeWallSphere()
        self.removeGagInTurret()
        if self.cannon:
            self.cannon.removeNode()
            self.cannon = None

    def getCannon(self):
        return self.cannon.find('**/cannon')

    def setupWallSphere(self):
        sphere = CollisionSphere(0.0, 0.0, 0.0, 3.0)
        node = CollisionNode('DistributedPieTurret.WallSphere')
        node.addSolid(sphere)
        node.setCollideMask(CIGlobals.WallBitmask)
        self.wallCollNode = self.cannon.attachNewNode(node)
        self.wallCollNode.setZ(2)
        self.wallCollNode.setY(1.0)

    def removeWallSphere(self):
        if self.wallCollNode:
            self.wallCollNode.removeNode()
            self.wallCollNode = None

    def createAndShootGag(self):
        if not self.readyGag:
            self.loadGagInTurret()
        if self.readyGag:
            self.readyGag.shoot(Point3(0, 200, -90))
            self.entities.append(self.readyGag)
            collideEventName = self.readyGag.getCollideEventName()
            self.readyGag = None
            if self.isLocal():
                self.acceptOnce(collideEventName, self.handleGagCollision)
        Sequence(Wait(self.reloadTime), Func(self.loadGagInTurret)).start()

    def loadGagInTurret(self):
        if self.cannon and self.gag:
            self.removeGagInTurret()
            self.eventId = random.uniform(0, 100000000)
            self.readyGag = TurretGag(self, self.uniqueName('pieTurretCollision') + str(self.eventId), self.gag)
            self.readyGag.build()

    def removeGagInTurret(self):
        if self.readyGag:
            self.readyGag.cleanup()
            self.readyGag = None

    def makeSplat(self, index, pos):
        if index >= len(self.entities):
            return
        ent = self.entities[index]
        gagClass = ent.gagClass
        splat = gagClass.buildSplat(gagClass.splatScale, gagClass.splatColor)
        base.audio3d.attachSoundToObject(gagClass.hitSfx, splat)
        splat.reparentTo(render)
        splat.setPos(pos[0], pos[1], pos[2])
        gagClass.hitSfx.play()
        Sequence(Wait(0.5), Func(splat.cleanup)).start()
        self.hitGag = None

    def d_makeSplat(self, index, pos):
        self.sendUpdate('makeSplat', [index, pos])

    def b_makeSplat(self, index, pos):
        self.d_makeSplat(index, pos)
        self.makeSplat(index, pos)

    def handleGagCollision(self, entry, ent):
        x, y, z = ent.getGag().getPos(render)
        self.b_makeSplat(self.entities.index(ent), [x, y, z])
        if self.isLocal():
            intoNP = entry.getIntoNodePath()
            avNP = intoNP.getParent()
            for key in self.cr.doId2do.keys():
                obj = self.cr.doId2do[key]
                if obj.__class__.__name__ == 'DistributedSuit':
                    if obj.getKey() == avNP.getKey():
                        if obj.getHealth() > 0:
                            obj.sendUpdate('hitByGag', [ent.getID()])
        ent.cleanup()

    def setHealth(self, hp):
        DistributedAvatar.setHealth(self, hp)
        if self.isLocal():
            base.localAvatar.getMyBattle().getTurretManager().updateTurretGui()

    def die(self):
        self.fsm.requestFinalState()
        turretPos = self.cannon.getPos(render)
        self.removeTurret()
        self.explosion = loader.loadModel("phase_3.5/models/props/explosion.bam")
        self.explosion.setScale(0.5)
        self.explosion.reparentTo(render)
        self.explosion.setBillboardPointEye()
        self.explosion.setPos(turretPos + (0, 0, 5))
        sfx = base.audio3d.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.ogg")
        base.audio3d.attachSoundToObject(sfx, self)
        base.playSfx(sfx)
        messenger.send(self.deathEvent)

    def isLocal(self):
        return self.getOwner() == base.localAvatar.doId

    def getDeathEvent(self):
        return self.deathEvent
Example #50
0
    def showToonHitBySuit(self, avId, timestamp):
        toon = self.getAvatar(avId)
        if toon == None:
            return
        rng = self.toonRNGs[self.avIdList.index(avId)]
        curPos = toon.getPos(render)
        oldTrack = self.toonHitTracks[avId]
        if oldTrack.isPlaying():
            oldTrack.finish()
        toon.setPos(curPos)
        toon.setZ(self.TOON_Z)
        parentNode = render.attachNewNode('mazeFlyToonParent-' + ` avId `)
        parentNode.setPos(toon.getPos())
        toon.reparentTo(parentNode)
        toon.setPos(0, 0, 0)
        startPos = parentNode.getPos()
        dropShadow = toon.dropShadow.copyTo(parentNode)
        dropShadow.setScale(toon.dropShadow.getScale(render))
        trajectory = Trajectory.Trajectory(0,
                                           Point3(0, 0, 0),
                                           Point3(0, 0, 50),
                                           gravMult=1.0)
        oldFlyDur = trajectory.calcTimeOfImpactOnPlane(0.0)
        trajectory = Trajectory.Trajectory(0,
                                           Point3(0, 0, 0),
                                           Point3(0, 0, 50),
                                           gravMult=0.55)
        flyDur = trajectory.calcTimeOfImpactOnPlane(0.0)
        avIndex = self.avIdList.index(avId)
        endPos = CTGG.ToonStartingPositions[avIndex]

        def flyFunc(t,
                    trajectory,
                    startPos=startPos,
                    endPos=endPos,
                    dur=flyDur,
                    moveNode=parentNode,
                    flyNode=toon):
            u = t / dur
            moveNode.setX(startPos[0] + u * (endPos[0] - startPos[0]))
            moveNode.setY(startPos[1] + u * (endPos[1] - startPos[1]))
            flyNode.setPos(trajectory.getPos(t))

        flyTrack = Sequence(LerpFunctionInterval(flyFunc,
                                                 fromData=0.0,
                                                 toData=flyDur,
                                                 duration=flyDur,
                                                 extraArgs=[trajectory]),
                            name=toon.uniqueName('hitBySuit-fly'))
        geomNode = toon.getGeomNode()
        startHpr = geomNode.getHpr()
        destHpr = Point3(startHpr)
        hRot = rng.randrange(1, 8)
        if rng.choice([0, 1]):
            hRot = -hRot
        destHpr.setX(destHpr[0] + hRot * 360)
        spinHTrack = Sequence(LerpHprInterval(geomNode,
                                              flyDur,
                                              destHpr,
                                              startHpr=startHpr),
                              Func(geomNode.setHpr, startHpr),
                              name=toon.uniqueName('hitBySuit-spinH'))
        parent = geomNode.getParent()
        rotNode = parent.attachNewNode('rotNode')
        geomNode.reparentTo(rotNode)
        rotNode.setZ(toon.getHeight() / 2.0)
        oldGeomNodeZ = geomNode.getZ()
        geomNode.setZ(-toon.getHeight() / 2.0)
        startHpr = rotNode.getHpr()
        destHpr = Point3(startHpr)
        pRot = rng.randrange(1, 3)
        if rng.choice([0, 1]):
            pRot = -pRot
        destHpr.setY(destHpr[1] + pRot * 360)
        spinPTrack = Sequence(LerpHprInterval(rotNode,
                                              flyDur,
                                              destHpr,
                                              startHpr=startHpr),
                              Func(rotNode.setHpr, startHpr),
                              name=toon.uniqueName('hitBySuit-spinP'))
        i = self.avIdList.index(avId)
        soundTrack = Sequence(Func(base.playSfx,
                                   self.sndTable['hitBySuit'][i]),
                              Wait(flyDur * (2.0 / 3.0)),
                              SoundInterval(self.sndTable['falling'][i],
                                            duration=flyDur * (1.0 / 3.0)),
                              name=toon.uniqueName('hitBySuit-soundTrack'))

        def preFunc(self=self, avId=avId, toon=toon, dropShadow=dropShadow):
            forwardSpeed = toon.forwardSpeed
            rotateSpeed = toon.rotateSpeed
            if avId == self.localAvId:
                self.stopGameWalk()
            else:
                toon.stopSmooth()
            if forwardSpeed or rotateSpeed:
                toon.setSpeed(forwardSpeed, rotateSpeed)
            toon.dropShadow.hide()

        def postFunc(self=self,
                     avId=avId,
                     oldGeomNodeZ=oldGeomNodeZ,
                     dropShadow=dropShadow,
                     parentNode=parentNode):
            if avId == self.localAvId:
                base.localAvatar.setPos(endPos)
                if hasattr(self, 'gameWalk'):
                    toon = base.localAvatar
                    toon.setSpeed(0, 0)
                    self.startGameWalk()
            dropShadow.removeNode()
            del dropShadow
            toon = self.getAvatar(avId)
            if toon:
                toon.dropShadow.show()
                geomNode = toon.getGeomNode()
                rotNode = geomNode.getParent()
                baseNode = rotNode.getParent()
                geomNode.reparentTo(baseNode)
                rotNode.removeNode()
                del rotNode
                geomNode.setZ(oldGeomNodeZ)
            if toon:
                toon.reparentTo(render)
                toon.setPos(endPos)
            parentNode.removeNode()
            del parentNode
            if avId != self.localAvId:
                if toon:
                    toon.startSmooth()

        preFunc()
        slipBack = Parallel(
            Sequence(ActorInterval(toon, 'slip-backward', endFrame=24),
                     Wait(CTGG.LyingDownDuration - (flyDur - oldFlyDur)),
                     ActorInterval(toon, 'slip-backward', startFrame=24)))
        if toon.doId == self.localAvId:
            slipBack.append(SoundInterval(self.sndOof))
        hitTrack = Sequence(Parallel(flyTrack, spinHTrack, spinPTrack,
                                     soundTrack),
                            slipBack,
                            Func(postFunc),
                            name=toon.uniqueName('hitBySuit'))
        self.notify.debug('hitTrack duration = %s' % hitTrack.getDuration())
        self.toonHitTracks[avId] = hitTrack
        hitTrack.start(globalClockDelta.localElapsedTime(timestamp))
        return
Example #51
0
class DistributedPartyGate(DistributedObject.DistributedObject):

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

    def __init__(self, cr):
        """__init__(cr)
        """
        DistributedObject.DistributedObject.__init__(self, cr)
        self.publicPartyChooseGuiDoneEvent = "doneChoosingPublicParty"
        self.publicPartyGui = PublicPartyGui(
            self.publicPartyChooseGuiDoneEvent)
        self.publicPartyGui.stash()
        self.loadClockSounds()
        self.hourSoundInterval = Sequence()
        self.accept('stoppedAsleep', self.handleSleep)

    def loadClockSounds(self):
        self.clockSounds = []
        for i in range(1, 13):
            if i < 10:
                si = "0%d" % i
            else:
                si = "%d" % i
            self.clockSounds.append(
                base.loader.loadSfx("phase_4/audio/sfx/clock%s.mp3" % si))

    def generate(self):
        """generate(self)
        This method is called when the DistributedObject is reintroduced
        to the world, either for the first time or from the cache.
        """
        DistributedObject.DistributedObject.generate(self)

        loader = self.cr.playGame.hood.loader
        partyGate = loader.geom.find('**/partyGate_grp')
        if partyGate.isEmpty():
            self.notify.warning('Could not find partyGate_grp in loader.geom')
            return
        self.clockFlat = partyGate.find("**/clock_flat")
        collSphere = CollisionSphere(0, 0, 0, 6.9)
        collSphere.setTangible(1)
        self.partyGateSphere = CollisionNode("PartyGateSphere")
        self.partyGateSphere.addSolid(collSphere)
        self.partyGateCollNodePath = partyGate.find(
            "**/partyGate_stepsLocator").attachNewNode(self.partyGateSphere)
        self.__enableCollisions()
        #        self.tunnelOrigin = NodePath("PartyGateTunnelOrigin")
        #        self.tunnelOrigin.reparentTo(partyGate)
        #        self.tunnelOrigin.setPos(partyGate.find("**/clockText_locator").getPos() + Point3(0.0, 0.0, -12.0))

        self.toontownTimeGui = ServerTimeGui(partyGate,
                                             hourCallback=self.hourChange)
        self.toontownTimeGui.setPos(
            partyGate.find("**/clockText_locator").getPos() +
            Point3(0.0, 0.0, -0.2))
        self.toontownTimeGui.setHpr(
            partyGate.find("**/clockText_locator").getHpr())
        self.toontownTimeGui.setScale(12.0, 1.0, 26.0)
        self.toontownTimeGui.amLabel.setPos(-0.035, 0, -0.032)
        self.toontownTimeGui.amLabel.setScale(0.5)
        self.toontownTimeGui.updateTime()
        self.setupSignText()

    def setupSignText(self):
        """Attach text to the left and right signs"""
        loader = self.cr.playGame.hood.loader
        partyGate = loader.geom.find('**/partyGateSignGroup')
        if partyGate.isEmpty():
            self.notify.warning('Could not find partyGate_grp in loader.geom')
            return
        gateFont = ToontownGlobals.getMinnieFont()
        leftSign = partyGate.find("**/signTextL_locatorBack")
        signScale = 0.35
        wordWrap = 8
        leftText = DirectLabel.DirectLabel(
            parent=leftSign,
            pos=(0, 0.0, 0.0),
            relief=None,
            text=TTLocalizer.PartyGateLeftSign,
            text_align=TextNode.ACenter,
            text_font=gateFont,
            text_wordwrap=wordWrap,
            text_fg=Vec4(0.7, 0.3, 0.3, 1.0),
            scale=signScale,
        )
        rightSign = partyGate.find("**/signTextR_locatorFront")
        rightText = DirectLabel.DirectLabel(
            parent=rightSign,
            pos=(0, 0.0, 0.0),
            relief=None,
            text=TTLocalizer.PartyGateRightSign,
            text_align=TextNode.ACenter,
            text_font=gateFont,
            text_wordwrap=wordWrap,
            text_fg=Vec4(0.7, 0.3, 0.3, 1.0),
            scale=signScale,
        )

    def announceGenerate(self):
        DistributedObject.DistributedObject.announceGenerate(self)
        if self.zoneId in ToontownGlobals.dnaMap:
            playground = ToontownGlobals.dnaMap[self.zoneId]
        else:
            playground = ToontownGlobals.dnaMap[2000]
        self.toontownTimeGui.hourLabel[
            "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground]
        self.toontownTimeGui.colonLabel[
            "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground]
        self.toontownTimeGui.minutesLabel[
            "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground]
        self.toontownTimeGui.amLabel[
            "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground]

    def disable(self):
        DistributedObject.DistributedObject.disable(self)
        self.__disableCollisions()
        self.toontownTimeGui.ival.finish()
        self.hourSoundInterval.finish()
        if self.publicPartyGui:
            self.publicPartyGui.stash()
            self.publicPartyGui.destroy()
            self.publicPartyGui = None

    def delete(self):
        DistributedObject.DistributedObject.delete(self)
        self.toontownTimeGui.destroy()
        del self.toontownTimeGui
        self.hourSoundInterval.finish()
        del self.hourSoundInterval
        del self.clockFlat
        if self.publicPartyGui:
            self.publicPartyGui.destroy()
            del self.publicPartyGui
        self.partyGateCollNodePath.removeNode()
        del self.partyGateCollNodePath
        self.ignoreAll()

    def showMessage(self, message):
        self.messageDoneEvent = self.uniqueName("messageDoneEvent")
        self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone)
        self.messageGui = TTDialog.TTGlobalDialog(
            doneEvent=self.messageDoneEvent,
            message=message,
            style=TTDialog.Acknowledge,
        )

    def __handleMessageDone(self):
        self.ignore(self.messageDoneEvent)
        self.freeAvatar()
        self.messageGui.cleanup()
        self.messageGui = None

    def __handleAskDone(self):
        DistributedPartyGate.notify.debug("__handleAskDone")
        self.ignore(self.publicPartyChooseGuiDoneEvent)
        doneStatus = self.publicPartyGui.doneStatus
        self.publicPartyGui.stash()
        if doneStatus is None:
            # They don't want to party... just let them walk away from the hat
            self.freeAvatar()
            return
        self.sendUpdate("partyChoiceRequest",
                        [base.localAvatar.doId, doneStatus[0], doneStatus[1]])

    def partyRequestDenied(self, reason):
        """
        Called by the AI when the player's request to join a public party was denied.
        """
        DistributedPartyGate.notify.debug(
            "partyRequestDenied( reason=%s )" %
            PartyGlobals.PartyGateDenialReasons.getString(reason))
        # let the local toon know that they were denied
        # TODO-parties: tell player through gui
        if reason == PartyGlobals.PartyGateDenialReasons.Unavailable:
            self.showMessage(TTLocalizer.PartyGatePartyUnavailable)
        elif reason == PartyGlobals.PartyGateDenialReasons.Full:
            self.showMessage(TTLocalizer.PartyGatePartyFull)

    def setParty(self, partyInfoTuple):
        """
        Gets called by the AI server with the approved partyId.
        """
        DistributedPartyGate.notify.debug("setParty")

        self.freeAvatar()
        if partyInfoTuple[0] == 0:
            DistributedPartyGate.notify.debug(
                "Public Party closed before toon could get to it.")
            return

        # We now need to enter the party with the given partyId, that is, move
        # our toon toward the hat entrance and do the appropriate state transition
        shardId, zoneId, numberOfGuests, hostName, activityIds, lane = partyInfoTuple
        if base.localAvatar.defaultShard == shardId:
            shardId = None
        base.cr.playGame.getPlace().requestLeave({
            "loader": "safeZoneLoader",
            "where": "party",
            "how": "teleportIn",
            "hoodId": ToontownGlobals.PartyHood,
            "zoneId": zoneId,
            "shardId": shardId,
            "avId": -1,
            #            "partyHat" : True,
            #            "tunnelOrigin" : self.tunnelOrigin,
        })

    def freeAvatar(self):
        base.localAvatar.posCamera(0, 0)
        base.cr.playGame.getPlace().setState("walk")

    def hourChange(self, currentHour):
        currentHour = currentHour % 12
        if currentHour == 0:
            currentHour = 12
        self.hourSoundInterval = Parallel()
        # Make a sequence with all the clock sounds
        seq1 = Sequence()
        for i in range(currentHour):
            seq1.append(SoundInterval(self.clockSounds[i]))
            seq1.append(Wait(0.2))
        # Now make a sequence that will deform the clock face
        timeForEachDeformation = seq1.getDuration() / currentHour
        seq2 = Sequence()
        for i in range(currentHour):
            seq2.append(
                self.clockFlat.scaleInterval(timeForEachDeformation / 2.0,
                                             Vec3(0.9, 1.0, 1.2),
                                             blendType='easeInOut'))
            seq2.append(
                self.clockFlat.scaleInterval(timeForEachDeformation / 2.0,
                                             Vec3(1.2, 1.0, 0.9),
                                             blendType='easeInOut'))
        seq2.append(
            self.clockFlat.scaleInterval(timeForEachDeformation / 2.0,
                                         Vec3(1.0, 1.0, 1.0),
                                         blendType='easeInOut'))
        # Now parallel the two together
        self.hourSoundInterval.append(seq1)
        self.hourSoundInterval.append(seq2)
        self.hourSoundInterval.start()

    def handleEnterGateSphere(self, collEntry):
        self.notify.debug("Entering steps Sphere....")
        # Freeze the toon, don't let him walk away...
        base.cr.playGame.getPlace().fsm.request('stopped')
        self.sendUpdate("getPartyList", [base.localAvatar.doId])

    def listAllPublicParties(self, publicPartyInfo):
        """
        Called from DistributedPartyGateAI with a tuple of all the public party
        information as told to it by the DistributedPartyManagerAI in order of
        newest party to oldest party.
        ( shardId, zoneId, numberOfGuests, hostName, activityIds, minLeft )
        """
        self.notify.debug("listAllPublicParties : publicPartyInfo = %s" %
                          publicPartyInfo)
        self.acceptOnce(self.publicPartyChooseGuiDoneEvent,
                        self.__handleAskDone)
        self.publicPartyGui.refresh(publicPartyInfo)
        self.publicPartyGui.unstash()

    def __enableCollisions(self):
        # start listening for toons to enter.
        self.accept('enterPartyGateSphere', self.handleEnterGateSphere)
        self.partyGateSphere.setCollideMask(OTPGlobals.WallBitmask)

    def __disableCollisions(self):
        # stop listening for toons.
        self.ignore('enterPartyGateSphere')
        self.partyGateSphere.setCollideMask(BitMask32(0))

    def handleSleep(self):
        if hasattr(self, 'messageGui'):
            self.__handleMessageDone()
Example #52
0
    def showResults(self):
        if not self.gameIsEnding:
            self.gameIsEnding = True
            for barrel in self.barrels:
                barrel.wrtReparentTo(render)

            for key in self.cogInfo:
                thief = self.cogInfo[key]['suit']
                thief.suit.setPos(100, 0, 0)
                thief.suit.hide()

            self.__killRewardCountdown()
            self.stopGameWalk()
            numBarrelsSaved = len(self.barrels) - len(self.stolenBarrels)
            resultStr = ''
            if numBarrelsSaved == len(self.barrels):
                resultStr = TTLocalizer.CogThiefPerfect
            elif numBarrelsSaved > 1:
                resultStr = TTLocalizer.CogThiefBarrelsSaved % {
                    'num': numBarrelsSaved
                }
            elif numBarrelsSaved == 1:
                resultStr = TTLocalizer.CogThiefBarrelSaved % {
                    'num': numBarrelsSaved
                }
            else:
                resultStr = TTLocalizer.CogThiefNoBarrelsSaved
            perfectTextSubnode = hidden.attachNewNode(
                self.__genText(resultStr))
            perfectText = hidden.attachNewNode('perfectText')
            perfectTextSubnode.reparentTo(perfectText)
            frame = self.__textGen.getCardActual()
            offsetY = -abs(frame[2] + frame[3]) / 2.0
            perfectTextSubnode.setPos(0, 0, offsetY)
            perfectText.setColor(1, 0.1, 0.1, 1)

            def fadeFunc(t, text=perfectText):
                text.setColorScale(1, 1, 1, t)

            def destroyText(text=perfectText):
                text.removeNode()

            def safeGameOver(self=self):
                if not self.frameworkFSM.isInternalStateInFlux():
                    self.gameOver()

            textTrack = Sequence(
                Func(perfectText.reparentTo, aspect2d),
                Parallel(
                    LerpScaleInterval(perfectText,
                                      duration=0.5,
                                      scale=0.3,
                                      startScale=0.0),
                    LerpFunctionInterval(fadeFunc,
                                         fromData=0.0,
                                         toData=1.0,
                                         duration=0.5)), Wait(2.0),
                Parallel(
                    LerpScaleInterval(perfectText, duration=0.5, scale=1.0),
                    LerpFunctionInterval(fadeFunc,
                                         fromData=1.0,
                                         toData=0.0,
                                         duration=0.5,
                                         blendType='easeIn')),
                Func(destroyText), WaitInterval(0.5), Func(safeGameOver))
            if numBarrelsSaved == len(self.barrels):
                soundTrack = SoundInterval(self.sndPerfect)
            else:
                soundTrack = Sequence()
            self.resultIval = Parallel(textTrack, soundTrack)
            self.resultIval.start()
Example #53
0
class PairingGameCard(PlayingCardNodePath):
    DoIntervalDefault = True
    FlipTime = 0.25
    UseDifferentCardColors = True
    CardColors = [(0.933594, 0.265625, 0.28125, 1.0),
                  (0.550781, 0.824219, 0.324219, 1.0),
                  (0.347656, 0.820312, 0.953125, 1.0),
                  (0.460938, 0.378906, 0.824219, 1.0),
                  (0.710938, 0.234375, 0.4375, 1.0),
                  (0.285156, 0.328125, 0.726562, 1.0),
                  (0.242188, 0.742188, 0.515625, 1.0),
                  (0.96875, 0.691406, 0.699219, 1.0),
                  (0.996094, 0.957031, 0.597656, 1.0),
                  (0.992188, 0.480469, 0.167969, 1.0)]

    def __init__(self, value):
        style = PlayingCardGlobals.Styles[0]
        PlayingCardNodePath.__init__(self, style, value)
        self.enterCallback = None
        self.exitCallback = None
        return

    def load(self):
        oneCard = loader.loadModel(
            'phase_4/models/minigames/garden_sign_memory')
        prop = self.attachNewNode('prop')
        PlayingCardGlobals.getImage(self.style, self.suit,
                                    self.rank).copyTo(prop)
        prop.setScale(7)
        oneCard.find('**/glow').removeNode()
        cs = oneCard.find('**/collision')
        for solidIndex in range(cs.node().getNumSolids()):
            cs.node().modifySolid(solidIndex).setTangible(False)

        cs.node().setName('cardCollision-%d' % self.value)
        sign = oneCard.find('**/sign1')
        if self.UseDifferentCardColors:
            index = self.rank % len(self.CardColors)
            color = self.CardColors[index]
            sign.setColorScale(*color)
        prop.setPos(0.0, 0.0, 0.08)
        prop.setP(-90)
        prop.reparentTo(oneCard)
        oneCard.reparentTo(self)
        cardBack = oneCard.find('**/sign2')
        cardBack.setColorScale(0.12, 0.35, 0.5, 1.0)
        cardModel = loader.loadModel('phase_3.5/models/gui/playingCard')
        logo = cardModel.find('**/logo')
        logo.reparentTo(self)
        logo.setScale(0.45)
        logo.setP(90)
        logo.setZ(0.025)
        logo.setX(-0.05)
        logo.setH(180)
        cardModel.removeNode()
        self.setR(0)
        self.setScale(2.5)
        self.flipIval = None
        self.turnUpSound = base.loader.loadSfx(
            'phase_4/audio/sfx/MG_pairing_card_flip_face_up.ogg')
        self.turnDownSound = base.loader.loadSfx(
            'phase_4/audio/sfx/MG_pairing_card_flip_face_down.ogg')
        return

    def unload(self):
        self.clearFlipIval()
        self.removeNode()
        del self.turnUpSound
        del self.turnDownSound

    def turnUp(self, doInterval=DoIntervalDefault):
        self.faceUp = 1
        if doInterval:
            self.clearFlipIval()
            self.flipIval = Parallel(
                LerpHprInterval(self, self.FlipTime, Vec3(0, 0, 0)),
                SoundInterval(self.turnUpSound,
                              node=self,
                              listenerNode=base.localAvatar,
                              cutOff=240))
            self.flipIval.start()
        else:
            self.setR(0)

    def clearFlipIval(self):
        if self.flipIval:
            self.flipIval.finish()
            self.flipIval = None
        return

    def turnDown(self, doInterval=DoIntervalDefault):
        self.faceUp = 0
        if doInterval:
            self.clearFlipIval()
            self.flipIval = Parallel(
                LerpHprInterval(self, self.FlipTime, Vec3(0, 0, 180)),
                SoundInterval(self.turnDownSound,
                              node=self,
                              listenerNode=base.localAvatar,
                              cutOff=240))
            self.flipIval.start()
        else:
            self.setR(180)
Example #54
0
class IceTreasure(DirectObject):
    __module__ = __name__
    notify = DirectNotifyGlobal.directNotify.newCategory('IceTreasure')
    RADIUS = 1.0

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

    def destroy(self):
        self.ignoreAll()
        if self.penalty:
            self.sparksEffect.cleanup()
            if self.track:
                self.track.finish()
        self.nodePath.removeNode()
        del self.nodePath
        del self.collSphere
        self.collNodePath.removeNode()
        del self.collNodePath
        del self.collNode

    def showGrab(self):
        self.nodePath.hide()
        self.collNodePath.hide()
        self.collNode.setIntoCollideMask(BitMask32(0))
        if self.penalty:
            self.track = Parallel(
                SoundInterval(self.penaltyGrabSound),
                Sequence(
                    Func(self.kaboom.showThrough),
                    LerpScaleInterval(self.kaboom,
                                      duration=0.5,
                                      scale=Point3(10, 10, 10),
                                      blendType='easeOut'),
                    Func(self.kaboom.hide)))
            self.track.start()
Example #55
0
class DistributedBanquetTable(DistributedObject.DistributedObject, FSM.FSM,
                              BanquetTableBase.BanquetTableBase):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'DistributedBanquetTable')
    rotationsPerSeatIndex = [90, 90, 0, 0, -90, -90, 180, 180]
    pitcherMinH = -360
    pitcherMaxH = 360
    rotateSpeed = 30
    waterPowerSpeed = base.config.GetDouble('water-power-speed', 15)
    waterPowerExponent = base.config.GetDouble('water-power-exponent', 0.75)
    useNewAnimations = True
    TugOfWarControls = False
    OnlyUpArrow = True
    if OnlyUpArrow:
        BASELINE_KEY_RATE = 3
    else:
        BASELINE_KEY_RATE = 6
    UPDATE_KEY_PRESS_RATE_TASK = 'BanquetTableUpdateKeyPressRateTask'
    YELLOW_POWER_THRESHOLD = 0.75
    RED_POWER_THRESHOLD = 0.97

    def __init__(self, cr):
        DistributedObject.DistributedObject.__init__(self, cr)
        FSM.FSM.__init__(self, 'DistributedBanquetTable')
        self.boss = None
        self.index = -1
        self.diners = {}
        self.dinerStatus = {}
        self.serviceLocs = {}
        self.chairLocators = {}
        self.sitLocators = {}
        self.activeIntervals = {}
        self.dinerStatusIndicators = {}
        self.preparedForPhaseFour = False
        self.avId = 0
        self.toon = None
        self.pitcherSmoother = SmoothMover()
        self.pitcherSmoother.setSmoothMode(SmoothMover.SMOn)
        self.smoothStarted = 0
        self.__broadcastPeriod = 0.2
        self.changeSeq = 0
        self.lastChangeSeq = 0
        self.pitcherAdviceLabel = None
        self.fireLength = 250
        self.fireTrack = None
        self.hitObject = None
        self.setupPowerBar()
        self.aimStart = None
        self.toonPitcherPosition = Point3(0, -2, 0)
        self.allowLocalRequestControl = True
        self.fadeTrack = None
        self.grabTrack = None
        self.gotHitByBoss = False
        self.keyTTL = []
        self.keyRate = 0
        self.buttons = [0, 1]
        self.lastPowerFired = 0
        self.moveSound = None
        self.releaseTrack = None
        return

    def disable(self):
        DistributedObject.DistributedObject.disable(self)
        taskMgr.remove(self.triggerName)
        taskMgr.remove(self.smoothName)
        taskMgr.remove(self.watchControlsName)
        taskMgr.remove(self.pitcherAdviceName)
        taskMgr.remove(self.posHprBroadcastName)
        taskMgr.remove(self.waterPowerTaskName)
        if self.releaseTrack:
            self.releaseTrack.finish()
            self.releaseTrack = None
        if self.fireTrack:
            self.fireTrack.finish()
            self.fireTrack = None
        self.cleanupIntervals()
        return

    def delete(self):
        DistributedObject.DistributedObject.delete(self)
        self.boss = None
        self.ignoreAll()
        for indicator in self.dinerStatusIndicators.values():
            indicator.delete()

        self.dinerStatusIndicators = {}
        for diner in self.diners.values():
            diner.delete()

        self.diners = {}
        self.powerBar.destroy()
        self.powerBar = None
        self.pitcherMoveSfx.stop()
        return

    def announceGenerate(self):
        DistributedObject.DistributedObject.announceGenerate(self)
        self.loadAssets()
        self.smoothName = self.uniqueName('pitcherSmooth')
        self.pitcherAdviceName = self.uniqueName('pitcherAdvice')
        self.posHprBroadcastName = self.uniqueName('pitcherBroadcast')
        self.waterPowerTaskName = self.uniqueName('updateWaterPower')
        self.triggerName = self.uniqueName('trigger')
        self.watchControlsName = self.uniqueName('watchControls')

    def setBossCogId(self, bossCogId):
        self.bossCogId = bossCogId
        self.boss = base.cr.doId2do[bossCogId]
        self.boss.setTable(self, self.index)

    def setIndex(self, index):
        self.index = index

    def setState(self, state, avId, extraInfo):
        self.gotHitByBoss = extraInfo
        if state == 'F':
            self.demand('Off')
        elif state == 'N':
            self.demand('On')
        elif state == 'I':
            self.demand('Inactive')
        elif state == 'R':
            self.demand('Free')
        elif state == 'C':
            self.demand('Controlled', avId)
        elif state == 'L':
            self.demand('Flat', avId)
        else:
            self.notify.error('Invalid state from AI: %s' % state)

    def setNumDiners(self, numDiners):
        self.numDiners = numDiners

    def setDinerInfo(self, hungryDurations, eatingDurations, dinerLevels):
        self.dinerInfo = {}
        for i in xrange(len(hungryDurations)):
            hungryDur = hungryDurations[i]
            eatingDur = eatingDurations[i]
            dinerLevel = dinerLevels[i]
            self.dinerInfo[i] = (hungryDur, eatingDur, dinerLevel)

    def loadAssets(self):
        self.tableGroup = loader.loadModel(
            'phase_12/models/bossbotHQ/BanquetTableChairs')
        tableLocator = self.boss.geom.find('**/TableLocator_%d' %
                                           (self.index + 1))
        if tableLocator.isEmpty():
            self.tableGroup.reparentTo(render)
            self.tableGroup.setPos(0, 75, 0)
        else:
            self.tableGroup.reparentTo(tableLocator)
        self.tableGeom = self.tableGroup.find('**/Geometry')
        self.setupDiners()
        self.setupChairCols()
        self.squirtSfx = loader.loadSfx(
            'phase_4/audio/sfx/AA_squirt_seltzer_miss.ogg')
        self.hitBossSfx = loader.loadSfx(
            'phase_5/audio/sfx/SA_watercooler_spray_only.ogg')
        self.hitBossSoundInterval = SoundInterval(self.hitBossSfx,
                                                  node=self.boss,
                                                  volume=1.0)
        self.serveFoodSfx = loader.loadSfx(
            'phase_4/audio/sfx/MG_sfx_travel_game_bell_for_trolley.ogg')
        self.pitcherMoveSfx = base.loader.loadSfx(
            'phase_4/audio/sfx/MG_cannon_adjust.ogg')

    def setupDiners(self):
        for i in xrange(self.numDiners):
            newDiner = self.createDiner(i)
            self.diners[i] = newDiner
            self.dinerStatus[i] = self.HUNGRY

    def createDiner(self, i):
        diner = Suit.Suit()
        diner.dna = SuitDNA.SuitDNA()
        level = self.dinerInfo[i][2]
        level -= 4
        diner.dna.newSuitRandom(level=level, dept='c')
        diner.setDNA(diner.dna)
        diner.nametag3d.stash()
        diner.nametag.destroy()
        if self.useNewAnimations:
            diner.loop('sit', fromFrame=i)
        else:
            diner.pose('landing', 0)
        locator = self.tableGroup.find('**/chair_%d' % (i + 1))
        locatorScale = locator.getNetTransform().getScale()[0]
        correctHeadingNp = locator.attachNewNode('correctHeading')
        self.chairLocators[i] = correctHeadingNp
        heading = self.rotationsPerSeatIndex[i]
        correctHeadingNp.setH(heading)
        sitLocator = correctHeadingNp.attachNewNode('sitLocator')
        base.sitLocator = sitLocator
        pos = correctHeadingNp.getPos(render)
        if SuitDNA.getSuitBodyType(diner.dna.name) == 'c':
            sitLocator.setPos(0.5, 3.65, -3.75)
        else:
            sitLocator.setZ(-2.4)
            sitLocator.setY(2.5)
            sitLocator.setX(0.5)
        self.sitLocators[i] = sitLocator
        diner.setScale(1.0 / locatorScale)
        diner.reparentTo(sitLocator)
        newLoc = NodePath('serviceLoc-%d-%d' % (self.index, i))
        newLoc.reparentTo(correctHeadingNp)
        newLoc.setPos(0, 3.0, 1)
        self.serviceLocs[i] = newLoc
        base.serviceLoc = newLoc
        head = diner.find('**/joint_head')
        newIndicator = DinerStatusIndicator.DinerStatusIndicator(parent=head,
                                                                 pos=Point3(
                                                                     0, 0,
                                                                     3.5),
                                                                 scale=5.0)
        newIndicator.wrtReparentTo(diner)
        self.dinerStatusIndicators[i] = newIndicator
        return diner

    def setupChairCols(self):
        for i in xrange(self.numDiners):
            chairCol = self.tableGroup.find('**/collision_chair_%d' % (i + 1))
            colName = 'ChairCol-%d-%d' % (self.index, i)
            chairCol.setTag('chairIndex', str(i))
            chairCol.setName(colName)
            chairCol.setCollideMask(ToontownGlobals.WallBitmask)
            self.accept('enter' + colName, self.touchedChair)

    def touchedChair(self, colEntry):
        chairIndex = int(colEntry.getIntoNodePath().getTag('chairIndex'))
        if chairIndex in self.dinerStatus:
            status = self.dinerStatus[chairIndex]
            if status in (self.HUNGRY, self.ANGRY):
                self.boss.localToonTouchedChair(self.index, chairIndex)

    def serveFood(self, food, chairIndex):
        self.removeFoodModel(chairIndex)
        serviceLoc = self.serviceLocs.get(chairIndex)
        if not food or food.isEmpty():
            foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood')
            foodModel.setScale(ToontownGlobals.BossbotFoodModelScale)
            foodModel.reparentTo(serviceLoc)
        else:
            food.wrtReparentTo(serviceLoc)
            tray = food.find('**/tray')
            if not tray.isEmpty():
                tray.hide()
            ivalDuration = 1.5
            foodMoveIval = Parallel(
                SoundInterval(self.serveFoodSfx, node=food),
                ProjectileInterval(food,
                                   duration=ivalDuration,
                                   startPos=food.getPos(serviceLoc),
                                   endPos=serviceLoc.getPos(serviceLoc)),
                LerpHprInterval(food, ivalDuration, Point3(0, -360, 0)))
            intervalName = 'serveFood-%d-%d' % (self.index, chairIndex)
            foodMoveIval.start()
            self.activeIntervals[intervalName] = foodMoveIval

    def setDinerStatus(self, chairIndex, status):
        if chairIndex in self.dinerStatus:
            oldStatus = self.dinerStatus[chairIndex]
            self.dinerStatus[chairIndex] = status
            if oldStatus != status:
                if status == self.EATING:
                    self.changeDinerToEating(chairIndex)
                elif status == self.HUNGRY:
                    self.changeDinerToHungry(chairIndex)
                elif status == self.ANGRY:
                    self.changeDinerToAngry(chairIndex)
                elif status == self.DEAD:
                    self.changeDinerToDead(chairIndex)
                elif status == self.HIDDEN:
                    self.changeDinerToHidden(chairIndex)

    def removeFoodModel(self, chairIndex):
        serviceLoc = self.serviceLocs.get(chairIndex)
        if serviceLoc:
            for i in xrange(serviceLoc.getNumChildren()):
                serviceLoc.getChild(0).removeNode()

    def changeDinerToEating(self, chairIndex):
        indicator = self.dinerStatusIndicators.get(chairIndex)
        eatingDuration = self.dinerInfo[chairIndex][1]
        if indicator:
            indicator.request('Eating', eatingDuration)
        diner = self.diners[chairIndex]
        intervalName = 'eating-%d-%d' % (self.index, chairIndex)
        eatInTime = 32.0 / 24.0
        eatOutTime = 21.0 / 24.0
        eatLoopTime = 19 / 24.0
        rightHand = diner.getRightHand()
        waitTime = 5
        loopDuration = eatingDuration - eatInTime - eatOutTime - waitTime
        serviceLoc = self.serviceLocs[chairIndex]

        def foodAttach(self=self, diner=diner):
            if self.serviceLocs[chairIndex].getNumChildren() < 1:
                return
            foodModel = self.serviceLocs[chairIndex].getChild(0)
            (foodModel.reparentTo(diner.getRightHand()), )
            (foodModel.setHpr(Point3(0, -94, 0)), )
            (foodModel.setPos(Point3(-0.15, -0.7, -0.4)), )
            scaleAdj = 1
            if SuitDNA.getSuitBodyType(diner.dna.name) == 'c':
                scaleAdj = 0.6
                (foodModel.setPos(Point3(0.1, -0.25, -0.31)), )
            else:
                scaleAdj = 0.8
                (foodModel.setPos(Point3(-0.25, -0.85, -0.34)), )
            oldScale = foodModel.getScale()
            newScale = oldScale * scaleAdj
            foodModel.setScale(newScale)

        def foodDetach(self=self, diner=diner):
            if diner.getRightHand().getNumChildren() < 1:
                return
            foodModel = diner.getRightHand().getChild(0)
            (foodModel.reparentTo(serviceLoc), )
            (foodModel.setPosHpr(0, 0, 0, 0, 0, 0), )
            scaleAdj = 1
            if SuitDNA.getSuitBodyType(diner.dna.name) == 'c':
                scaleAdj = 0.6
            else:
                scakeAdj = 0.8
            oldScale = foodModel.getScale()
            newScale = oldScale / scaleAdj
            foodModel.setScale(newScale)

        eatIval = Sequence(
            ActorInterval(diner, 'sit', duration=waitTime),
            ActorInterval(diner, 'sit-eat-in', startFrame=0, endFrame=6),
            Func(foodAttach),
            ActorInterval(diner, 'sit-eat-in', startFrame=6, endFrame=32),
            ActorInterval(diner, 'sit-eat-loop', duration=loopDuration,
                          loop=1),
            ActorInterval(diner, 'sit-eat-out', startFrame=0, endFrame=12),
            Func(foodDetach),
            ActorInterval(diner, 'sit-eat-out', startFrame=12, endFrame=21))
        eatIval.start()
        self.activeIntervals[intervalName] = eatIval

    def changeDinerToHungry(self, chairIndex):
        intervalName = 'eating-%d-%d' % (self.index, chairIndex)
        if intervalName in self.activeIntervals:
            self.activeIntervals[intervalName].finish()
        self.removeFoodModel(chairIndex)
        indicator = self.dinerStatusIndicators.get(chairIndex)
        if indicator:
            indicator.request('Hungry', self.dinerInfo[chairIndex][0])
        diner = self.diners[chairIndex]
        if random.choice([0, 1]):
            diner.loop('sit-hungry-left')
        else:
            diner.loop('sit-hungry-right')

    def changeDinerToAngry(self, chairIndex):
        self.removeFoodModel(chairIndex)
        indicator = self.dinerStatusIndicators.get(chairIndex)
        if indicator:
            indicator.request('Angry')
        diner = self.diners[chairIndex]
        diner.loop('sit-angry')

    def changeDinerToDead(self, chairIndex):
        def removeDeathSuit(suit, deathSuit):
            if not deathSuit.isEmpty():
                deathSuit.detachNode()
                suit.cleanupLoseActor()

        self.removeFoodModel(chairIndex)
        indicator = self.dinerStatusIndicators.get(chairIndex)
        if indicator:
            indicator.request('Dead')
        diner = self.diners[chairIndex]
        deathSuit = diner
        locator = self.tableGroup.find('**/chair_%d' % (chairIndex + 1))
        deathSuit = diner.getLoseActor()
        ival = Sequence(
            Func(self.notify.debug, 'before actorinterval sit-lose'),
            ActorInterval(diner, 'sit-lose'),
            Func(self.notify.debug, 'before deathSuit.setHpr'),
            Func(deathSuit.setHpr, diner.getHpr()),
            Func(self.notify.debug, 'before diner.hide'), Func(diner.hide),
            Func(self.notify.debug, 'before deathSuit.reparentTo'),
            Func(deathSuit.reparentTo, self.chairLocators[chairIndex]),
            Func(self.notify.debug, 'befor ActorInterval lose'),
            ActorInterval(deathSuit,
                          'lose',
                          duration=MovieUtil.SUIT_LOSE_DURATION),
            Func(self.notify.debug, 'before remove deathsuit'),
            Func(removeDeathSuit,
                 diner,
                 deathSuit,
                 name='remove-death-suit-%d-%d' % (chairIndex, self.index)),
            Func(self.notify.debug, 'diner.stash'), Func(diner.stash))
        spinningSound = base.loader.loadSfx(
            'phase_3.5/audio/sfx/Cog_Death.ogg')
        deathSound = base.loader.loadSfx(
            'phase_3.5/audio/sfx/ENC_cogfall_apart_%s.ogg' %
            random.randint(1, 6))
        deathSoundTrack = Sequence(
            Wait(0.8),
            SoundInterval(spinningSound,
                          duration=1.2,
                          startTime=1.5,
                          volume=0.2,
                          node=deathSuit),
            SoundInterval(spinningSound,
                          duration=3.0,
                          startTime=0.6,
                          volume=0.8,
                          node=deathSuit),
            SoundInterval(deathSound, volume=0.32, node=deathSuit))
        intervalName = 'dinerDie-%d-%d' % (self.index, chairIndex)
        deathIval = Parallel(ival, deathSoundTrack)
        deathIval.start()
        self.activeIntervals[intervalName] = deathIval

    def changeDinerToHidden(self, chairIndex):
        self.removeFoodModel(chairIndex)
        indicator = self.dinerStatusIndicators.get(chairIndex)
        if indicator:
            indicator.request('Inactive')
        diner = self.diners[chairIndex]
        diner.hide()

    def setAllDinersToSitNeutral(self):
        startFrame = 0
        for diner in self.diners.values():
            if not diner.isHidden():
                diner.loop('sit', fromFrame=startFrame)
                startFrame += 1

    def cleanupIntervals(self):
        for interval in self.activeIntervals.values():
            interval.finish()

        self.activeIntervals = {}

    def clearInterval(self, name, finish=1):
        if name in self.activeIntervals:
            ival = self.activeIntervals[name]
            if finish:
                ival.finish()
            else:
                ival.pause()
            if name in self.activeIntervals:
                del self.activeIntervals[name]
        else:
            self.notify.debug('interval: %s already cleared' % name)

    def finishInterval(self, name):
        if name in self.activeIntervals:
            interval = self.activeIntervals[name]
            interval.finish()

    def getNotDeadInfo(self):
        notDeadList = []
        for i in xrange(self.numDiners):
            if self.dinerStatus[i] != self.DEAD:
                notDeadList.append((self.index, i, 12))

        return notDeadList

    def enterOn(self):
        pass

    def exitOn(self):
        pass

    def enterInactive(self):
        for chairIndex in xrange(self.numDiners):
            indicator = self.dinerStatusIndicators.get(chairIndex)
            if indicator:
                indicator.request('Inactive')
            self.removeFoodModel(chairIndex)

    def exitInactive(self):
        pass

    def enterFree(self):
        self.resetPowerBar()
        if self.fadeTrack:
            self.fadeTrack.finish()
            self.fadeTrack = None
        self.prepareForPhaseFour()
        if self.avId == localAvatar.doId:
            self.tableGroup.setAlphaScale(0.3)
            self.tableGroup.setTransparency(1)
            taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName)
            self.fadeTrack = Sequence(
                Func(self.tableGroup.setTransparency, 1),
                self.tableGroup.colorScaleInterval(0.2, VBase4(1, 1, 1, 0.3)))
            self.fadeTrack.start()
            self.allowLocalRequestControl = False
        else:
            self.allowLocalRequestControl = True
        self.avId = 0
        return

    def exitFree(self):
        pass

    def touchedTable(self, colEntry):
        tableIndex = int(colEntry.getIntoNodePath().getTag('tableIndex'))
        if self.state == 'Free' and self.avId == 0 and self.allowLocalRequestControl:
            self.d_requestControl()

    def prepareForPhaseFour(self):
        if not self.preparedForPhaseFour:
            for i in xrange(8):
                chair = self.tableGroup.find('**/chair_%d' % (i + 1))
                if not chair.isEmpty():
                    chair.hide()
                colChairs = self.tableGroup.findAllMatches('**/ChairCol*')
                for i in xrange(colChairs.getNumPaths()):
                    col = colChairs.getPath(i)
                    col.stash()

                colChairs = self.tableGroup.findAllMatches(
                    '**/collision_chair*')
                for i in xrange(colChairs.getNumPaths()):
                    col = colChairs.getPath(i)
                    col.stash()

            tableCol = self.tableGroup.find('**/collision_table')
            colName = 'TableCol-%d' % self.index
            tableCol.setTag('tableIndex', str(self.index))
            tableCol.setName(colName)
            tableCol.setCollideMask(ToontownGlobals.WallBitmask
                                    | ToontownGlobals.BanquetTableBitmask)
            self.accept('enter' + colName, self.touchedTable)
            self.preparedForPhaseFour = True
            self.waterPitcherModel = loader.loadModel(
                'phase_12/models/bossbotHQ/tt_m_ara_bhq_seltzerBottle')
            lampNode = self.tableGroup.find('**/lamp_med_5')
            pos = lampNode.getPos(self.tableGroup)
            lampNode.hide()
            bottleLocator = self.tableGroup.find('**/bottle_locator')
            pos = bottleLocator.getPos(self.tableGroup)
            self.waterPitcherNode = self.tableGroup.attachNewNode(
                'pitcherNode')
            self.waterPitcherNode.setPos(pos)
            self.waterPitcherModel.reparentTo(self.waterPitcherNode)
            self.nozzle = self.waterPitcherModel.find('**/nozzle_tip')
            self.handLocator = self.waterPitcherModel.find('**/hand_locator')
            self.handPos = self.handLocator.getPos()

    def d_requestControl(self):
        self.sendUpdate('requestControl')

    def d_requestFree(self, gotHitByBoss):
        self.sendUpdate('requestFree', [gotHitByBoss])

    def enterControlled(self, avId):
        self.prepareForPhaseFour()
        self.avId = avId
        toon = base.cr.doId2do.get(avId)
        if not toon:
            return
        self.toon = toon
        self.grabTrack = self.makeToonGrabInterval(toon)
        self.notify.debug('grabTrack=%s' % self.grabTrack)
        self.pitcherCamPos = Point3(0, -50, 40)
        self.pitcherCamHpr = Point3(0, -21, 0)
        if avId == localAvatar.doId:
            self.boss.toMovieMode()
            self.__enableControlInterface()
            self.startPosHprBroadcast()
            self.grabTrack = Sequence(
                self.grabTrack, Func(camera.wrtReparentTo, localAvatar),
                LerpPosHprInterval(camera, 1, self.pitcherCamPos,
                                   self.pitcherCamHpr),
                Func(self.boss.toCraneMode))
            if self.TugOfWarControls:
                self.__spawnUpdateKeyPressRateTask()
            self.accept('exitCrane', self.gotBossZapped)
        else:
            self.startSmooth()
            toon.stopSmooth()
        self.grabTrack.start()

    def exitControlled(self):
        self.ignore('exitCrane')
        if self.grabTrack:
            self.grabTrack.finish()
            self.grabTrack = None
        nextState = self.getCurrentOrNextState()
        self.notify.debug('nextState=%s' % nextState)
        if nextState == 'Flat':
            place = base.cr.playGame.getPlace()
            self.notify.debug('%s' % place.fsm)
            if self.avId == localAvatar.doId:
                self.__disableControlInterface()
        else:
            if self.toon and not self.toon.isDisabled():
                self.toon.loop('neutral')
                self.toon.startSmooth()
            self.releaseTrack = self.makeToonReleaseInterval(self.toon)
            self.stopPosHprBroadcast()
            self.stopSmooth()
            if self.avId == localAvatar.doId:
                localAvatar.wrtReparentTo(render)
                self.__disableControlInterface()
                camera.reparentTo(base.localAvatar)
                camera.setPos(base.localAvatar.cameraPositions[0][0])
                camera.setHpr(0, 0, 0)
                self.goToFinalBattle()
                self.safeBossToFinalBattleMode()
            else:
                toon = base.cr.doId2do.get(self.avId)
                if toon:
                    toon.wrtReparentTo(render)
            self.releaseTrack.start()
        return

    def safeBossToFinalBattleMode(self):
        if self.boss:
            self.boss.toFinalBattleMode()

    def goToFinalBattle(self):
        if self.cr:
            place = self.cr.playGame.getPlace()
            if place and hasattr(place, 'fsm'):
                if place.fsm.getCurrentState().getName() == 'crane':
                    place.setState('finalBattle')

    def makeToonGrabInterval(self, toon):
        toon.pose('leverNeutral', 0)
        toon.update()
        rightHandPos = toon.rightHand.getPos(toon)
        self.toonPitcherPosition = Point3(self.handPos[0] - rightHandPos[0],
                                          self.handPos[1] - rightHandPos[1], 0)
        destZScale = rightHandPos[2] / self.handPos[2]
        grabIval = Sequence(
            Func(toon.wrtReparentTo, self.waterPitcherNode),
            Func(toon.loop, 'neutral'),
            Parallel(
                ActorInterval(toon, 'jump'),
                Sequence(
                    Wait(0.43),
                    Parallel(
                        ProjectileInterval(toon,
                                           duration=0.9,
                                           startPos=toon.getPos(
                                               self.waterPitcherNode),
                                           endPos=self.toonPitcherPosition),
                        LerpHprInterval(toon, 0.9, Point3(0, 0, 0)),
                        LerpScaleInterval(self.waterPitcherModel, 0.9,
                                          Point3(1, 1, destZScale))))),
            Func(toon.setPos, self.toonPitcherPosition),
            Func(toon.loop, 'leverNeutral'))
        return grabIval

    def makeToonReleaseInterval(self, toon):
        temp1 = self.waterPitcherNode.attachNewNode('temp1')
        temp1.setPos(self.toonPitcherPosition)
        temp2 = self.waterPitcherNode.attachNewNode('temp2')
        temp2.setPos(0, -10, -self.waterPitcherNode.getZ())
        startPos = temp1.getPos(render)
        endPos = temp2.getPos(render)
        temp1.removeNode()
        temp2.removeNode()

        def getSlideToPos(toon=toon):
            return render.getRelativePoint(toon, Point3(0, -10, 0))

        if self.gotHitByBoss:
            self.notify.debug('creating zap interval instead')
            grabIval = Sequence(
                Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render),
                Parallel(ActorInterval(toon, 'slip-backward'),
                         toon.posInterval(0.5, getSlideToPos, fluid=1)))
        else:
            grabIval = Sequence(
                Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render),
                Parallel(
                    ActorInterval(toon, 'jump'),
                    Sequence(
                        Wait(0.43),
                        ProjectileInterval(toon,
                                           duration=0.9,
                                           startPos=startPos,
                                           endPos=endPos))))
        return grabIval

    def b_clearSmoothing(self):
        self.d_clearSmoothing()
        self.clearSmoothing()

    def d_clearSmoothing(self):
        self.sendUpdate('clearSmoothing', [0])

    def clearSmoothing(self, bogus=None):
        self.pitcherSmoother.clearPositions(1)

    def doSmoothTask(self, task):
        self.pitcherSmoother.computeAndApplySmoothHpr(self.waterPitcherNode)
        return Task.cont

    def startSmooth(self):
        if not self.smoothStarted:
            taskName = self.smoothName
            taskMgr.remove(taskName)
            self.reloadPosition()
            taskMgr.add(self.doSmoothTask, taskName)
            self.smoothStarted = 1

    def stopSmooth(self):
        if self.smoothStarted:
            taskName = self.smoothName
            taskMgr.remove(taskName)
            self.forceToTruePosition()
            self.smoothStarted = 0

    def __enableControlInterface(self):
        gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui')
        self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'),
                                               gui.find('**/CloseBtn_DN'),
                                               gui.find('**/CloseBtn_Rllvr'),
                                               gui.find('**/CloseBtn_UP')),
                                        relief=None,
                                        scale=2,
                                        text=TTLocalizer.BossbotPitcherLeave,
                                        text_scale=0.04,
                                        text_pos=(0, -0.07),
                                        text_fg=VBase4(1, 1, 1, 1),
                                        pos=(1.05, 0, -0.82),
                                        command=self.__exitPitcher)
        self.accept('escape', self.__exitPitcher)
        self.accept('control', self.__controlPressed)
        self.accept('control-up', self.__controlReleased)
        self.accept('InputState-forward', self.__upArrow)
        self.accept('InputState-reverse', self.__downArrow)
        self.accept('InputState-turnLeft', self.__leftArrow)
        self.accept('InputState-turnRight', self.__rightArrow)
        self.accept('arrow_up', self.__upArrowKeyPressed)
        self.accept('arrow_down', self.__downArrowKeyPressed)
        taskMgr.add(self.__watchControls, self.watchControlsName)
        taskMgr.doMethodLater(5, self.__displayPitcherAdvice,
                              self.pitcherAdviceName)
        self.arrowVert = 0
        self.arrowHorz = 0
        self.powerBar.show()
        return

    def __disableControlInterface(self):
        if self.closeButton:
            self.closeButton.destroy()
            self.closeButton = None
        self.__cleanupPitcherAdvice()
        self.ignore('escape')
        self.ignore('control')
        self.ignore('control-up')
        self.ignore('InputState-forward')
        self.ignore('InputState-reverse')
        self.ignore('InputState-turnLeft')
        self.ignore('InputState-turnRight')
        self.ignore('arrow_up')
        self.ignore('arrow_down')
        self.arrowVert = 0
        self.arrowHorz = 0
        taskMgr.remove(self.watchControlsName)
        taskMgr.remove(self.waterPowerTaskName)
        self.resetPowerBar()
        self.aimStart = None
        self.powerBar.hide()
        if self.TugOfWarControls:
            self.__killUpdateKeyPressRateTask()
            self.keyTTL = []
        self.__setMoveSound(None)
        return

    def __displayPitcherAdvice(self, task):
        if self.pitcherAdviceLabel == None:
            self.pitcherAdviceLabel = DirectLabel(
                text=TTLocalizer.BossbotPitcherAdvice,
                text_fg=VBase4(1, 1, 1, 1),
                text_align=TextNode.ACenter,
                relief=None,
                pos=(0, 0, 0.69),
                scale=0.1)
        return

    def __cleanupPitcherAdvice(self):
        if self.pitcherAdviceLabel:
            self.pitcherAdviceLabel.destroy()
            self.pitcherAdviceLabel = None
        taskMgr.remove(self.pitcherAdviceName)
        return

    def showExiting(self):
        if self.closeButton:
            self.closeButton.destroy()
            self.closeButton = DirectLabel(
                relief=None,
                text=TTLocalizer.BossbotPitcherLeaving,
                pos=(1.05, 0, -0.88),
                text_pos=(0, 0),
                text_scale=0.06,
                text_fg=VBase4(1, 1, 1, 1))
        self.__cleanupPitcherAdvice()
        return

    def __exitPitcher(self):
        self.showExiting()
        self.d_requestFree(False)

    def __controlPressed(self):
        self.__cleanupPitcherAdvice()
        if self.TugOfWarControls:
            if self.power:
                self.aimStart = 1
                self.__endFireWater()
        elif self.state == 'Controlled':
            self.__beginFireWater()

    def __controlReleased(self):
        if self.TugOfWarControls:
            pass
        elif self.state == 'Controlled':
            self.__endFireWater()

    def __upArrow(self, pressed):
        self.__incrementChangeSeq()
        self.__cleanupPitcherAdvice()
        if pressed:
            self.arrowVert = 1
        elif self.arrowVert > 0:
            self.arrowVert = 0

    def __downArrow(self, pressed):
        self.__incrementChangeSeq()
        self.__cleanupPitcherAdvice()
        if pressed:
            self.arrowVert = -1
        elif self.arrowVert < 0:
            self.arrowVert = 0

    def __rightArrow(self, pressed):
        self.__incrementChangeSeq()
        self.__cleanupPitcherAdvice()
        if pressed:
            self.arrowHorz = 1
        elif self.arrowHorz > 0:
            self.arrowHorz = 0

    def __leftArrow(self, pressed):
        self.__incrementChangeSeq()
        self.__cleanupPitcherAdvice()
        if pressed:
            self.arrowHorz = -1
        elif self.arrowHorz < 0:
            self.arrowHorz = 0

    def __incrementChangeSeq(self):
        self.changeSeq = self.changeSeq + 1 & 255

    def stopPosHprBroadcast(self):
        taskName = self.posHprBroadcastName
        taskMgr.remove(taskName)

    def startPosHprBroadcast(self):
        taskName = self.posHprBroadcastName
        self.b_clearSmoothing()
        self.d_sendPitcherPos()
        taskMgr.remove(taskName)
        taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast,
                              taskName)

    def __posHprBroadcast(self, task):
        self.d_sendPitcherPos()
        taskName = self.posHprBroadcastName
        taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast,
                              taskName)
        return Task.done

    def d_sendPitcherPos(self):
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate(
            'setPitcherPos',
            [self.changeSeq,
             self.waterPitcherNode.getH(), timestamp])

    def setPitcherPos(self, changeSeq, h, timestamp):
        self.changeSeq = changeSeq
        if self.smoothStarted:
            now = globalClock.getFrameTime()
            local = globalClockDelta.networkToLocalTime(timestamp, now)
            self.pitcherSmoother.setH(h)
            self.pitcherSmoother.setTimestamp(local)
            self.pitcherSmoother.markPosition()
        else:
            self.waterPitcherNode.setH(h)

    def __watchControls(self, task):
        if self.arrowHorz:
            self.__movePitcher(self.arrowHorz)
        else:
            self.__setMoveSound(None)
        return Task.cont

    def __movePitcher(self, xd):
        dt = globalClock.getDt()
        h = self.waterPitcherNode.getH() - xd * self.rotateSpeed * dt
        h %= 360
        self.notify.debug(
            'rotSpeed=%.2f curH=%.2f  xd =%.2f, dt = %.2f, h=%.2f' %
            (self.rotateSpeed, self.waterPitcherNode.getH(), xd, dt, h))
        limitH = h
        self.waterPitcherNode.setH(limitH)
        if xd:
            self.__setMoveSound(self.pitcherMoveSfx)

    def reloadPosition(self):
        self.pitcherSmoother.clearPositions(0)
        self.pitcherSmoother.setHpr(self.waterPitcherNode.getHpr())
        self.pitcherSmoother.setPhonyTimestamp()

    def forceToTruePosition(self):
        if self.pitcherSmoother.getLatestPosition():
            self.pitcherSmoother.applySmoothHpr(self.waterPitcherNode)
        self.pitcherSmoother.clearPositions(1)

    def getSprayTrack(self,
                      color,
                      origin,
                      target,
                      dScaleUp,
                      dHold,
                      dScaleDown,
                      horizScale=1.0,
                      vertScale=1.0,
                      parent=render):
        track = Sequence()
        SPRAY_LEN = 1.5
        sprayProp = MovieUtil.globalPropPool.getProp('spray')
        sprayScale = hidden.attachNewNode('spray-parent')
        sprayRot = hidden.attachNewNode('spray-rotate')
        spray = sprayRot
        spray.setColor(color)
        if color[3] < 1.0:
            spray.setTransparency(1)

        def showSpray(sprayScale, sprayRot, sprayProp, origin, target, parent):
            if callable(origin):
                origin = origin()
            if callable(target):
                target = target()
            sprayRot.reparentTo(parent)
            sprayRot.clearMat()
            sprayScale.reparentTo(sprayRot)
            sprayScale.clearMat()
            sprayProp.reparentTo(sprayScale)
            sprayProp.clearMat()
            sprayRot.setPos(origin)
            sprayRot.lookAt(Point3(target))

        track.append(
            Func(showSpray, sprayScale, sprayRot, sprayProp, origin, target,
                 parent))

        def calcTargetScale(target=target,
                            origin=origin,
                            horizScale=horizScale,
                            vertScale=vertScale):
            if callable(target):
                target = target()
            if callable(origin):
                origin = origin()
            distance = Vec3(target - origin).length()
            yScale = distance / SPRAY_LEN
            targetScale = Point3(yScale * horizScale, yScale,
                                 yScale * vertScale)
            return targetScale

        track.append(
            LerpScaleInterval(sprayScale,
                              dScaleUp,
                              calcTargetScale,
                              startScale=Point3(0.01, 0.01, 0.01)))
        track.append(Func(self.checkHitObject))
        track.append(Wait(dHold))

        def prepareToShrinkSpray(spray, sprayProp, origin, target):
            if callable(target):
                target = target()
            if callable(origin):
                origin = origin()
            sprayProp.setPos(Point3(0.0, -SPRAY_LEN, 0.0))
            spray.setPos(target)

        track.append(
            Func(prepareToShrinkSpray, spray, sprayProp, origin, target))
        track.append(
            LerpScaleInterval(sprayScale, dScaleDown, Point3(0.01, 0.01,
                                                             0.01)))

        def hideSpray(spray, sprayScale, sprayRot, sprayProp, propPool):
            sprayProp.detachNode()
            MovieUtil.removeProp(sprayProp)
            sprayRot.removeNode()
            sprayScale.removeNode()

        track.append(
            Func(hideSpray, spray, sprayScale, sprayRot, sprayProp,
                 MovieUtil.globalPropPool))
        return track

    def checkHitObject(self):
        if not self.hitObject:
            return
        if self.avId != base.localAvatar.doId:
            return
        tag = self.hitObject.getNetTag('pieCode')
        pieCode = int(tag)
        if pieCode == ToontownGlobals.PieCodeBossCog:
            self.hitBossSoundInterval.start()
            self.sendUpdate('waterHitBoss', [self.index])
            if self.TugOfWarControls:
                damage = 1
                if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD:
                    damage = 1
                elif self.lastPowerFired < self.RED_POWER_THRESHOLD:
                    damage = 2
                else:
                    damage = 3
                self.boss.d_hitBoss(damage)
            else:
                damage = 1
                if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD:
                    damage = 1
                elif self.lastPowerFired < self.RED_POWER_THRESHOLD:
                    damage = 2
                else:
                    damage = 3
                self.boss.d_hitBoss(damage)

    def waterHitBoss(self, tableIndex):
        if self.index == tableIndex:
            self.hitBossSoundInterval.start()

    def setupPowerBar(self):
        self.powerBar = DirectWaitBar(pos=(0.0, 0, -0.94),
                                      relief=DGG.SUNKEN,
                                      frameSize=(-2.0, 2.0, -0.2, 0.2),
                                      borderWidth=(0.02, 0.02),
                                      scale=0.25,
                                      range=1,
                                      sortOrder=50,
                                      frameColor=(0.5, 0.5, 0.5, 0.5),
                                      barColor=(0.75, 0.75, 1.0, 0.8),
                                      text='',
                                      text_scale=0.26,
                                      text_fg=(1, 1, 1, 1),
                                      text_align=TextNode.ACenter,
                                      text_pos=(0, -0.05))
        self.power = 0
        self.powerBar['value'] = self.power
        self.powerBar.hide()

    def resetPowerBar(self):
        self.power = 0
        self.powerBar['value'] = self.power
        self.powerBar['text'] = ''
        self.keyTTL = []

    def __beginFireWater(self):
        if self.fireTrack and self.fireTrack.isPlaying():
            return
        if self.aimStart != None:
            return
        if not self.state == 'Controlled':
            return
        if not self.avId == localAvatar.doId:
            return
        time = globalClock.getFrameTime()
        self.aimStart = time
        messenger.send('wakeup')
        taskMgr.add(self.__updateWaterPower, self.waterPowerTaskName)
        return

    def __endFireWater(self):
        if self.aimStart == None:
            return
        if not self.state == 'Controlled':
            return
        if not self.avId == localAvatar.doId:
            return
        taskMgr.remove(self.waterPowerTaskName)
        messenger.send('wakeup')
        self.aimStart = None
        origin = self.nozzle.getPos(render)
        target = self.boss.getPos(render)
        angle = deg2Rad(self.waterPitcherNode.getH() + 90)
        x = math.cos(angle)
        y = math.sin(angle)
        fireVector = Point3(x, y, 0)
        if self.power < 0.001:
            self.power = 0.001
        self.lastPowerFired = self.power
        fireVector *= self.fireLength * self.power
        target = origin + fireVector
        segment = CollisionSegment(origin[0], origin[1], origin[2], target[0],
                                   target[1], target[2])
        fromObject = render.attachNewNode(CollisionNode('pitcherColNode'))
        fromObject.node().addSolid(segment)
        fromObject.node().setFromCollideMask(ToontownGlobals.PieBitmask
                                             | ToontownGlobals.CameraBitmask
                                             | ToontownGlobals.FloorBitmask)
        fromObject.node().setIntoCollideMask(BitMask32.allOff())
        queue = CollisionHandlerQueue()
        base.cTrav.addCollider(fromObject, queue)
        base.cTrav.traverse(render)
        queue.sortEntries()
        self.hitObject = None
        if queue.getNumEntries():
            entry = queue.getEntry(0)
            target = entry.getSurfacePoint(render)
            self.hitObject = entry.getIntoNodePath()
        base.cTrav.removeCollider(fromObject)
        fromObject.removeNode()
        self.d_firingWater(origin, target)
        self.fireWater(origin, target)
        self.resetPowerBar()
        return

    def __updateWaterPower(self, task):
        if not self.powerBar:
            print '### no power bar!!!'
            return task.done
        newPower = self.__getWaterPower(globalClock.getFrameTime())
        self.power = newPower
        self.powerBar['value'] = newPower
        if self.power < self.YELLOW_POWER_THRESHOLD:
            self.powerBar['barColor'] = VBase4(0.75, 0.75, 1.0, 0.8)
        elif self.power < self.RED_POWER_THRESHOLD:
            self.powerBar['barColor'] = VBase4(1.0, 1.0, 0.0, 0.8)
        else:
            self.powerBar['barColor'] = VBase4(1.0, 0.0, 0.0, 0.8)
        return task.cont

    def __getWaterPower(self, time):
        elapsed = max(time - self.aimStart, 0.0)
        t = elapsed / self.waterPowerSpeed
        exponent = self.waterPowerExponent
        if t > 1:
            t = t % 1
        power = 1 - math.pow(1 - t, exponent)
        if power > 1.0:
            power = 1.0
        return power

    def d_firingWater(self, origin, target):
        self.sendUpdate(
            'firingWater',
            [origin[0], origin[1], origin[2], target[0], target[1], target[2]])

    def firingWater(self, startX, startY, startZ, endX, endY, endZ):
        origin = Point3(startX, startY, startZ)
        target = Point3(endX, endY, endZ)
        self.fireWater(origin, target)

    def fireWater(self, origin, target):
        color = VBase4(0.75, 0.75, 1, 0.8)
        dScaleUp = 0.1
        dHold = 0.3
        dScaleDown = 0.1
        horizScale = 0.1
        vertScale = 0.1
        sprayTrack = self.getSprayTrack(color, origin, target, dScaleUp, dHold,
                                        dScaleDown, horizScale, vertScale)
        duration = self.squirtSfx.length()
        if sprayTrack.getDuration() < duration:
            duration = sprayTrack.getDuration()
        soundTrack = SoundInterval(self.squirtSfx,
                                   node=self.waterPitcherModel,
                                   duration=duration)
        self.fireTrack = Parallel(sprayTrack, soundTrack)
        self.fireTrack.start()

    def getPos(self, wrt=render):
        return self.tableGroup.getPos(wrt)

    def getLocator(self):
        return self.tableGroup

    def enterFlat(self, avId):
        self.prepareForPhaseFour()
        self.resetPowerBar()
        self.notify.debug('enterFlat %d' % self.index)
        if self.avId:
            toon = base.cr.doId2do.get(self.avId)
            if toon:
                toon.wrtReparentTo(render)
                toon.setZ(0)
        self.tableGroup.setScale(1, 1, 0.01)
        if self.avId and self.avId == localAvatar.doId:
            localAvatar.b_squish(ToontownGlobals.BossCogDamageLevels[
                ToontownGlobals.BossCogMoveAttack])

    def exitFlat(self):
        self.tableGroup.setScale(1.0)
        if self.avId:
            toon = base.cr.doId2do.get(self.avId)
            if toon:
                if toon == localAvatar:
                    self.boss.toCraneMode()
                    toon.b_setAnimState('neutral')
                toon.setAnimState('neutral')
                toon.loop('leverNeutral')

    def __allowDetect(self, task):
        if self.fadeTrack:
            self.fadeTrack.finish()
        self.fadeTrack = Sequence(
            self.tableGroup.colorScaleInterval(0.2, VBase4(1, 1, 1, 1)),
            Func(self.tableGroup.clearColorScale),
            Func(self.tableGroup.clearTransparency))
        self.fadeTrack.start()
        self.allowLocalRequestControl = True

    def gotBossZapped(self):
        self.showExiting()
        self.d_requestFree(True)

    def __upArrowKeyPressed(self):
        if self.TugOfWarControls:
            self.__pressHandler(0)

    def __downArrowKeyPressed(self):
        if self.TugOfWarControls:
            self.__pressHandler(1)

    def __pressHandler(self, index):
        if index == self.buttons[0]:
            self.keyTTL.insert(0, 1.0)
            if not self.OnlyUpArrow:
                self.buttons.reverse()

    def __spawnUpdateKeyPressRateTask(self):
        taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK))
        taskMgr.doMethodLater(0.1, self.__updateKeyPressRateTask,
                              self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK))

    def __killUpdateKeyPressRateTask(self):
        taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK))

    def __updateKeyPressRateTask(self, task):
        if self.state not in 'Controlled':
            return Task.done
        for i in xrange(len(self.keyTTL)):
            self.keyTTL[i] -= 0.1

        for i in xrange(len(self.keyTTL)):
            if self.keyTTL[i] <= 0:
                a = self.keyTTL[0:i]
                del self.keyTTL
                self.keyTTL = a
                break

        self.keyRate = len(self.keyTTL)
        keyRateDiff = self.keyRate - self.BASELINE_KEY_RATE
        diffPower = keyRateDiff / 300.0
        if self.power < 1 and diffPower > 0:
            diffPower = diffPower * math.pow(1 - self.power, 1.25)
        newPower = self.power + diffPower
        if newPower > 1:
            newPower = 1
        elif newPower < 0:
            newPower = 0
        self.notify.debug('diffPower=%.2f keyRate = %d, newPower=%.2f' %
                          (diffPower, self.keyRate, newPower))
        self.power = newPower
        self.powerBar['value'] = newPower
        if self.power < self.YELLOW_POWER_THRESHOLD:
            self.powerBar['barColor'] = VBase4(0.75, 0.75, 1.0, 0.8)
        elif self.power < self.RED_POWER_THRESHOLD:
            self.powerBar['barColor'] = VBase4(1.0, 1.0, 0.0, 0.8)
        else:
            self.powerBar['barColor'] = VBase4(1.0, 0.0, 0.0, 0.8)
        self.__spawnUpdateKeyPressRateTask()
        return Task.done

    def __setMoveSound(self, sfx):
        if sfx != self.moveSound:
            if self.moveSound:
                self.moveSound.stop()
            self.moveSound = sfx
            if self.moveSound:
                base.playSfx(self.moveSound, looping=1, volume=0.5)
Example #56
0
class DistributedPartyCatchActivity(DistributedPartyActivity, DistributedPartyCatchActivityBase):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyCatchActivity')
    DropTaskName = 'dropSomething'
    DropObjectPlurals = {'apple': TTLocalizer.PartyCatchActivityApples,
     'orange': TTLocalizer.PartyCatchActivityOranges,
     'pear': TTLocalizer.PartyCatchActivityPears,
     'coconut': TTLocalizer.PartyCatchActivityCoconuts,
     'watermelon': TTLocalizer.PartyCatchActivityWatermelons,
     'pineapple': TTLocalizer.PartyCatchActivityPineapples,
     'anvil': TTLocalizer.PartyCatchActivityAnvils}

    class Generation:

        def __init__(self, generation, startTime, startNetworkTime, numPlayers):
            self.generation = generation
            self.startTime = startTime
            self.startNetworkTime = startNetworkTime
            self.numPlayers = numPlayers
            self.hasBeenScheduled = False
            self.droppedObjNames = []
            self.dropSchedule = []
            self.numItemsDropped = 0
            self.droppedObjCaught = {}

    def __init__(self, cr):
        DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyCatch, PartyGlobals.ActivityTypes.HostInitiated, wantRewardGui=True)
        self.setUsesSmoothing()
        self.setUsesLookAround()
        self._sNumGen = SerialNumGen()

    def getTitle(self):
        return TTLocalizer.PartyCatchActivityTitle

    def getInstructions(self):
        return TTLocalizer.PartyCatchActivityInstructions % {'badThing': self.DropObjectPlurals['anvil']}

    def generate(self):
        DistributedPartyActivity.generate(self)
        self.notify.info('localAvatar doId: %s' % base.localAvatar.doId)
        self.notify.info('generate()')
        self._generateFrame = globalClock.getFrameCount()
        self._id2gen = {}
        self._orderedGenerations = []
        self._orderedGenerationIndex = None
        rng = RandomNumGen(self.doId)
        self._generationSeedBase = rng.randrange(1000)
        self._lastDropTime = 0.0
        return

    def getCurGeneration(self):
        if self._orderedGenerationIndex is None:
            return
        return self._orderedGenerations[self._orderedGenerationIndex]

    def _addGeneration(self, generation, startTime, startNetworkTime, numPlayers):
        self._id2gen[generation] = self.Generation(generation, startTime, startNetworkTime, numPlayers)
        i = 0
        while 1:
            if i >= len(self._orderedGenerations):
                break
            gen = self._orderedGenerations[i]
            startNetT = self._id2gen[gen].startTime
            genId = self._id2gen[gen].generation
            if startNetT > startNetworkTime:
                break
            if startNetT == startNetworkTime and genId > generation:
                break
            i += 1
        self._orderedGenerations = self._orderedGenerations[:i] + [generation] + self._orderedGenerations[i:]
        if self._orderedGenerationIndex is not None:
            if self._orderedGenerationIndex >= i:
                self._orderedGenerationIndex += 1

    def _removeGeneration(self, generation):
        del self._id2gen[generation]
        i = self._orderedGenerations.index(generation)
        self._orderedGenerations = self._orderedGenerations[:i] + self._orderedGenerations[i + 1:]
        if self._orderedGenerationIndex is not None:
            if len(self._orderedGenerations):
                if self._orderedGenerationIndex >= i:
                    self._orderedGenerationIndex -= 1
            else:
                self._orderedGenerationIndex = None
        return

    def announceGenerate(self):
        self.notify.info('announceGenerate()')
        self.catchTreeZoneEvent = 'fence_floor'
        DistributedPartyActivity.announceGenerate(self)

    def load(self, loadModels = 1, arenaModel = 'partyCatchTree'):
        self.notify.info('load()')
        DistributedPartyCatchActivity.notify.debug('PartyCatch: load')
        self.activityFSM = CatchActivityFSM(self)
        if __dev__:
            for o in xrange(3):
                print {0: 'SPOTS PER PLAYER',
                 1: 'DROPS PER MINUTE PER SPOT DURING NORMAL DROP PERIOD',
                 2: 'DROPS PER MINUTE PER PLAYER DURING NORMAL DROP PERIOD'}[o]
                for i in xrange(1, self.FallRateCap_Players + 10):
                    self.defineConstants(forceNumPlayers=i)
                    numDropLocations = self.DropRows * self.DropColumns
                    numDropsPerMin = 60.0 / self.DropPeriod
                    if o == 0:
                        spotsPerPlayer = numDropLocations / float(i)
                        print '%2d PLAYERS: %s' % (i, spotsPerPlayer)
                    elif o == 1:
                        numDropsPerMinPerSpot = numDropsPerMin / numDropLocations
                        print '%2d PLAYERS: %s' % (i, numDropsPerMinPerSpot)
                    elif i > 0:
                        numDropsPerMinPerPlayer = numDropsPerMin / i
                        print '%2d PLAYERS: %s' % (i, numDropsPerMinPerPlayer)

        self.defineConstants()
        self.treesAndFence = loader.loadModel('phase_13/models/parties/%s' % arenaModel)
        self.treesAndFence.setScale(0.9)
        self.treesAndFence.find('**/fence_floor').setPos(0.0, 0.0, 0.1)
        self.treesAndFence.reparentTo(self.root)
        ground = self.treesAndFence.find('**/groundPlane')
        ground.setBin('ground', 1)
        DistributedPartyActivity.load(self)
        exitText = TextNode('PartyCatchExitText')
        exitText.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
        exitText.setCardDecal(True)
        exitText.setCardColor(1.0, 1.0, 1.0, 0.0)
        exitText.setText(TTLocalizer.PartyCatchActivityExit)
        exitText.setTextColor(0.0, 8.0, 0.0, 0.9)
        exitText.setAlign(exitText.ACenter)
        exitText.setFont(ToontownGlobals.getBuildingNametagFont())
        exitText.setShadowColor(0, 0, 0, 1)
        exitText.setBin('fixed')
        if TTLocalizer.BuildingNametagShadow:
            exitText.setShadow(*TTLocalizer.BuildingNametagShadow)
        exitTextLoc = self.treesAndFence.find('**/loc_exitSignText')
        exitTextNp = exitTextLoc.attachNewNode(exitText)
        exitTextNp.setDepthWrite(0)
        exitTextNp.setScale(4)
        exitTextNp.setZ(-.5)
        self.sign.reparentTo(self.treesAndFence.find('**/loc_eventSign'))
        self.sign.wrtReparentTo(self.root)
        self.avatarNodePath = NodePath('PartyCatchAvatarNodePath')
        self.avatarNodePath.reparentTo(self.root)
        self._avatarNodePathParentToken = 3
        base.cr.parentMgr.registerParent(self._avatarNodePathParentToken, self.avatarNodePath)
        self.toonSDs = {}
        self.dropShadow = loader.loadModelOnce('phase_3/models/props/drop_shadow')
        self.dropObjModels = {}
        if loadModels:
            self.__loadDropModels()
        self.sndGoodCatch = base.loadSfx('phase_4/audio/sfx/SZ_DD_treasure.ogg')
        self.sndOof = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg')
        self.sndAnvilLand = base.loadSfx('phase_4/audio/sfx/AA_drop_anvil_miss.ogg')
        self.sndPerfect = base.loadSfx('phase_4/audio/sfx/ring_perfect.ogg')
        self.__textGen = TextNode('partyCatchActivity')
        self.__textGen.setFont(ToontownGlobals.getSignFont())
        self.__textGen.setAlign(TextNode.ACenter)
        self.activityFSM.request('Idle')

    def __loadDropModels(self):
        for objType in PartyGlobals.DropObjectTypes:
            model = loader.loadModel(objType.modelPath)
            self.dropObjModels[objType.name] = model
            modelScales = {'apple': 0.7,
             'orange': 0.7,
             'pear': 0.5,
             'coconut': 0.7,
             'watermelon': 0.6,
             'pineapple': 0.45}
            if objType.name in modelScales:
                model.setScale(modelScales[objType.name])
            if objType == PartyGlobals.Name2DropObjectType['pear']:
                model.setZ(-.6)
            if objType == PartyGlobals.Name2DropObjectType['coconut']:
                model.setP(180)
            if objType == PartyGlobals.Name2DropObjectType['watermelon']:
                model.setH(135)
                model.setZ(-.5)
            if objType == PartyGlobals.Name2DropObjectType['pineapple']:
                model.setZ(-1.7)
            if objType == PartyGlobals.Name2DropObjectType['anvil']:
                model.setZ(-self.ObjRadius)
            model.flattenStrong()

    def unload(self):
        DistributedPartyCatchActivity.notify.debug('unload')
        self.finishAllDropIntervals()
        self.destroyOrthoWalk()
        DistributedPartyActivity.unload(self)
        self.stopDropTask()
        del self.activityFSM
        del self.__textGen
        for avId in self.toonSDs.keys():
            if avId in self.toonSDs:
                toonSD = self.toonSDs[avId]
                toonSD.unload()

        del self.toonSDs
        self.treesAndFence.removeNode()
        del self.treesAndFence
        self.dropShadow.removeNode()
        del self.dropShadow
        base.cr.parentMgr.unregisterParent(self._avatarNodePathParentToken)
        for model in self.dropObjModels.values():
            model.removeNode()

        del self.dropObjModels
        del self.sndGoodCatch
        del self.sndOof
        del self.sndAnvilLand
        del self.sndPerfect

    def setStartTimestamp(self, timestamp32):
        self.notify.info('setStartTimestamp(%s)' % (timestamp32,))
        self._startTimestamp = globalClockDelta.networkToLocalTime(timestamp32, bits=32)

    def getCurrentCatchActivityTime(self):
        return globalClock.getFrameTime() - self._startTimestamp

    def getObjModel(self, objName):
        return self.dropObjModels[objName].copyTo(hidden)

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

    def handleToonJoined(self, toonId):
        if toonId not in self.toonSDs:
            toonSD = PartyCatchActivityToonSD(toonId, self)
            self.toonSDs[toonId] = toonSD
            toonSD.load()
        self.notify.debug('handleToonJoined : currentState = %s' % self.activityFSM.state)
        self.cr.doId2do[toonId].useLOD(500)
        if self.activityFSM.state == 'Active':
            if toonId in self.toonSDs:
                self.toonSDs[toonId].enter()
            if base.localAvatar.doId == toonId:
                base.localAvatar.b_setParent(self._avatarNodePathParentToken)
                self.putLocalAvatarInActivity()
            if toonId in self.toonSDs:
                self.toonSDs[toonId].fsm.request('rules')

    def handleToonExited(self, toonId):
        self.notify.debug('handleToonExited( toonId=%s )' % toonId)
        if toonId in self.cr.doId2do:
            self.cr.doId2do[toonId].resetLOD()
            if toonId in self.toonSDs:
                self.toonSDs[toonId].fsm.request('notPlaying')
                self.toonSDs[toonId].exit()
                self.toonSDs[toonId].unload()
                del self.toonSDs[toonId]
            if base.localAvatar.doId == toonId:
                base.localAvatar.b_setParent(ToontownGlobals.SPRender)

    def takeLocalAvatarOutOfActivity(self):
        self.notify.debug('localToon has left the circle')
        base.camera.reparentTo(base.localAvatar)
        base.localAvatar.startUpdateSmartCamera()
        base.localAvatar.enableSmartCameraViews()
        base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex)
        DistributedSmoothNode.activateSmoothing(1, 0)

    def _enableCollisions(self):
        DistributedPartyActivity._enableCollisions(self)
        self._enteredTree = False
        self.accept('enter' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree)
        self.accept('again' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree)
        self.accept('exit' + self.catchTreeZoneEvent, self._toonExitedTree)
        self.accept(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT, self._handleCannonLanded)

    def _disableCollisions(self):
        self.ignore(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT)
        self.ignore('enter' + self.catchTreeZoneEvent)
        self.ignore('again' + self.catchTreeZoneEvent)
        self.ignore('exit' + self.catchTreeZoneEvent)
        DistributedPartyActivity._disableCollisions(self)

    def _handleCannonLanded(self):
        x = base.localAvatar.getX()
        y = base.localAvatar.getY()
        if x > self.x - self.StageHalfWidth and x < self.x + self.StageHalfWidth and y > self.y - self.StageHalfHeight and y < self.y + self.StageHalfHeight:
            self._toonEnteredTree(None)
        return

    def _toonMayHaveEnteredTree(self, collEntry):
        if self._enteredTree:
            return
        if base.localAvatar.controlManager.currentControls.getIsAirborne():
            return
        self._toonEnteredTree(collEntry)

    def _toonEnteredTree(self, collEntry):
        self.notify.debug('_toonEnteredTree : avid = %s' % base.localAvatar.doId)
        self.notify.debug('_toonEnteredTree : currentState = %s' % self.activityFSM.state)
        if self.isLocalToonInActivity():
            return
        if self.activityFSM.state == 'Active':
            base.cr.playGame.getPlace().fsm.request('activity')
            self.d_toonJoinRequest()
        elif self.activityFSM.state == 'Idle':
            base.cr.playGame.getPlace().fsm.request('activity')
            self.d_toonJoinRequest()
        self._enteredTree = True

    def _toonExitedTree(self, collEntry):
        self.notify.debug('_toonExitedTree : avid = %s' % base.localAvatar.doId)
        self._enteredTree = False
        if hasattr(base.cr.playGame.getPlace(), 'fsm') and self.activityFSM.state == 'Active' and self.isLocalToonInActivity():
            if base.localAvatar.doId in self.toonSDs:
                self.takeLocalAvatarOutOfActivity()
                self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying')
            self.d_toonExitDemand()

    def setToonsPlaying(self, toonIds):
        self.notify.info('setToonsPlaying(%s)' % (toonIds,))
        DistributedPartyActivity.setToonsPlaying(self, toonIds)
        if self.isLocalToonInActivity() and base.localAvatar.doId not in toonIds:
            if base.localAvatar.doId in self.toonSDs:
                self.takeLocalAvatarOutOfActivity()
                self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying')

    def __genText(self, text):
        self.__textGen.setText(text)
        return self.__textGen.generate()

    def getNumPlayers(self):
        return len(self.toonIds)

    def defineConstants(self, forceNumPlayers = None):
        DistributedPartyCatchActivity.notify.debug('defineConstants')
        self.ShowObjSpheres = 0
        self.ShowToonSpheres = 0
        self.useGravity = True
        self.trickShadows = True
        if forceNumPlayers is None:
            numPlayers = self.getNumPlayers()
        else:
            numPlayers = forceNumPlayers
        self.calcDifficultyConstants(numPlayers)
        DistributedPartyCatchActivity.notify.debug('ToonSpeed: %s' % self.ToonSpeed)
        DistributedPartyCatchActivity.notify.debug('total drops: %s' % self.totalDrops)
        DistributedPartyCatchActivity.notify.debug('numFruits: %s' % self.numFruits)
        DistributedPartyCatchActivity.notify.debug('numAnvils: %s' % self.numAnvils)
        self.ObjRadius = 1.0
        dropRegionTable = PartyRegionDropPlacer.getDropRegionTable(numPlayers)
        self.DropRows, self.DropColumns = len(dropRegionTable), len(dropRegionTable[0])
        for objType in PartyGlobals.DropObjectTypes:
            DistributedPartyCatchActivity.notify.debug('*** Object Type: %s' % objType.name)
            objType.onscreenDuration = objType.onscreenDurMult * self.BaselineOnscreenDropDuration
            DistributedPartyCatchActivity.notify.debug('onscreenDuration=%s' % objType.onscreenDuration)
            v_0 = 0.0
            t = objType.onscreenDuration
            x_0 = self.MinOffscreenHeight
            x = 0.0
            g = 2.0 * (x - x_0 - v_0 * t) / (t * t)
            DistributedPartyCatchActivity.notify.debug('gravity=%s' % g)
            objType.trajectory = Trajectory(0, Vec3(0, 0, x_0), Vec3(0, 0, v_0), gravMult=abs(g / Trajectory.gravity))
            objType.fallDuration = objType.onscreenDuration + self.OffscreenTime

        return

    def grid2world(self, column, row):
        x = column / float(self.DropColumns - 1)
        y = row / float(self.DropRows - 1)
        x = x * 2.0 - 1.0
        y = y * 2.0 - 1.0
        x *= self.StageHalfWidth
        y *= self.StageHalfHeight
        return (x, y)

    def showPosts(self):
        self.hidePosts()
        self.posts = [Toon.Toon(),
         Toon.Toon(),
         Toon.Toon(),
         Toon.Toon()]
        for i in xrange(len(self.posts)):
            tree = self.posts[i]
            tree.reparentTo(render)
            x = self.StageHalfWidth
            y = self.StageHalfHeight
            if i > 1:
                x = -x
            if i % 2:
                y = -y
            tree.setPos(x + self.x, y + self.y, 0)

    def hidePosts(self):
        if hasattr(self, 'posts'):
            for tree in self.posts:
                tree.removeNode()

            del self.posts

    def showDropGrid(self):
        self.hideDropGrid()
        self.dropMarkers = []
        for row in xrange(self.DropRows):
            self.dropMarkers.append([])
            rowList = self.dropMarkers[row]
            for column in xrange(self.DropColumns):
                toon = Toon.Toon()
                toon.setDNA(base.localAvatar.getStyle())
                toon.reparentTo(self.root)
                toon.setScale(1.0 / 3)
                x, y = self.grid2world(column, row)
                toon.setPos(x, y, 0)
                rowList.append(toon)

    def hideDropGrid(self):
        if hasattr(self, 'dropMarkers'):
            for row in self.dropMarkers:
                for marker in row:
                    marker.removeNode()

            del self.dropMarkers

    def handleToonDisabled(self, avId):
        DistributedPartyCatchActivity.notify.debug('handleToonDisabled')
        DistributedPartyCatchActivity.notify.debug('avatar ' + str(avId) + ' disabled')
        if avId in self.toonSDs:
            self.toonSDs[avId].exit(unexpectedExit=True)
        del self.toonSDs[avId]

    def turnOffSmoothingOnGuests(self):
        pass

    def setState(self, newState, timestamp):
        self.notify.info('setState(%s, %s)' % (newState, timestamp))
        DistributedPartyCatchActivity.notify.debug('setState( newState=%s, ... )' % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        self.activityFSM.request(newState)
        if newState == 'Active':
            if base.localAvatar.doId != self.party.partyInfo.hostId:
                if globalClock.getFrameCount() > self._generateFrame:
                    if base.localAvatar.getX() > self.x - self.StageHalfWidth and base.localAvatar.getX() < self.x + self.StageHalfWidth and base.localAvatar.getY() > self.y - self.StageHalfHeight and base.localAvatar.getY() < self.y + self.StageHalfHeight:
                        self._toonEnteredTree(None)
        return

    def putLocalAvatarInActivity(self):
        if base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(), 'fsm'):
            base.cr.playGame.getPlace().fsm.request('activity', [False])
        else:
            self.notify.info("Avoided crash: toontown.parties.DistributedPartyCatchActivity:632, toontown.parties.DistributedPartyCatchActivity:1198, toontown.parties.activityFSMMixins:49, direct.fsm.FSM:423, AttributeError: 'NoneType' object has no attribute 'fsm'")
        base.localAvatar.stopUpdateSmartCamera()
        base.camera.reparentTo(self.treesAndFence)
        base.camera.setPosHpr(0.0, -63.0, 30.0, 0.0, -20.0, 0.0)
        if not hasattr(self, 'ltLegsCollNode'):
            self.createCatchCollisions()

    def createCatchCollisions(self):
        radius = 0.7
        handler = CollisionHandlerEvent()
        handler.setInPattern('ltCatch%in')
        self.ltLegsCollNode = CollisionNode('catchLegsCollNode')
        self.ltLegsCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask)
        self.ltHeadCollNode = CollisionNode('catchHeadCollNode')
        self.ltHeadCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask)
        self.ltLHandCollNode = CollisionNode('catchLHandCollNode')
        self.ltLHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask)
        self.ltRHandCollNode = CollisionNode('catchRHandCollNode')
        self.ltRHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask)
        legsCollNodepath = base.localAvatar.attachNewNode(self.ltLegsCollNode)
        legsCollNodepath.hide()
        head = base.localAvatar.getHeadParts().getPath(2)
        headCollNodepath = head.attachNewNode(self.ltHeadCollNode)
        headCollNodepath.hide()
        lHand = base.localAvatar.getLeftHands()[0]
        lHandCollNodepath = lHand.attachNewNode(self.ltLHandCollNode)
        lHandCollNodepath.hide()
        rHand = base.localAvatar.getRightHands()[0]
        rHandCollNodepath = rHand.attachNewNode(self.ltRHandCollNode)
        rHandCollNodepath.hide()
        base.localAvatar.cTrav.addCollider(legsCollNodepath, handler)
        base.localAvatar.cTrav.addCollider(headCollNodepath, handler)
        base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler)
        base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler)
        if self.ShowToonSpheres:
            legsCollNodepath.show()
            headCollNodepath.show()
            lHandCollNodepath.show()
            rHandCollNodepath.show()
        self.ltLegsCollNode.addSolid(CollisionSphere(0, 0, radius, radius))
        self.ltHeadCollNode.addSolid(CollisionSphere(0, 0, 0, radius))
        self.ltLHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0))
        self.ltRHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0))
        self.toonCollNodes = [legsCollNodepath,
         headCollNodepath,
         lHandCollNodepath,
         rHandCollNodepath]

    def destroyCatchCollisions(self):
        if not hasattr(self, 'ltLegsCollNode'):
            return
        for collNode in self.toonCollNodes:
            while collNode.node().getNumSolids():
                collNode.node().removeSolid(0)

            base.localAvatar.cTrav.removeCollider(collNode)

        del self.toonCollNodes
        del self.ltLegsCollNode
        del self.ltHeadCollNode
        del self.ltLHandCollNode
        del self.ltRHandCollNode

    def timerExpired(self):
        pass

    def __handleCatch(self, generation, objNum):
        DistributedPartyCatchActivity.notify.debug('catch: %s' % [generation, objNum])
        if base.localAvatar.doId not in self.toonIds:
            return
        self.showCatch(base.localAvatar.doId, generation, objNum)
        objName = self._id2gen[generation].droppedObjNames[objNum]
        objTypeId = PartyGlobals.Name2DOTypeId[objName]
        self.sendUpdate('claimCatch', [generation, objNum, objTypeId])
        self.finishDropInterval(generation, objNum)

    def showCatch(self, avId, generation, objNum):
        if avId not in self.toonSDs:
            return
        isLocal = avId == base.localAvatar.doId
        if generation not in self._id2gen:
            return
        if not self._id2gen[generation].hasBeenScheduled:
            return
        objName = self._id2gen[generation].droppedObjNames[objNum]
        objType = PartyGlobals.Name2DropObjectType[objName]
        if objType.good:
            if objNum not in self._id2gen[generation].droppedObjCaught:
                if isLocal:
                    base.playSfx(self.sndGoodCatch)
                fruit = self.getObjModel(objName)
                toon = self.getAvatar(avId)
                rHand = toon.getRightHands()[1]
                self.toonSDs[avId].eatFruit(fruit, rHand)
        else:
            self.toonSDs[avId].fsm.request('fallForward')
        self._id2gen[generation].droppedObjCaught[objNum] = 1

    def setObjectCaught(self, avId, generation, objNum):
        self.notify.info('setObjectCaught(%s, %s, %s)' % (avId, generation, objNum))
        if self.activityFSM.state != 'Active':
            DistributedPartyCatchActivity.notify.warning('ignoring msg: object %s caught by %s' % (objNum, avId))
            return
        isLocal = avId == base.localAvatar.doId
        if not isLocal:
            DistributedPartyCatchActivity.notify.debug('AI: avatar %s caught %s' % (avId, objNum))
            self.finishDropInterval(generation, objNum)
            self.showCatch(avId, generation, objNum)
        self._scheduleGenerations()
        gen = self._id2gen[generation]
        if gen.hasBeenScheduled:
            objName = gen.droppedObjNames[objNum]
            if PartyGlobals.Name2DropObjectType[objName].good:
                if hasattr(self, 'fruitsCaught'):
                    self.fruitsCaught += 1

    def finishDropInterval(self, generation, objNum):
        if hasattr(self, 'dropIntervals'):
            if (generation, objNum) in self.dropIntervals:
                self.dropIntervals[generation, objNum].finish()

    def finishAllDropIntervals(self):
        if hasattr(self, 'dropIntervals'):
            for dropInterval in self.dropIntervals.values():
                dropInterval.finish()

    def setGenerations(self, generations):
        self.notify.info('setGenerations(%s)' % (generations,))
        gen2t = {}
        gen2nt = {}
        gen2np = {}
        for id, timestamp32, numPlayers in generations:
            gen2t[id] = globalClockDelta.networkToLocalTime(timestamp32, bits=32) - self._startTimestamp
            gen2nt[id] = timestamp32
            gen2np[id] = numPlayers

        ids = self._id2gen.keys()
        for id in ids:
            if id not in gen2t:
                self._removeGeneration(id)

        for id in gen2t:
            if id not in self._id2gen:
                self._addGeneration(id, gen2t[id], gen2nt[id], gen2np[id])

    def scheduleDrops(self, genId = None):
        if genId is None:
            genId = self.getCurGeneration()
        gen = self._id2gen[genId]
        if gen.hasBeenScheduled:
            return
        fruitIndex = int((gen.startTime + 0.5 * self.DropPeriod) / PartyGlobals.CatchActivityDuration)
        fruitNames = ['apple',
         'orange',
         'pear',
         'coconut',
         'watermelon',
         'pineapple']
        fruitName = fruitNames[fruitIndex % len(fruitNames)]
        rng = RandomNumGen(genId + self._generationSeedBase)
        gen.droppedObjNames = [fruitName] * self.numFruits + ['anvil'] * self.numAnvils
        rng.shuffle(gen.droppedObjNames)
        dropPlacer = PartyRegionDropPlacer(self, gen.numPlayers, genId, gen.droppedObjNames, startTime=gen.startTime)
        gen.numItemsDropped = 0
        tIndex = gen.startTime % PartyGlobals.CatchActivityDuration
        tPercent = float(tIndex) / PartyGlobals.CatchActivityDuration
        gen.numItemsDropped += dropPlacer.skipPercent(tPercent)
        while not dropPlacer.doneDropping(continuous=True):
            nextDrop = dropPlacer.getNextDrop()
            gen.dropSchedule.append(nextDrop)

        gen.hasBeenScheduled = True
        return

    def startDropTask(self):
        taskMgr.add(self.dropTask, self.DropTaskName)

    def stopDropTask(self):
        taskMgr.remove(self.DropTaskName)

    def _scheduleGenerations(self):
        curT = self.getCurrentCatchActivityTime()
        genIndex = self._orderedGenerationIndex
        newGenIndex = genIndex
        while genIndex is None or genIndex < len(self._orderedGenerations) - 1:
            if genIndex is None:
                nextGenIndex = 0
            else:
                nextGenIndex = genIndex + 1
            nextGenId = self._orderedGenerations[nextGenIndex]
            nextGen = self._id2gen[nextGenId]
            startT = nextGen.startTime
            if curT >= startT:
                newGenIndex = nextGenIndex
            if not nextGen.hasBeenScheduled:
                self.defineConstants(forceNumPlayers=nextGen.numPlayers)
                self.scheduleDrops(genId=self._orderedGenerations[nextGenIndex])
            genIndex = nextGenIndex

        self._orderedGenerationIndex = newGenIndex
        return

    def dropTask(self, task):
        self._scheduleGenerations()
        curT = self.getCurrentCatchActivityTime()
        if self._orderedGenerationIndex is not None:
            i = self._orderedGenerationIndex
            genIndex = self._orderedGenerations[i]
            gen = self._id2gen[genIndex]
            while len(gen.dropSchedule) > 0 and gen.dropSchedule[0][0] < curT:
                drop = gen.dropSchedule[0]
                gen.dropSchedule = gen.dropSchedule[1:]
                dropTime, objName, dropCoords = drop
                objNum = gen.numItemsDropped
                x, y = self.grid2world(*dropCoords)
                dropIval = self.getDropIval(x, y, objName, genIndex, objNum)

                def cleanup(generation, objNum, self = self):
                    del self.dropIntervals[generation, objNum]

                dropIval.append(Func(Functor(cleanup, genIndex, objNum)))
                self.dropIntervals[genIndex, objNum] = dropIval
                gen.numItemsDropped += 1
                dropIval.start(curT - dropTime)
                self._lastDropTime = dropTime

        return Task.cont

    def getDropIval(self, x, y, dropObjName, generation, num):
        objType = PartyGlobals.Name2DropObjectType[dropObjName]
        id = (generation, num)
        dropNode = hidden.attachNewNode('catchDropNode%s' % (id,))
        dropNode.setPos(x, y, 0)
        shadow = self.dropShadow.copyTo(dropNode)
        shadow.setZ(PartyGlobals.CatchDropShadowHeight)
        shadow.setColor(1, 1, 1, 1)
        object = self.getObjModel(dropObjName)
        object.reparentTo(hidden)
        if dropObjName in ['watermelon', 'anvil']:
            objH = object.getH()
            absDelta = {'watermelon': 12,
             'anvil': 15}[dropObjName]
            delta = (self.randomNumGen.random() * 2.0 - 1.0) * absDelta
            newH = objH + delta
        else:
            newH = self.randomNumGen.random() * 360.0
        object.setH(newH)
        sphereName = 'FallObj%s' % (id,)
        radius = self.ObjRadius
        if objType.good:
            radius *= lerp(1.0, 1.3, 0.5)
        collSphere = CollisionSphere(0, 0, 0, radius)
        collSphere.setTangible(0)
        collNode = CollisionNode(sphereName)
        collNode.setCollideMask(PartyGlobals.CatchActivityBitmask)
        collNode.addSolid(collSphere)
        collNodePath = object.attachNewNode(collNode)
        collNodePath.hide()
        if self.ShowObjSpheres:
            collNodePath.show()
        catchEventName = 'ltCatch' + sphereName

        def eatCollEntry(forward, collEntry):
            forward()

        self.accept(catchEventName, Functor(eatCollEntry, Functor(self.__handleCatch, id[0], id[1])))

        def cleanup(self = self, dropNode = dropNode, id = id, event = catchEventName):
            self.ignore(event)
            dropNode.removeNode()

        duration = objType.fallDuration
        onscreenDuration = objType.onscreenDuration
        targetShadowScale = 0.3
        if self.trickShadows:
            intermedScale = targetShadowScale * (self.OffscreenTime / self.BaselineDropDuration)
            shadowScaleIval = Sequence(LerpScaleInterval(shadow, self.OffscreenTime, intermedScale, startScale=0))
            shadowScaleIval.append(LerpScaleInterval(shadow, duration - self.OffscreenTime, targetShadowScale, startScale=intermedScale))
        else:
            shadowScaleIval = LerpScaleInterval(shadow, duration, targetShadowScale, startScale=0)
        targetShadowAlpha = 0.4
        shadowAlphaIval = LerpColorScaleInterval(shadow, self.OffscreenTime, Point4(1, 1, 1, targetShadowAlpha), startColorScale=Point4(1, 1, 1, 0))
        shadowIval = Parallel(shadowScaleIval, shadowAlphaIval)
        if self.useGravity:

            def setObjPos(t, objType = objType, object = object):
                z = objType.trajectory.calcZ(t)
                object.setZ(z)

            setObjPos(0)
            dropIval = LerpFunctionInterval(setObjPos, fromData=0, toData=onscreenDuration, duration=onscreenDuration)
        else:
            startPos = Point3(0, 0, self.MinOffscreenHeight)
            object.setPos(startPos)
            dropIval = LerpPosInterval(object, onscreenDuration, Point3(0, 0, 0), startPos=startPos, blendType='easeIn')
        ival = Sequence(Func(Functor(dropNode.reparentTo, self.root)), Parallel(Sequence(WaitInterval(self.OffscreenTime), Func(Functor(object.reparentTo, dropNode)), dropIval), shadowIval), Func(cleanup), name='drop%s' % (id,))
        if objType == PartyGlobals.Name2DropObjectType['anvil']:
            ival.append(Func(self.playAnvil))
        return ival

    def playAnvil(self):
        if base.localAvatar.doId in self.toonIds:
            base.playSfx(self.sndAnvilLand)

    def initOrthoWalk(self):
        DistributedPartyCatchActivity.notify.debug('startOrthoWalk')

        def doCollisions(oldPos, newPos, self = self):
            x = bound(newPos[0], self.StageHalfWidth, -self.StageHalfWidth)
            y = bound(newPos[1], self.StageHalfHeight, -self.StageHalfHeight)
            newPos.setX(x)
            newPos.setY(y)
            return newPos

        orthoDrive = OrthoDrive(self.ToonSpeed, instantTurn=True)
        self.orthoWalk = OrthoWalk(orthoDrive, broadcast=True)

    def destroyOrthoWalk(self):
        DistributedPartyCatchActivity.notify.debug('destroyOrthoWalk')
        if hasattr(self, 'orthoWalk'):
            self.orthoWalk.stop()
            self.orthoWalk.destroy()
            del self.orthoWalk

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

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

    def startActive(self):
        DistributedPartyCatchActivity.notify.debug('startActive')
        for avId in self.toonIds:
            if avId in self.toonSDs:
                toonSD = self.toonSDs[avId]
                toonSD.enter()
                toonSD.fsm.request('normal')

        self.fruitsCaught = 0
        self.dropIntervals = {}
        self.startDropTask()
        if base.localAvatar.doId in self.toonIds:
            self.putLocalAvatarInActivity()

    def finishActive(self):
        DistributedPartyCatchActivity.notify.debug('finishActive')
        self.stopDropTask()
        if hasattr(self, 'finishIval'):
            self.finishIval.pause()
            del self.finishIval
        if base.localAvatar.doId in self.toonIds:
            self.takeLocalAvatarOutOfActivity()
        for ival in self.dropIntervals.values():
            ival.finish()

        del self.dropIntervals

    def startConclusion(self):
        DistributedPartyCatchActivity.notify.debug('startConclusion')
        for avId in self.toonIds:
            if avId in self.toonSDs:
                toonSD = self.toonSDs[avId]
                toonSD.fsm.request('notPlaying')

        self.destroyCatchCollisions()
        if base.localAvatar.doId not in self.toonIds:
            return
        else:
            self.localToonExiting()
        if self.fruitsCaught >= self.numFruits:
            finishText = TTLocalizer.PartyCatchActivityFinishPerfect
        else:
            finishText = TTLocalizer.PartyCatchActivityFinish
        perfectTextSubnode = hidden.attachNewNode(self.__genText(finishText))
        perfectText = hidden.attachNewNode('perfectText')
        perfectTextSubnode.reparentTo(perfectText)
        frame = self.__textGen.getCardActual()
        offsetY = -abs(frame[2] + frame[3]) / 2.0
        perfectTextSubnode.setPos(0, 0, offsetY)
        perfectText.setColor(1, 0.1, 0.1, 1)

        def fadeFunc(t, text = perfectText):
            text.setColorScale(1, 1, 1, t)

        def destroyText(text = perfectText):
            text.removeNode()

        textTrack = Sequence(Func(perfectText.reparentTo, aspect2d), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5))
        soundTrack = SoundInterval(self.sndPerfect)
        self.finishIval = Parallel(textTrack, soundTrack)
        self.finishIval.start()

    def finishConclusion(self):
        DistributedPartyCatchActivity.notify.debug('finishConclusion')
        if base.localAvatar.doId in self.toonIds:
            self.takeLocalAvatarOutOfActivity()
            base.cr.playGame.getPlace().fsm.request('walk')

    def showJellybeanReward(self, earnedAmount, jarAmount, message):
        if earnedAmount > 0:
            DistributedPartyActivity.showJellybeanReward(self, earnedAmount, jarAmount, message)
        else:
            base.cr.playGame.getPlace().fsm.request('walk')
Example #57
0
    def getDropIval(self):
        shadow = self.shadow
        drop = self.drop
        id = self.id
        hangTime = Globals.ShadowTime
        dropTime = Globals.DropTime
        dropHeight = Globals.DropHeight
        targetShadowScale = 0.5
        targetShadowAlpha = 0.4
        shadowScaleIval = LerpScaleInterval(shadow,
                                            dropTime,
                                            targetShadowScale,
                                            startScale=0)
        shadowAlphaIval = LerpColorScaleInterval(
            shadow,
            hangTime,
            Point4(1, 1, 1, targetShadowAlpha),
            startColorScale=Point4(1, 1, 1, 0))
        shadowIval = Parallel(shadowScaleIval, shadowAlphaIval)
        startPos = Point3(0, 0, dropHeight)
        drop.setPos(startPos)
        dropIval = LerpPosInterval(drop,
                                   dropTime,
                                   Point3(0, 0, 0),
                                   startPos=startPos,
                                   blendType='easeIn')
        dropSoundIval = self._dropSfx
        dropSoundIval.node = self
        self.drop.setTransparency(1)

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

        scaleChange = 0.4 + random.random() / 4
        dropShakeSeq = Sequence(
            LerpScaleInterval(self.drop,
                              0.25,
                              Vec3(1.0 + scaleChange, 1.0 + scaleChange / 2,
                                   1.0 - scaleChange),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.25,
                              Vec3(1.0, 1.0, 1.0),
                              blendType='easeInOut'),
            Func(self.disableCollisionDamage),
            LerpScaleInterval(self.drop,
                              0.2,
                              Vec3(1.0 + scaleChange / 8,
                                   1.0 + scaleChange / 8,
                                   1.0 - scaleChange / 8),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.2,
                              Vec3(1.0, 1.0, 1.0),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.15,
                              Vec3(1.0 + scaleChange / 16,
                                   1.0 + scaleChange / 16,
                                   1.0 - scaleChange / 16),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.15,
                              Vec3(1.0, 1.0, 1.0),
                              blendType='easeInOut'),
            LerpScaleInterval(self.drop,
                              0.1,
                              Vec3(1.0 + scaleChange / 16,
                                   1.0 + scaleChange / 8,
                                   1.0 - scaleChange / 16),
                              blendType='easeInOut'),
            LerpColorScaleInterval(self.drop, Globals.DropFadeTime,
                                   Vec4(1.0, 1.0, 1.0, 0.0)))
        ival = Sequence(Func(self.reparentTo, render),
                        Parallel(Sequence(WaitInterval(hangTime), dropIval),
                                 shadowIval),
                        Parallel(Func(self.game.dropHit, self, id),
                                 dropSoundIval, dropShakeSeq),
                        Func(self.game.cleanupDrop, id),
                        name='drop%s' % id)
        self.ival = ival
        return ival
Example #58
0
    def getDropIval(self, x, y, dropObjName, generation, num):
        objType = PartyGlobals.Name2DropObjectType[dropObjName]
        id = (generation, num)
        dropNode = hidden.attachNewNode('catchDropNode%s' % (id,))
        dropNode.setPos(x, y, 0)
        shadow = self.dropShadow.copyTo(dropNode)
        shadow.setZ(PartyGlobals.CatchDropShadowHeight)
        shadow.setColor(1, 1, 1, 1)
        object = self.getObjModel(dropObjName)
        object.reparentTo(hidden)
        if dropObjName in ['watermelon', 'anvil']:
            objH = object.getH()
            absDelta = {'watermelon': 12,
             'anvil': 15}[dropObjName]
            delta = (self.randomNumGen.random() * 2.0 - 1.0) * absDelta
            newH = objH + delta
        else:
            newH = self.randomNumGen.random() * 360.0
        object.setH(newH)
        sphereName = 'FallObj%s' % (id,)
        radius = self.ObjRadius
        if objType.good:
            radius *= lerp(1.0, 1.3, 0.5)
        collSphere = CollisionSphere(0, 0, 0, radius)
        collSphere.setTangible(0)
        collNode = CollisionNode(sphereName)
        collNode.setCollideMask(PartyGlobals.CatchActivityBitmask)
        collNode.addSolid(collSphere)
        collNodePath = object.attachNewNode(collNode)
        collNodePath.hide()
        if self.ShowObjSpheres:
            collNodePath.show()
        catchEventName = 'ltCatch' + sphereName

        def eatCollEntry(forward, collEntry):
            forward()

        self.accept(catchEventName, Functor(eatCollEntry, Functor(self.__handleCatch, id[0], id[1])))

        def cleanup(self = self, dropNode = dropNode, id = id, event = catchEventName):
            self.ignore(event)
            dropNode.removeNode()

        duration = objType.fallDuration
        onscreenDuration = objType.onscreenDuration
        targetShadowScale = 0.3
        if self.trickShadows:
            intermedScale = targetShadowScale * (self.OffscreenTime / self.BaselineDropDuration)
            shadowScaleIval = Sequence(LerpScaleInterval(shadow, self.OffscreenTime, intermedScale, startScale=0))
            shadowScaleIval.append(LerpScaleInterval(shadow, duration - self.OffscreenTime, targetShadowScale, startScale=intermedScale))
        else:
            shadowScaleIval = LerpScaleInterval(shadow, duration, targetShadowScale, startScale=0)
        targetShadowAlpha = 0.4
        shadowAlphaIval = LerpColorScaleInterval(shadow, self.OffscreenTime, Point4(1, 1, 1, targetShadowAlpha), startColorScale=Point4(1, 1, 1, 0))
        shadowIval = Parallel(shadowScaleIval, shadowAlphaIval)
        if self.useGravity:

            def setObjPos(t, objType = objType, object = object):
                z = objType.trajectory.calcZ(t)
                object.setZ(z)

            setObjPos(0)
            dropIval = LerpFunctionInterval(setObjPos, fromData=0, toData=onscreenDuration, duration=onscreenDuration)
        else:
            startPos = Point3(0, 0, self.MinOffscreenHeight)
            object.setPos(startPos)
            dropIval = LerpPosInterval(object, onscreenDuration, Point3(0, 0, 0), startPos=startPos, blendType='easeIn')
        ival = Sequence(Func(Functor(dropNode.reparentTo, self.root)), Parallel(Sequence(WaitInterval(self.OffscreenTime), Func(Functor(object.reparentTo, dropNode)), dropIval), shadowIval), Func(cleanup), name='drop%s' % (id,))
        if objType == PartyGlobals.Name2DropObjectType['anvil']:
            ival.append(Func(self.playAnvil))
        return ival
 def __init__(self, gameObject=None):
     base.loadingScreen.beginStep('LegendaryGameGUI', 4, 20)
     self.gameObject = gameObject
     self.guiImage = loader.loadModel(
         'models/minigames/pir_m_gam_fsh_legendaryGui')
     self.UICompoments = {}
     self.uiBaseNode = NodePath('baseNode')
     self.uiBaseNode.reparentTo(aspect2d)
     self.uiBaseNode.show()
     self.leftBaseNode = NodePath('leftBaseNode')
     self.leftBaseNode.reparentTo(base.a2dLeftCenter)
     self.leftBaseNode.show()
     self.fishActor = None
     self.actorAnim = {}
     self.scaleSize = {
         InventoryType.Collection_Set11_Part1: 0.059999999999999998,
         InventoryType.Collection_Set11_Part2: 0.055,
         InventoryType.Collection_Set11_Part3: 0.12,
         InventoryType.Collection_Set11_Part4: 0.086999999999999994,
         InventoryType.Collection_Set11_Part5: 0.080000000000000002
     }
     self.meterFrame = DirectFrame(
         parent=self.leftBaseNode,
         frameSize=(-0.29999999999999999, 0.29999999999999999, -1.0, 0.0),
         frameColor=(1.0, 1.0, 1.0, 0.0),
         relief=None,
         state=DGG.DISABLED,
         pos=(1.0, 0.0, -0.45000000000000001),
         hpr=(0, 0, 0),
         scale=(1.3, 0.0, 1.3),
         image=self.guiImage.find('**/pir_t_gui_fsh_meter'),
         image_scale=(0.20000000000000001, 0.0, 0.80000000000000004),
         image_pos=(0, 0, 0),
         text='',
         textMayChange=1,
         text_scale=PiratesGuiGlobals.TextScaleTitleLarge,
         text_pos=(-0.55000000000000004, 0.10000000000000001),
         text_shadow=PiratesGuiGlobals.TextShadow)
     self.UICompoments['meterFrame'] = self.meterFrame
     self.fishingRod = DirectFrame(
         parent=self.meterFrame,
         frameSize=(-0.29999999999999999, 0.29999999999999999, -1.0, 0.0),
         relief=None,
         state=DGG.DISABLED,
         pos=FishingGlobals.fishingRodScreenPosition,
         image=self.guiImage.find('**/pir_t_gui_fsh_fullRod'),
         image_scale=(1.0, 0.0, 0.125),
         image_pos=(0.20000000000000001, 0, 0))
     self.fishingRod.setR(FishingGlobals.fishingRodInitSlope)
     self.UICompoments['fishingRod'] = self.fishingRod
     base.loadingScreen.tick()
     self.fishingHandleBaseFrame = DirectFrame(
         parent=self.uiBaseNode,
         frameSize=(-0.29999999999999999, 0.29999999999999999, -1.5, 1.5),
         frameColor=(1.0, 1.0, 1.0, 0.0),
         relief=None,
         state=DGG.DISABLED,
         pos=(0.0, 0.0, 0.0),
         hpr=(0, 0, 0),
         scale=(0.71999999999999997, 0.0, 0.71999999999999997),
         image=self.guiImage.find('**/pir_t_gui_fsh_partialRod'),
         image_scale=(3.7999999999999998, 0.0, 1.8999999999999999),
         image_pos=(0, 0, 0),
         image_hpr=(0.0, 0.0, 0))
     self.fishingHandleBaseFrame.hide()
     self.UICompoments[
         'fishingHandleBaseFrame'] = self.fishingHandleBaseFrame
     self.fishingHandle = DirectFrame(
         parent=self.fishingHandleBaseFrame,
         frameSize=(-0.080000000000000002, 0.080000000000000002,
                    -0.20000000000000001, 0.20000000000000001),
         relief=None,
         state=DGG.DISABLED,
         pos=(-0.10000000000000001, 0.0, -0.050000000000000003),
         hpr=(0, 0, 0),
         image=self.guiImage.find('**/pir_t_gui_fsh_handleArm'),
         image_scale=(1.0, 0.0, 1.0),
         image_pos=(-0.042000000000000003, 0, -0.115),
         image_hpr=(0.0, 0.0, 0))
     self.UICompoments['fishingHandle'] = self.fishingHandle
     self.arrowImage = DirectFrame(
         parent=self.fishingHandleBaseFrame,
         frameSize=(-0.40000000000000002, 0.40000000000000002,
                    -0.40000000000000002, 0.40000000000000002),
         relief=None,
         state=DGG.DISABLED,
         pos=(0.0, 0.0, 0.0),
         hpr=(0, 0, 0),
         scale=(1.2, 0.0, 1.2),
         image=self.guiImage.find('**/pir_t_gui_fsh_arrow'),
         image_scale=(1.0, 0.0, 1.0),
         image_pos=(0.0, 0, 0.0),
         image_hpr=(0.0, 0.0, 0.0))
     self.arrowImage.hide()
     self.UICompoments['arrowImage'] = self.arrowImage
     btnGeom = (self.guiImage.find('**/pir_t_gui_fsh_handle'),
                self.guiImage.find('**/pir_t_gui_fsh_handle'),
                self.guiImage.find('**/pir_t_gui_fsh_handleOn'))
     self.fishingHandleButton = GuiButton(pos=(-0.29999999999999999, 0,
                                               -0.55000000000000004),
                                          hpr=(0, 0, 0),
                                          scale=0.45000000000000001,
                                          image=btnGeom,
                                          image_pos=(0, 0, 0),
                                          image_scale=1.0,
                                          sortOrder=2)
     self.fishingHandleButton.bind(DGG.B1PRESS, self.handleButtonClicked)
     self.fishingHandleButton.reparentTo(self.fishingHandle)
     self.UICompoments['fishingHandleButton'] = self.fishingHandleButton
     self.fishingHandleBaseFrame.setTransparency(TransparencyAttrib.MAlpha)
     self.meterFrame.setTransparency(TransparencyAttrib.MAlpha)
     self.lineOneTransitTextNode = TextNode('lineOneTransitText')
     self.lineOneTransitTextNode.setFont(PiratesGlobals.getPirateFont())
     self.lineOneTransitTextNode.setText('')
     self.lineOneTransitTextNode.setAlign(TextNode.ACenter)
     self.lineOneTransitTextNode.setTextColor(1.0, 1.0, 1.0, 0.5)
     self.lineOneTransitTextNodePath = NodePath(self.lineOneTransitTextNode)
     self.lineOneTransitTextNodePath.setPos(0.0, 0.0, -0.80000000000000004)
     self.lineOneTransitTextNodePath.setScale(0.34999999999999998,
                                              0.34999999999999998,
                                              0.34999999999999998)
     self.lineOneTransitTextNodePath.reparentTo(self.uiBaseNode)
     self.lineOneTransitTextNodePath.hide()
     self.UICompoments[
         'lineOneTransitText'] = self.lineOneTransitTextNodePath
     self.lineTwoTransitTextNode = TextNode('lineTwoTransitText')
     self.lineTwoTransitTextNode.setFont(PiratesGlobals.getPirateFont())
     self.lineTwoTransitTextNode.setText('')
     self.lineTwoTransitTextNode.setAlign(TextNode.ACenter)
     self.lineTwoTransitTextNode.setTextColor(1.0, 1.0, 1.0, 0.5)
     self.lineTwoTransitTextNodePath = NodePath(self.lineTwoTransitTextNode)
     self.lineTwoTransitTextNodePath.setPos(-0.40000000000000002, 0.0,
                                            -0.94999999999999996)
     self.lineTwoTransitTextNodePath.setScale(0.12, 0.12, 0.12)
     self.lineTwoTransitTextNodePath.reparentTo(self.uiBaseNode)
     self.lineTwoTransitTextNodePath.hide()
     self.UICompoments[
         'lineTwoTransitText'] = self.lineTwoTransitTextNodePath
     base.loadingScreen.tick()
     self.test_guiImage = loader.loadModel('models/gui/toplevel_gui')
     self.buttonIcon = (
         self.test_guiImage.find('**/treasure_chest_closed'),
         self.test_guiImage.find('**/treasure_chest_closed'),
         self.test_guiImage.find('**/treasure_chest_closed_over'))
     self.winImagePanel = GuiPanel.GuiPanel('', 2.6000000000000001,
                                            1.8999999999999999, True)
     self.winImagePanel.setPos(-1.3, 0.0, -0.94999999999999996)
     self.winImagePanel.reparentTo(self.uiBaseNode)
     self.winImagePanel.background = OnscreenImage(
         parent=self.winImagePanel,
         scale=(2.3999999999999999, 0, 1.8),
         image=self.guiImage.find('**/pir_t_gui_fsh_posterBackground'),
         hpr=(0, 0, 0),
         pos=(1.3, 0, 0.94999999999999996))
     self.winImagePanel.setBin('gui-popup', -4)
     self.winTitleTextNode = TextNode('winTitleTextNode')
     self.winTitleTextNode.setText('Congratulations!')
     self.winTitleTextNode.setAlign(TextNode.ACenter)
     self.winTitleTextNode.setFont(PiratesGlobals.getPirateFont())
     self.winTitleTextNode.setTextColor(0.23000000000000001,
                                        0.089999999999999997,
                                        0.029999999999999999, 1.0)
     self.winTitleTextNodePath = NodePath(self.winTitleTextNode)
     self.winTitleTextNodePath.setPos(1.3500000000000001, 0.0,
                                      1.6699999999999999)
     self.winTitleTextNodePath.setScale(0.17999999999999999)
     self.winTitleTextNodePath.reparentTo(self.winImagePanel)
     self.wholeStoryTextNode = TextNode('storyTextNode')
     self.wholeStoryTextNode.setText('')
     self.wholeStoryTextNode.setWordwrap(19.0)
     self.wholeStoryTextNode.setTextColor(0.23000000000000001,
                                          0.089999999999999997,
                                          0.029999999999999999, 1.0)
     self.wholeStoryTextNodePath = NodePath(self.wholeStoryTextNode)
     self.wholeStoryTextNodePath.setPos(0.33000000000000002, 0.0,
                                        1.6399999999999999)
     self.wholeStoryTextNodePath.setScale(0.050000000000000003)
     self.wholeStoryTextNodePath.reparentTo(self.winImagePanel)
     self.winImagePanel.closeButton[
         'command'] = self.closeDialogGotNextState
     self.winImagePanel.closeButton['extraArgs'] = [
         'winImagePanel', 'FarewellLegendaryFish', False
     ]
     self.UICompoments['winImagePanel'] = self.winImagePanel
     self.winImagePanel.hide()
     self.luiCloseDialogSequence = Sequence()
     self.arrowImageRotationInterval = LerpHprInterval(
         self.arrowImage, 2.2000000000000002,
         self.arrowImage.getHpr() + Point3(0.0, 0.0, 280.0),
         self.arrowImage.getHpr())
     self.luiArrowRotatingSequence = Sequence(
         Func(self.showGui, ['arrowImage']),
         Parallel(Func(self.arrowImageRotationInterval.start),
                  Wait(2.2000000000000002)),
         Func(self.hideGui, ['arrowImage']),
         Func(self.arrowImage.setHpr,
              self.arrowImage.getHpr() + Point3(0.0, 0.0, 5.0)),
         name=self.gameObject.distributedFishingSpot.uniqueName(
             'luiArrowRotatingSequence'))
     self.lineOneColorChange = LerpColorScaleInterval(
         self.lineOneTransitTextNodePath,
         FishingGlobals.legendaryTransitionTextDuration,
         (1.0, 1.0, 1.0, 0.0), (1.0, 1.0, 1.0, 1.0),
         blendType='easeOut')
     self.lineOnePosChange = LerpPosInterval(
         self.lineOneTransitTextNodePath,
         FishingGlobals.legendaryTransitionTextDuration,
         (0.0, 0.0, -0.20000000000000001), (0.0, 0.0, -0.80000000000000004),
         blendType='easeOut')
     self.lineTwoCholorChange = LerpColorScaleInterval(
         self.lineTwoTransitTextNodePath,
         FishingGlobals.legendaryTransitionTextDuration,
         (1.0, 1.0, 1.0, 1.0), (1.0, 1.0, 1.0, 1.0),
         blendType='easeOut')
     self.lineTwoPosChange = LerpPosInterval(
         self.lineTwoTransitTextNodePath,
         FishingGlobals.legendaryTransitionTextDuration,
         (0.0, 0.0, -0.32000000000000001), (0.0, 0.0, -0.94999999999999996),
         blendType='easeOut')
     self.transitionTextMovingSequence = Sequence(
         Func(self.lineOneTransitTextNodePath.show),
         Func(self.lineTwoTransitTextNodePath.show),
         Parallel(self.lineOnePosChange, self.lineTwoPosChange,
                  self.lineOneColorChange, self.lineTwoCholorChange),
         Func(self.lineOneTransitTextNodePath.hide),
         Func(self.lineTwoTransitTextNodePath.hide),
         name=self.gameObject.distributedFishingSpot.uniqueName(
             'transitionTextMovingSequence'))
     self.meterFadeInInterval = Sequence(
         Func(self.meterFrame.show),
         LerpColorScaleInterval(
             self.meterFrame,
             FishingGlobals.legendaryTransitionTextDuration,
             colorScale=(1.0, 1.0, 1.0, 1.0),
             startColorScale=(1.0, 1.0, 1.0, 0.0),
             blendType='easeOut'),
         name='FadeInLegendaryMeter')
     self.meterFadeOutInterval = Sequence(LerpColorScaleInterval(
         self.meterFrame,
         FishingGlobals.legendaryTransitionTextDuration,
         colorScale=(1.0, 1.0, 1.0, 0.0),
         startColorScale=(1.0, 1.0, 1.0, 1.0),
         blendType='easeOut'),
                                          Func(self.meterFrame.hide),
                                          name='FadeOutLegendaryMeter')
     self.rodFadeInInterval = Sequence(
         Func(self.fishingHandleBaseFrame.show),
         LerpColorScaleInterval(
             self.fishingHandleBaseFrame,
             FishingGlobals.legendaryTransitionTextDuration,
             colorScale=(1.0, 1.0, 1.0, 1.0),
             startColorScale=(1.0, 1.0, 1.0, 0.0),
             blendType='easeOut'),
         name='FadeInLegendaryRodInterface')
     self.rodFadeOutInterval = Sequence(
         LerpColorScaleInterval(
             self.fishingHandleBaseFrame,
             FishingGlobals.legendaryTransitionTextDuration,
             colorScale=(1.0, 1.0, 1.0, 0.0),
             startColorScale=(1.0, 1.0, 1.0, 1.0),
             blendType='easeOut'),
         Func(self.fishingHandleBaseFrame.hide),
         name='FadeOutLegendaryRodInterface')
     base.loadingScreen.tick()
     smallScale = self.fishingHandleButton['scale']
     bigScale = self.fishingHandleButton['scale'] * 1.2
     self.buttonGrowUpInterval = LerpScaleInterval(self.fishingHandleButton,
                                                   1.0, bigScale,
                                                   smallScale)
     self.luiFightTransitSequence = Sequence(
         Parallel(Func(self.fishingHandleBaseFrame.show),
                  Func(self.meterFadeOutInterval.start),
                  Func(self.rodFadeInInterval.start),
                  Func(self.buttonGrowUpInterval.start)),
         Wait(1.0),
         Func(self.meterFrame.hide),
         name=self.gameObject.distributedFishingSpot.uniqueName(
             'luiFightTransitSequence'))
     self.luiReelTransitSequence = Sequence(
         Parallel(Func(self.fishingHandleBaseFrame.show),
                  Func(self.meterFadeOutInterval.start),
                  Func(self.rodFadeInInterval.start)),
         Wait(1.0),
         Func(self.meterFrame.hide),
         name=self.gameObject.distributedFishingSpot.uniqueName(
             'luiReelTransitSequence'))
     self.luiStruggleTransitSequence = Sequence(
         Parallel(Func(self.meterFrame.show), Func(self.resetFishingRod),
                  self.meterFadeInInterval, self.rodFadeOutInterval),
         Wait(1.0),
         Func(self.fishingHandleBaseFrame.hide),
         name=self.gameObject.distributedFishingSpot.uniqueName(
             'luiStruggleTransitSequence'))
     self.meterFadeOutInterval.start()
     self.rodFadeOutInterval.start()
     self.hideAllGUI()
     base.loadingScreen.endStep('LegendaryGameGUI')
Example #60
0
class DistributedBoat(DistributedObject):
    notify = directNotify.newCategory("DistributedBoat")

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.fsm = ClassicFSM('DistributedBoat', [
            State('off', self.enterOff, self.exitOff),
            State('eastToWest', self.enterEastToWest, self.exitEastToWest),
            State('westToEast', self.enterWestToEast, self.exitWestToEast)
        ], 'off', 'off')
        self.boat = None
        self.eastPier = None
        self.eastPierPath = 'east_pier'
        self.westPier = None
        self.westPierPath = 'west_pier'
        self.pierUpP = 0.0
        self.pierDownP = -45.0
        self.fogHorn = 'phase_5/audio/sfx/SZ_DD_foghorn.ogg'
        self.shipBell = 'phase_6/audio/sfx/SZ_DD_shipbell.ogg'
        self.waterLap = 'phase_6/audio/sfx/SZ_DD_waterlap.ogg'
        self.dockCreak = 'phase_6/audio/sfx/SZ_DD_dockcreak.ogg'
        self.eastWest = 'phase_6/paths/dd-e-w.bam'
        self.westEast = 'phase_6/paths/dd-w-e.bam'
        self.boatPath = '*donalds_boat*'
        self.track = None
        self.state = None

    def __handleOnBoat(self, entry):
        base.localAvatar.b_setParent(CIGlobals.SPDonaldsBoat)
        base.playSfx(self.soundWaterLap, looping=1)

    def __handleOffBoat(self, entry):
        base.localAvatar.b_setParent(CIGlobals.SPRender)
        self.soundWaterLap.stop()

    def __pollBoat(self, task):
        try:
            self.boat = self.cr.playGame.hood.loader.geom.find('**/' +
                                                               self.boatPath)
        except:
            return task.cont
        self.generated()
        return task.done

    def generate(self):
        DistributedObject.generate(self)
        self.soundFogHorn = base.loadSfx(self.fogHorn)
        self.soundShipBell = base.loadSfx(self.shipBell)
        self.soundWaterLap = base.loadSfx(self.waterLap)
        self.soundDockCreak = base.loadSfx(self.dockCreak)
        #try:
        #    self.boat = self.cr.playGame.hood.loader.geom.find('**/' + self.boatPath)
        #except:
        #        base.taskMgr.add(self.__pollBoat, self.uniqueName('__pollBoat'))
        #        return
        self.boat = self.cr.playGame.hood.loader.geom.find('**/' +
                                                           self.boatPath)
        self.generated()

    def generated(self):
        self.eastPier = self.cr.playGame.hood.loader.geom.find(
            '**/' + self.eastPierPath)
        self.westPier = self.cr.playGame.hood.loader.geom.find(
            '**/' + self.westPierPath)
        base.cr.parentMgr.registerParent(CIGlobals.SPDonaldsBoat, self.boat)
        self.accept('enterdonalds_boat_floor', self.__handleOnBoat)
        self.accept('exitdonalds_boat_floor', self.__handleOffBoat)
        self.d_requestCurrentStateAndTimestamp()
        self.fsm.enterInitialState()

    def disable(self):
        base.taskMgr.remove(self.uniqueName('__pollBoat'))
        base.cr.parentMgr.unregisterParent(CIGlobals.SPDonaldsBoat)
        self.ignore('enterdonalds_boat_floor')
        self.ignore('exitdonalds_boat_floor')
        self.fsm.requestFinalState()
        del self.fsm
        del self.soundFogHorn
        del self.soundShipBell
        del self.soundWaterLap
        del self.soundDockCreak
        self.fogHorn = None
        self.shipBell = None
        self.waterLap = None
        self.dockCreak = None
        self.boat = None
        self.track = None
        self.pierDownP = None
        self.pierUpP = None
        self.eastPier = None
        self.eastPierPath = None
        self.westPier = None
        self.westPierPath = None
        self.boatPath = None
        self.westEast = None
        self.eastWest = None
        DistributedObject.disable(self)

    def currentStateAndTimestamp(self, state, timestamp):
        self.setState(state, timestamp)

    def d_requestCurrentStateAndTimestamp(self):
        self.sendUpdate('requestCurrentStateAndTimestamp', [])

    def setState(self, state, timestamp=None):
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)
        self.state = state
        if self.boat:
            self.fsm.request(state, [ts])

    def enterEastToWest(self, ts=0):
        moPath = Mopath.Mopath()
        moPath.loadFile(self.eastWest)
        moIval = MopathInterval(moPath, self.boat)

        self.track = Parallel(
            SoundInterval(self.soundShipBell, node=self.boat),
            SoundInterval(self.soundDockCreak, node=self.eastPier), moIval,
            LerpQuatInterval(self.eastPier,
                             duration=5.0,
                             quat=(90, self.pierDownP, 0),
                             startHpr=(90, self.pierUpP, 0)),
            Sequence(
                Wait(15.0),
                Parallel(
                    LerpQuatInterval(self.westPier,
                                     duration=5.0,
                                     quat=(-90, self.pierUpP, 0),
                                     startHpr=(-90, self.pierDownP, 0)),
                    Sequence(
                        Wait(2.0),
                        SoundInterval(self.soundDockCreak,
                                      node=self.westPier))),
                SoundInterval(self.soundFogHorn, node=self.boat)))
        self.track.start(ts)

    def exitEastToWest(self):
        if self.track:
            self.track.finish()
            self.track = None

    def enterWestToEast(self, ts=0):
        moPath = Mopath.Mopath()
        moPath.loadFile(self.westEast)
        moIval = MopathInterval(moPath, self.boat)

        self.track = Parallel(
            SoundInterval(self.soundShipBell, node=self.boat),
            SoundInterval(self.soundDockCreak, node=self.westPier), moIval,
            LerpQuatInterval(self.westPier,
                             duration=5.0,
                             quat=(-90, self.pierDownP, 0),
                             startHpr=(-90, self.pierUpP, 0)),
            Sequence(
                Wait(15.0),
                Parallel(
                    LerpQuatInterval(self.eastPier,
                                     duration=5.0,
                                     quat=(90, self.pierUpP, 0),
                                     startHpr=(90, self.pierDownP, 0)),
                    Sequence(
                        Wait(2.0),
                        SoundInterval(self.soundDockCreak,
                                      node=self.eastPier))),
                SoundInterval(self.soundFogHorn, node=self.boat)))
        self.track.start(ts)

    def exitWestToEast(self):
        if self.track:
            self.track.finish()
            self.track = None

    def enterOff(self):
        pass

    def exitOff(self):
        pass