コード例 #1
0
class DistributedPartyTugOfWarActivity(DistributedPartyTeamActivity):
    notify = directNotify.newCategory('DistributedPartyTugOfWarActivity')

    def __init__(self, cr):
        DistributedPartyTeamActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTugOfWar, startDelay=PartyGlobals.TugOfWarStartDelay)
        self.buttons = [0, 1]
        self.arrowKeys = None
        self.keyTTL = []
        self.idealRate = 0.0
        self.keyRate = 0
        self.allOutMode = False
        self.rateMatchAward = 0.0
        self.toonIdsToStartPositions = {}
        self.toonIdsToIsPullingFlags = {}
        self.toonIdsToRightHands = {}
        self.fallenToons = []
        self.fallenPositions = []
        self.unusedFallenPositionsIndices = [0,
         1,
         2,
         3]
        self.toonIdsToAnimIntervals = {}
        self.tugRopes = []
        return

    def generate(self):
        DistributedPartyTeamActivity.generate(self)
        self._hopOffFinishedSV = StateVar(True)
        self._rewardFinishedSV = StateVar(True)
        self._isWalkStateReadyFC = FunctionCall(self._testWalkStateReady, self._hopOffFinishedSV, self._rewardFinishedSV)

    def delete(self):
        self._isWalkStateReadyFC.destroy()
        self._hopOffFinishedSV.destroy()
        self._rewardFinishedSV.destroy()
        DistributedPartyTeamActivity.delete(self)

    def handleToonJoined(self, toonId):
        DistributedPartyTeamActivity.handleToonJoined(self, toonId)
        self.toonIdsToAnimIntervals[toonId] = None
        if toonId == base.localAvatar.doId:
            base.cr.playGame.getPlace().fsm.request('activity')
            camera.wrtReparentTo(self.root)
            self.cameraMoveIval = LerpPosHprInterval(camera, 1.5, PartyGlobals.TugOfWarCameraPos, PartyGlobals.TugOfWarCameraInitialHpr, other=self.root)
            self.cameraMoveIval.start()
            self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam)
            self.notify.debug('posIndex: %d' % self.localToonPosIndex)
            toon = self.getAvatar(toonId)
            targetPos = self.dockPositions[self.localToonTeam][self.localToonPosIndex]
            if toon.getZ(self.root) < PartyGlobals.TugOfWarToonPositionZ:
                toon.setZ(self.root, PartyGlobals.TugOfWarToonPositionZ)
            targetH = fitDestAngle2Src(toon.getH(self.root), PartyGlobals.TugOfWarHeadings[self.localToonTeam])
            travelVector = targetPos - toon.getPos(self.root)
            duration = travelVector.length() / 5.0
            if self.toonIdsToAnimIntervals[toonId] is not None:
                self.toonIdsToAnimIntervals[toonId].finish()
            self.toonIdsToAnimIntervals[toonId] = Sequence(Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, 'run'), LerpPosHprInterval(toon, duration, targetPos, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, 'neutral'))
            self.toonIdsToAnimIntervals[toonId].start()
        return

    def handleToonExited(self, toonId):
        DistributedPartyTeamActivity.handleToonExited(self, toonId)
        if toonId == base.localAvatar.doId:
            self.cameraMoveIval.pause()
            if toonId not in self.fallenToons:
                if toonId in self.toonIdsToAnimIntervals and self.toonIdsToAnimIntervals[toonId] is not None:
                    self.toonIdsToAnimIntervals[toonId].finish()
                toon = self.getAvatar(toonId)
                targetH = fitDestAngle2Src(toon.getH(self.root), 180.0)
                targetPos = self.hopOffPositions[self.getTeam(toonId)][self.getIndex(toonId, self.getTeam(toonId))]
                hopOffAnim = Sequence(Func(toon.startPosHprBroadcast, 0.1), toon.hprInterval(0.2, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, toon, targetPos, 5.0, self.root), Func(toon.stopPosHprBroadcast), Func(toon.sendCurrentPosition), Func(self.hopOffFinished, toonId))
                self.toonIdsToAnimIntervals[toonId] = hopOffAnim
                self._hopOffFinishedSV.set(False)
                self.toonIdsToAnimIntervals[toonId].start()
            else:
                self._hopOffFinishedSV.set(True)
                del self.toonIdsToAnimIntervals[toonId]
        return

    def handleRewardDone(self):
        self._rewardFinishedSV.set(True)

    def _testWalkStateReady(self, hoppedOff, rewardFinished):
        if hoppedOff and rewardFinished:
            DistributedPartyTeamActivity.handleRewardDone(self)

    def hopOffFinished(self, toonId):
        if hasattr(self, 'toonIdsToAnimIntervals') and toonId in self.toonIdsToAnimIntervals:
            del self.toonIdsToAnimIntervals[toonId]
        if toonId == base.localAvatar.doId:
            if hasattr(self._hopOffFinishedSV, '_value'):
                self._hopOffFinishedSV.set(True)

    def handleToonShifted(self, toonId):
        if toonId == base.localAvatar.doId:
            self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam)
            if self.toonIdsToAnimIntervals[toonId] is not None:
                self.toonIdsToAnimIntervals[toonId].finish()
            toon = self.getAvatar(toonId)
            targetPos = self.dockPositions[self.localToonTeam][self.localToonPosIndex]
            self.toonIdsToAnimIntervals[toonId] = Sequence(Wait(0.6), Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, 'run'), toon.posInterval(0.5, targetPos, other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, 'neutral'))
            self.toonIdsToAnimIntervals[toonId].start()
        return

    def handleToonDisabled(self, toonId):
        if toonId in self.toonIdsToAnimIntervals:
            if self.toonIdsToAnimIntervals[toonId]:
                if self.toonIdsToAnimIntervals[toonId].isPlaying():
                    self.toonIdsToAnimIntervals[toonId].finish()
            else:
                self.notify.debug('self.toonIdsToAnimIntervals[%d] is none' % toonId)

    def setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds):
        DistributedPartyTeamActivity.setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds)
        self.toonIdsToRightHands.clear()
        for toonId in self.getToonIdsAsList():
            toon = self.getAvatar(toonId)
            if toon:
                self.toonIdsToRightHands[toonId] = toon.getRightHands()[0]

    def load(self):
        DistributedPartyTeamActivity.load(self)
        self.loadModels()
        self.loadGuiElements()
        self.loadSounds()
        self.loadIntervals()
        self.arrowKeys = ArrowKeys()

    def loadModels(self):
        self.playArea = loader.loadModel('phase_13/models/parties/partyTugOfWar')
        self.playArea.reparentTo(self.root)
        self.sign.reparentTo(self.playArea.find('**/TugOfWar_sign_locator'))
        self.dockPositions = [[], []]
        for i in range(4):
            self.dockPositions[0].append(Point3(-PartyGlobals.TugOfWarInitialToonPositionsXOffset - PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ))

        for i in range(4):
            self.dockPositions[1].append(Point3(PartyGlobals.TugOfWarInitialToonPositionsXOffset + PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ))

        self.hopOffPositions = [[], []]
        for i in range(1, 5):
            self.hopOffPositions[PartyGlobals.TeamActivityTeams.LeftTeam].append(self.playArea.find('**/leftTeamHopOff%d_locator' % i).getPos())
            self.hopOffPositions[PartyGlobals.TeamActivityTeams.RightTeam].append(self.playArea.find('**/rightTeamHopOff%d_locator' % i).getPos())

        for i in range(1, 5):
            pos = self.playArea.find('**/fallenToon%d_locator' % i).getPos()
            self.fallenPositions.append(pos)

        self.joinCollision = []
        self.joinCollisionNodePaths = []
        for i in range(len(PartyGlobals.TeamActivityTeams)):
            collShape = CollisionTube(PartyGlobals.TugOfWarJoinCollisionEndPoints[0], PartyGlobals.TugOfWarJoinCollisionEndPoints[1], PartyGlobals.TugOfWarJoinCollisionRadius)
            collShape.setTangible(True)
            self.joinCollision.append(CollisionNode('TugOfWarJoinCollision%d' % i))
            self.joinCollision[i].addSolid(collShape)
            tubeNp = self.playArea.attachNewNode(self.joinCollision[i])
            tubeNp.node().setCollideMask(ToontownGlobals.WallBitmask)
            self.joinCollisionNodePaths.append(tubeNp)
            self.joinCollisionNodePaths[i].setPos(PartyGlobals.TugOfWarJoinCollisionPositions[i])

        self.__enableCollisions()
        ropeModel = loader.loadModel('phase_4/models/minigames/tug_of_war_rope')
        self.ropeTexture = ropeModel.findTexture('*')
        ropeModel.removeNode()
        for i in range(PartyGlobals.TugOfWarMaximumPlayersPerTeam * 2 - 1):
            rope = Rope(self.uniqueName('TugRope%d' % i))
            if rope.showRope:
                rope.ropeNode.setRenderMode(RopeNode.RMBillboard)
                rope.ropeNode.setThickness(0.2)
                rope.setTexture(self.ropeTexture)
                rope.ropeNode.setUvMode(RopeNode.UVDistance)
                rope.ropeNode.setUvDirection(1)
                rope.setTransparency(1)
                rope.setColor(0.89, 0.89, 0.6, 1.0)
                rope.reparentTo(self.root)
                rope.stash()
            self.tugRopes.append(rope)

        self.splash = Splash.Splash(self.root)
        self.splash.setScale(2.0, 4.0, 1.0)
        pos = self.fallenPositions[0]
        self.splash.setPos(pos[0], pos[1], PartyGlobals.TugOfWarSplashZOffset)
        self.splash.hide()

    def loadGuiElements(self):
        self.powerMeter = MinigamePowerMeter(PartyGlobals.TugOfWarPowerMeterSize)
        self.powerMeter.reparentTo(aspect2d)
        self.powerMeter.setPos(0.0, 0.0, 0.6)
        self.powerMeter.hide()
        self.arrows = [None] * 2
        for x in range(len(self.arrows)):
            self.arrows[x] = loader.loadModel('phase_3/models/props/arrow')
            self.arrows[x].reparentTo(self.powerMeter)
            self.arrows[x].setScale(0.2 - 0.4 * x, 0.2, 0.2)
            self.arrows[x].setPos(0.12 - 0.24 * x, 0, -.26)

        return

    def loadSounds(self):
        self.splashSound = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_splash.ogg')
        self.whistleSound = base.loader.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg')

    def loadIntervals(self):
        self.updateIdealRateInterval = Sequence()
        self.updateIdealRateInterval.append(Wait(PartyGlobals.TugOfWarTargetRateList[0][0]))
        for i in range(1, len(PartyGlobals.TugOfWarTargetRateList)):
            duration = PartyGlobals.TugOfWarTargetRateList[i][0]
            idealRate = PartyGlobals.TugOfWarTargetRateList[i][1]
            self.updateIdealRateInterval.append(Func(self.setIdealRate, idealRate))
            if i == len(PartyGlobals.TugOfWarTargetRateList) - 1:
                self.updateIdealRateInterval.append(Func(setattr, self, 'allOutMode', True))
            else:
                self.updateIdealRateInterval.append(Wait(duration))

        self.updateKeyPressRateInterval = Sequence(Wait(PartyGlobals.TugOfWarKeyPressUpdateRate), Func(self.updateKeyPressRate))
        self.reportToServerInterval = Sequence(Wait(PartyGlobals.TugOfWarKeyPressReportRate), Func(self.reportToServer))
        self.setupInterval = Parallel()
        self.globalSetupInterval = Sequence(Wait(PartyGlobals.TugOfWarReadyDuration + PartyGlobals.TugOfWarGoDuration), Func(self.tightenRopes))
        self.localSetupInterval = Sequence(Func(self.setStatus, TTLocalizer.PartyTugOfWarReady), Func(self.showStatus), Wait(PartyGlobals.TugOfWarReadyDuration), Func(base.playSfx, self.whistleSound), Func(self.setStatus, TTLocalizer.PartyTugOfWarGo), Wait(PartyGlobals.TugOfWarGoDuration), Func(self.enableKeys), Func(self.hideStatus), Func(self.updateIdealRateInterval.start), Func(self.updateKeyPressRateInterval.loop), Func(self.reportToServerInterval.loop))
        self.splashInterval = Sequence(Func(base.playSfx, self.splashSound), Func(self.splash.play))

    def unload(self):
        DistributedPartyTeamActivity.unload(self)
        self.arrowKeys.destroy()
        self.unloadIntervals()
        self.unloadModels()
        self.unloadGuiElements()
        self.unloadSounds()
        if hasattr(self, 'toonIds'):
            del self.toonIds
        del self.buttons
        del self.arrowKeys
        del self.keyTTL
        del self.idealRate
        del self.keyRate
        del self.allOutMode
        del self.rateMatchAward
        del self.toonIdsToStartPositions
        del self.toonIdsToIsPullingFlags
        del self.toonIdsToRightHands
        del self.fallenToons
        del self.fallenPositions
        del self.unusedFallenPositionsIndices
        self.toonIdsToAnimIntervals.clear()
        del self.toonIdsToAnimIntervals

    def unloadModels(self):
        self.playArea.removeNode()
        del self.playArea
        del self.dockPositions
        del self.hopOffPositions
        self.__disableCollisions()
        while len(self.joinCollision) > 0:
            collNode = self.joinCollision.pop()
            del collNode

        while len(self.joinCollisionNodePaths) > 0:
            collNodePath = self.joinCollisionNodePaths.pop()
            collNodePath.removeNode()
            del collNodePath

        while len(self.tugRopes) > 0:
            rope = self.tugRopes.pop()
            if rope is not None:
                rope.removeNode()
            del rope

        del self.tugRopes
        self.splash.destroy()
        del self.splash
        return

    def unloadGuiElements(self):
        for arrow in self.arrows:
            if arrow is not None:
                arrow.removeNode()
                del arrow

        del self.arrows
        if self.powerMeter is not None:
            self.powerMeter.cleanup()
            del self.powerMeter
        return

    def unloadSounds(self):
        del self.splashSound
        del self.whistleSound

    def unloadIntervals(self):
        self.updateIdealRateInterval.pause()
        del self.updateIdealRateInterval
        self.updateKeyPressRateInterval.pause()
        del self.updateKeyPressRateInterval
        self.reportToServerInterval.pause()
        del self.reportToServerInterval
        self.setupInterval.pause()
        del self.setupInterval
        self.globalSetupInterval.pause()
        del self.globalSetupInterval
        self.localSetupInterval.pause()
        del self.localSetupInterval
        self.splashInterval.pause()
        del self.splashInterval

    def __enableCollisions(self):
        for i in range(len(PartyGlobals.TeamActivityTeams)):
            self.accept('enterTugOfWarJoinCollision%d' % i, getattr(self, '_join%s' % PartyGlobals.TeamActivityTeams.getString(i)))

    def __disableCollisions(self):
        for i in range(len(PartyGlobals.TeamActivityTeams)):
            self.ignore('enterTugOfWarJoinCollision%d' % i)

    def startWaitForEnough(self):
        DistributedPartyTeamActivity.startWaitForEnough(self)
        self.__enableCollisions()

    def finishWaitForEnough(self):
        DistributedPartyTeamActivity.finishWaitForEnough(self)
        self.__disableCollisions()

    def startWaitToStart(self, waitStartTimestamp):
        DistributedPartyTeamActivity.startWaitToStart(self, waitStartTimestamp)
        self.__enableCollisions()

    def finishWaitToStart(self):
        DistributedPartyTeamActivity.finishWaitToStart(self)
        self.__disableCollisions()

    def startRules(self):
        DistributedPartyTeamActivity.startRules(self)
        self.setUpRopes()
        if self.isLocalToonPlaying:
            self.showControls()

    def finishRules(self):
        DistributedPartyTeamActivity.finishRules(self)
        if self.activityFSM.getCurrentOrNextState() == 'WaitForEnough':
            self.hideRopes()
            self.hideControls()

    def finishWaitForServer(self):
        DistributedPartyTeamActivity.finishWaitForServer(self)
        if self.activityFSM.getCurrentOrNextState() == 'WaitForEnough':
            self.hideRopes()
            self.hideControls()

    def startActive(self):
        DistributedPartyTeamActivity.startActive(self)
        self.toonIdsToStartPositions.clear()
        self.toonIdsToIsPullingFlags.clear()
        for toonId in self.getToonIdsAsList():
            self.toonIdsToIsPullingFlags[toonId] = False
            toon = self.getAvatar(toonId)
            if toon:
                self.toonIdsToStartPositions[toonId] = toon.getPos(self.root)
            else:
                self.notify.warning("couldn't find toon %d assigning 0,0,0 to startPos" % toonId)
                self.toonIdsToStartPositions[toonId] = Point3(0, 0, 0)

        self.unusedFallenPositionsIndices = [0,
         1,
         2,
         3]
        self.setupInterval = Parallel(self.globalSetupInterval)
        if self.isLocalToonPlaying:
            self.keyTTL = []
            self.idealForce = 0.0
            self.keyRate = 0
            self.rateMatchAward = 0.0
            self.allOutMode = False
            self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
            self.setupInterval.append(self.localSetupInterval)
        self.setupInterval.start()

    def finishActive(self):
        DistributedPartyTeamActivity.finishActive(self)
        self.hideControls()
        self.disableKeys()
        self.setupInterval.pause()
        self.reportToServerInterval.pause()
        self.updateKeyPressRateInterval.pause()
        self.updateIdealRateInterval.pause()
        self.hideRopes()

    def startConclusion(self, losingTeam):
        DistributedPartyTeamActivity.startConclusion(self, losingTeam)
        if self.isLocalToonPlaying:
            self._rewardFinishedSV.set(False)
            if losingTeam == PartyGlobals.TeamActivityNeitherTeam:
                self.setStatus(TTLocalizer.PartyTeamActivityGameTie)
            else:
                self.setStatus(TTLocalizer.PartyTugOfWarGameEnd)
            self.showStatus()
        if losingTeam == PartyGlobals.TeamActivityNeitherTeam:
            for toonId in self.getToonIdsAsList():
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop('neutral')

        else:
            for toonId in self.toonIds[losingTeam]:
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop('neutral')

            for toonId in self.toonIds[1 - losingTeam]:
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop('victory')

        for ival in list(self.toonIdsToAnimIntervals.values()):
            if ival is not None:
                ival.finish()

        return

    def finishConclusion(self):
        DistributedPartyTeamActivity.finishConclusion(self)
        self.fallenToons = []

    def getTitle(self):
        return TTLocalizer.PartyTugOfWarTitle

    def getInstructions(self):
        return TTLocalizer.TugOfWarInstructions

    def showControls(self):
        for arrow in self.arrows:
            arrow.setColor(PartyGlobals.TugOfWarDisabledArrowColor)

        self.powerMeter.setTarget(PartyGlobals.TugOfWarTargetRateList[0][1])
        self.powerMeter.setPower(PartyGlobals.TugOfWarTargetRateList[0][1])
        self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5))
        self.powerMeter.clearTooSlowTooFast()
        self.powerMeter.show()

    def hideControls(self):
        self.powerMeter.hide()

    def setUpRopes(self):
        self.notify.debug('setUpRopes')
        ropeIndex = 0
        leftToonId = -1
        if self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]:
            leftToonId = self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]
        rightToonId = -1
        if self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]:
            rightToonId = self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam][0]
        if leftToonId in self.toonIdsToRightHands and rightToonId in self.toonIdsToRightHands:
            self.tugRopes[ropeIndex].setup(3, ((self.toonIdsToRightHands[leftToonId], (0, 0, 0)), (self.root, (0.0, 0.0, 2.5)), (self.toonIdsToRightHands[rightToonId], (0, 0, 0))), [0,
             0,
             0,
             1,
             1,
             1])
            self.tugRopes[ropeIndex].unstash()
            ropeIndex += 1
        teams = [PartyGlobals.TeamActivityTeams.LeftTeam, PartyGlobals.TeamActivityTeams.RightTeam]
        for currTeam in teams:
            numToons = len(self.toonIds[currTeam])
            if numToons > 1:
                for i in range(numToons - 1, 0, -1):
                    toon1 = self.toonIds[currTeam][i]
                    toon2 = self.toonIds[currTeam][i - 1]
                    if toon1 not in self.toonIdsToRightHands:
                        self.notify.warning('Toon in tug of war activity but not properly setup:  %s' % toon1)
                    elif toon2 not in self.toonIdsToRightHands:
                        self.notify.warning('Toon in tug of war activity but not properly setup:  %s' % toon2)
                    else:
                        self.notify.debug('Connecting rope between toon %d and toon %d of team %d.' % (i, i - 1, currTeam))
                        self.tugRopes[ropeIndex].setup(3, ((self.toonIdsToRightHands[toon1], (0, 0, 0)), (self.toonIdsToRightHands[toon1], (0, 0, 0)), (self.toonIdsToRightHands[toon2], (0, 0, 0))), [0,
                         0,
                         0,
                         1,
                         1,
                         1])
                        self.tugRopes[ropeIndex].unstash()
                        ropeIndex += 1

    def tightenRopes(self):
        self.notify.debug('tightenRopes')
        self.tugRopes[0].setup(3, ((self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam][0]], (0, 0, 0))), [0,
         0,
         0,
         1,
         1,
         1])

    def hideRopes(self):
        self.notify.debug('hideRopes')
        for rope in self.tugRopes:
            rope.stash()

    def handleGameTimerExpired(self):
        self.disableKeys()

    def setIdealRate(self, idealRate):
        self.notify.debug('setIdealRate( %d )' % idealRate)
        self.idealRate = idealRate
        self.idealForce = self.advantage * (4 + 0.4 * self.idealRate)

    def updateKeyPressRate(self):
        for i in range(len(self.keyTTL)):
            self.keyTTL[i] -= PartyGlobals.TugOfWarKeyPressUpdateRate

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

        self.keyRate = len(self.keyTTL)
        if self.keyRate == self.idealRate or self.keyRate == self.idealRate + 1:
            self.rateMatchAward += 0.3
        else:
            self.rateMatchAward = 0.0

    def reportToServer(self):
        self.currentForce = self.computeForce(self.keyRate)
        self.sendUpdate('reportKeyRateForce', [self.keyRate, self.currentForce])
        self.setSpeedGauge()
        self.setAnimState(base.localAvatar.doId, self.keyRate)

    def computeForce(self, keyRate):
        F = 0
        if self.allOutMode:
            F = 0.75 * keyRate
        else:
            stdDev = 0.25 * self.idealRate
            F = self.advantage * (self.rateMatchAward + 4 + 0.4 * self.idealRate) * math.pow(math.e, -math.pow(keyRate - self.idealRate, 2) / (2.0 * math.pow(stdDev, 2)))
        return F

    def setSpeedGauge(self):
        self.powerMeter.setPower(self.keyRate)
        self.powerMeter.setTarget(self.idealRate)
        if not self.allOutMode:
            self.powerMeter.updateTooSlowTooFast()
            index = float(self.currentForce) / self.idealForce
            bonus = 0.0
            if index > 1.0:
                bonus = max(1.0, index - 1.0)
                index = 1.0
            color = (0,
             0.75 * index + 0.25 * bonus,
             0.75 * (1 - index),
             0.5)
            self.powerMeter.setBarColor(color)
        else:
            self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5))

    def updateToonKeyRate(self, toonId, keyRate):
        if toonId != base.localAvatar.doId:
            self.setAnimState(toonId, keyRate)

    def setAnimState(self, toonId, keyRate):
        if self.activityFSM.state != 'Active':
            return
        toon = self.getAvatar(toonId)
        if toonId not in self.toonIdsToIsPullingFlags:
            if self.getTeam(toonId) == None:
                self.notify.warning("setAnimState called with toonId (%d) that wasn't in self.toonIds" % toonId)
                return
            else:
                self.notify.warning('setAnimState called with toonId (%d) that was in self.toonIds but not in self.toonIdsToIsPullingFlags. Adding it.' % toonId)
                self.toonIdsToIsPullingFlags[toonId] = False
        if keyRate > 0 and not self.toonIdsToIsPullingFlags[toonId]:
            if toon:
                toon.loop('tug-o-war')
            else:
                self.notify.warning('toon %d is None, skipping toon.loop(tugowar)' % toonId)
            self.toonIdsToIsPullingFlags[toonId] = True
        if keyRate <= 0 and self.toonIdsToIsPullingFlags[toonId]:
            if toon:
                toon.pose('tug-o-war', 3)
                toon.startLookAround()
            else:
                self.notify.warning('toon %d is None, skipping toon.startLookAround' % toonId)
            self.toonIdsToIsPullingFlags[toonId] = False
        return

    def enableKeys(self):
        self.notify.debug('enableKeys')
        self.arrowKeys.setPressHandlers([lambda : self.__pressHandler(2),
         lambda : self.__pressHandler(3),
         lambda : self.__pressHandler(1),
         lambda : self.__pressHandler(0)])
        self.arrowKeys.setReleaseHandlers([lambda : self.__releaseHandler(2),
         lambda : self.__releaseHandler(3),
         lambda : self.__releaseHandler(1),
         lambda : self.__releaseHandler(0)])
        for arrow in self.arrows:
            arrow.setColor(PartyGlobals.TugOfWarEnabledArrowColor)

    def disableKeys(self):
        self.arrowKeys.setPressHandlers(self.arrowKeys.NULL_HANDLERS)
        self.arrowKeys.setReleaseHandlers(self.arrowKeys.NULL_HANDLERS)

    def __pressHandler(self, index):
        if index == self.buttons[0]:
            self.arrows[index].setColor(PartyGlobals.TugOfWarHilightedArrowColor)
            self.keyTTL.insert(0, PartyGlobals.TugOfWarKeyPressTimeToLive)
            self.buttons.reverse()

    def __releaseHandler(self, index):
        if index in self.buttons:
            self.arrows[index].setColor(PartyGlobals.TugOfWarEnabledArrowColor)

    def updateToonPositions(self, offset):
        if self.activityFSM.state != 'Active':
            return
        if self.isLocalToonPlaying:
            camera.lookAt(self.root, offset, 0.0, PartyGlobals.TugOfWarCameraLookAtHeightOffset)
        for toonId in self.getToonIdsAsList():
            if hasattr(self, 'fallenToons') and toonId not in self.fallenToons:
                toon = self.getAvatar(toonId)
                if toon is not None:
                    origPos = self.toonIdsToStartPositions[toonId]
                    curPos = toon.getPos(self.root)
                    newPos = Point3(origPos[0] + offset, curPos[1], curPos[2])
                    if self.toonIdsToAnimIntervals[toonId] != None:
                        if self.toonIdsToAnimIntervals[toonId].isPlaying():
                            self.toonIdsToAnimIntervals[toonId].finish()
                            self.checkIfFallen(toonId)
                    if toonId not in self.fallenToons:
                        self.toonIdsToAnimIntervals[toonId] = Sequence(LerpPosInterval(toon, duration=PartyGlobals.TugOfWarKeyPressReportRate, pos=newPos, other=self.root), Func(self.checkIfFallen, toonId))
                        self.toonIdsToAnimIntervals[toonId].start()

        return

    def checkIfFallen(self, toonId):
        if hasattr(self, 'fallenToons') and toonId not in self.fallenToons:
            toon = self.getAvatar(toonId)
            if toon:
                curPos = toon.getPos(self.root)
                team = self.getTeam(toonId)
                if team == PartyGlobals.TeamActivityTeams.LeftTeam and curPos[0] > -2.0 or team == PartyGlobals.TeamActivityTeams.RightTeam and curPos[0] < 2.0:
                    losingTeam = self.getTeam(toonId)
                    self.throwTeamInWater(losingTeam)
                    self.sendUpdate('reportFallIn', [losingTeam])

    def throwTeamInWater(self, losingTeam):
        self.notify.debug('throwTeamInWater( %s )' % PartyGlobals.TeamActivityTeams.getString(losingTeam))
        splashSet = False
        for toonId in self.toonIds[losingTeam]:
            self.fallenToons.append(toonId)
            toon = self.getAvatar(toonId)
            fallenPosIndex = self.toonIds[losingTeam].index(toonId)
            if fallenPosIndex < 0 or fallenPosIndex >= 4:
                fallenPosIndex = 0
            newPos = self.fallenPositions[fallenPosIndex]
            if toonId in self.toonIdsToAnimIntervals and self.toonIdsToAnimIntervals[toonId] is not None:
                if self.toonIdsToAnimIntervals[toonId].isPlaying():
                    self.toonIdsToAnimIntervals[toonId].finish()
            if toon:
                parallel = Parallel(ActorInterval(actor=toon, animName='slip-forward', duration=2.0), LerpPosInterval(toon, duration=2.0, pos=newPos, other=self.root))
            else:
                self.notify.warning('toon %d is none, skipping slip-forward' % toonId)
                parallel = Parallel()
            if not splashSet:
                splashSet = True
                parallel.append(self.splashInterval)
            if toon:
                self.toonIdsToAnimIntervals[toonId] = Sequence(parallel, Func(toon.loop, 'neutral'))
            else:
                self.notify.warning('toon %d is none, skipping toon.loop(neutral)' % toonId)
                self.toonIdsToAnimIntervals[toonId] = parallel
            self.toonIdsToAnimIntervals[toonId].start()

        return

    def setAdvantage(self, advantage):
        DistributedPartyTeamActivity.setAdvantage(self, advantage)
        if self.isLocalToonPlaying:
            self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
コード例 #2
0
class SiegeManager(DistributedObject, SiegeManagerBase):
    TeamJoinableChangedEvent = 'PVPTeamJoinableChanged'

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        SiegeManagerBase.__init__(self)

    def generate(self):
        self._announcerInterest = None
        self._siegeTeam = 0
        self._siegeTeamUpdater = FunctionCall(self._setSiegeTeam,
                                              localAvatar._siegeTeamSV)
        self._siegeTeamUpdater.pushCurrentState()
        DistributedObject.generate(self)
        self._pvpTeamJoinable = {}
        base.cr.distributedDistrict.siegeManager = self

    def delete(self):
        self._siegeTeamUpdater.destroy()
        del self._siegeTeamUpdater
        self._removeAnnouncerInterest()
        del self._pvpTeamJoinable
        del base.cr.distributedDistrict.siegeManager
        DistributedObject.delete(self)

    def setPvpEnabled(self, enabled):
        self._pvpEnabled = enabled

    def getPvpEnabled(self):
        return self._pvpEnabled

    def setTeamsJoinable(self, teamJoinableItems):
        for (teamId, joinable) in teamJoinableItems:
            self._pvpTeamJoinable[teamId] = joinable

        messenger.send(SiegeManager.TeamJoinableChangedEvent)

    def teamIsJoinable(self, teamId):
        if not config.GetBool('want-pvp-team-balance', 1):
            return True

        return self._pvpTeamJoinable.get(teamId, True)

    def sendTalk(self, message):
        print 'Seige Manager Sending Message %s' % message
        self.sendUpdate('setTalkGroup', [0, 0, '', message, [], 0])

    def sendWLChat(self, message):
        self.sendUpdate('sendWLChat', [message, 0, 0])

    def sendSC(self, msgIndex):
        self.sendUpdate('sendSC', [msgIndex])

    def setTalkGroup(self, fromAv, fromAC, avatarName, chat, mods, flags):
        print 'Seige Manager- SetTalkGroup %s' % chat
        teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
        (message, scrubbed) = localAvatar.scrubTalk(chat, mods)
        base.talkAssistant.receiveShipPVPMessage(fromAv, fromAC, avatarName,
                                                 teamName, message, scrubbed)

    def recvChat(self, avatarId, message, chatFlags, DISLid, name):
        teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
        if not self.cr.avatarFriendsManager.checkIgnored(avatarId):
            displayMess = '%s %s %s' % (
                name, self.getPVPChatTeamName(
                    localAvatar.getSiegeTeam()), message)
            base.talkAssistant.receiveShipPVPMessage(avatarId, DISLid, name,
                                                     teamName, message)

    def recvWLChat(self, avatarId, message, chatFlags, DISLid, name):
        teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
        if not self.cr.avatarFriendsManager.checkIgnored(avatarId):
            displayMess = '%s %s %s' % (
                name, self.getPVPChatTeamName(
                    localAvatar.getSiegeTeam()), message)
            base.talkAssistant.receiveShipPVPMessage(avatarId, DISLid, name,
                                                     teamName, message)

    def recvSpeedChat(self, avatarId, msgIndex, name):
        print 'siege manager recvSpeedChat'
        if not self.cr.avatarFriendsManager.checkIgnored(avatarId):
            displayMess = '%s %s %s' % (
                name, self.getPVPChatTeamName(localAvatar.getSiegeTeam()),
                SCDecoders.decodeSCStaticTextMsg(msgIndex))
            message = SCDecoders.decodeSCStaticTextMsg(msgIndex)
            teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
            base.talkAssistant.receiveShipPVPMessage(avatarId, 0, name,
                                                     teamName, message)

    def sendSCQuest(self, questInt, msgType, taskNum):
        self.sendUpdate('sendSCQuest', [questInt, msgType, taskNum])

    def recvSCQuest(self, avName, senderId, questInt, msgType, taskNum):
        senderName = avName
        message = base.talkAssistant.SCDecoder.decodeSCQuestMsgInt(
            questInt, msgType, taskNum)
        if not self.cr.avatarFriendsManager.checkIgnored(senderId):
            teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
            displayMess = '%s %s %s' % (avName, teamName, message)
            base.talkAssistant.receiveShipPVPMessage(senderId, 0, avName,
                                                     teamName, message)

    def getPVPChatTeamName(self, teamId):
        if teamId == 2:
            return PLocalizer.PVPSpanish
        elif teamId == 1:
            return PLocalizer.PVPFrench
        else:
            return PLocalizer.PVPPrefix

    def _addAnnouncerInterest(self):
        if not self._announcerInterest:
            self._announcerInterest = self.cr.addTaggedInterest(
                self.doId, self.ANNOUNCER_ZONE, self.cr.ITAG_GAME,
                'siegeAnnouncer')

    def _removeAnnouncerInterest(self):
        if self._announcerInterest:
            self.cr.removeTaggedInterest(self._announcerInterest)
            self._announcerInterest = None

    def _setSiegeTeam(self, siegeTeam):
        if siegeTeam and not (self._siegeTeam):
            self._addAnnouncerInterest()
        elif not siegeTeam and self._siegeTeam:
            self._removeAnnouncerInterest()

        self._siegeTeam = siegeTeam
コード例 #3
0
class FrameProfiler:
    notify = directNotify.newCategory('FrameProfiler')

    # because of precision requirements, all times related to the profile/log
    # schedule are stored as integers
    Minute = 60
    Hour = 60 * Minute
    Day = 24 * Hour

    def __init__(self):
        Hour = FrameProfiler.Hour
        # how long to wait between frame profiles
        frequent_profiles = ConfigVariableBool('frequent-frame-profiles',
                                               False)
        self._period = 2 * FrameProfiler.Minute
        if frequent_profiles:
            self._period = 1 * FrameProfiler.Minute
        # used to prevent profile from being taken exactly every 'period' seconds
        self._jitterMagnitude = self._period * .75
        # when to log output
        # each entry must be an integer multiple of all previous entries
        # as well as an integer multiple of the period
        self._logSchedule = [
            1 * FrameProfiler.Hour,
            4 * FrameProfiler.Hour,
            12 * FrameProfiler.Hour,
            1 * FrameProfiler.Day,
        ]  # day schedule proceeds as 1, 2, 4, 8 days, etc.
        if frequent_profiles:
            self._logSchedule = [
                1 * FrameProfiler.Minute,
                4 * FrameProfiler.Minute,
                12 * FrameProfiler.Minute,
                24 * FrameProfiler.Minute,
            ]
        for t in self._logSchedule:
            #assert isInteger(t)
            # make sure the period is evenly divisible into each element of the log schedule
            assert (t % self._period) == 0
        # make sure each element of the schedule is evenly divisible into each subsequent element
        for i in range(len(self._logSchedule)):
            e = self._logSchedule[i]
            for j in range(i, len(self._logSchedule)):
                assert (self._logSchedule[j] % e) == 0
        #assert isInteger(self._period)
        self._enableFC = FunctionCall(self._setEnabled,
                                      taskMgr.getProfileFramesSV())
        self._enableFC.pushCurrentState()

    def destroy(self):
        self._enableFC.set(False)
        self._enableFC.destroy()

    def _setEnabled(self, enabled):
        if enabled:
            self.notify.info('frame profiler started')
            self._startTime = globalClock.getFrameTime()
            self._profileCounter = 0
            self._jitter = None
            self._period2aggregateProfile = {}
            self._id2session = {}
            self._id2task = {}
            # don't profile process startup
            self._task = taskMgr.doMethodLater(
                self._period, self._scheduleNextProfileDoLater,
                'FrameProfilerStart-%s' % serialNum())
        else:
            self._task.remove()
            del self._task
            for session in self._period2aggregateProfile.values():
                session.release()
            del self._period2aggregateProfile
            for task in self._id2task.values():
                task.remove()
            del self._id2task
            for session in self._id2session.values():
                session.release()
            del self._id2session
            self.notify.info('frame profiler stopped')

    def _scheduleNextProfileDoLater(self, task):
        self._scheduleNextProfile()
        return Task.done

    def _scheduleNextProfile(self):
        self._profileCounter += 1
        self._timeElapsed = self._profileCounter * self._period
        #assert isInteger(self._timeElapsed)
        time = self._startTime + self._timeElapsed

        # vary the actual delay between profiles by a random amount to prevent interaction
        # with periodic events
        jitter = self._jitter
        if jitter is None:
            jitter = normalDistrib(-self._jitterMagnitude,
                                   self._jitterMagnitude)
            time += jitter
        else:
            time -= jitter
            jitter = None
        self._jitter = jitter

        sessionId = serialNum()
        session = taskMgr.getProfileSession('FrameProfile-%s' % sessionId)
        self._id2session[sessionId] = session
        taskMgr.profileFrames(num=1,
                              session=session,
                              callback=Functor(self._analyzeResults,
                                               sessionId))

        # schedule the next profile
        delay = max(time - globalClock.getFrameTime(), 0.)
        self._task = taskMgr.doMethodLater(delay,
                                           self._scheduleNextProfileDoLater,
                                           'FrameProfiler-%s' % serialNum())

    def _analyzeResults(self, sessionId):
        # do the analysis in a task 1) to separate the processing from the profiled frame,
        # and 2) to get the processing to show up in a named task instead of in the taskMgr
        self._id2task[sessionId] = taskMgr.add(
            Functor(self._doAnalysis, sessionId),
            'FrameProfilerAnalysis-%s' % sessionId)

    def _doAnalysis(self, sessionId, task):
        if hasattr(task, '_generator'):
            gen = task._generator
        else:
            gen = self._doAnalysisGen(sessionId)
            task._generator = gen
        result = next(gen)
        if result == Task.done:
            del task._generator
        return result

    def _doAnalysisGen(self, sessionId):
        # generator to limit max number of profile loggings per frame
        p2ap = self._period2aggregateProfile

        self._id2task.pop(sessionId)
        session = self._id2session.pop(sessionId)

        if session.profileSucceeded():
            # always add this profile to the first aggregated profile
            period = self._logSchedule[0]
            if period not in self._period2aggregateProfile:
                p2ap[period] = session.getReference()
            else:
                p2ap[period].aggregate(session)
        else:
            self.notify.warning('frame profile did not succeed')

        session.release()
        session = None

        counter = 0

        # log profiles when it's time, and aggregate them upwards into the
        # next-longer profile
        for pi in range(len(self._logSchedule)):
            period = self._logSchedule[pi]
            if (self._timeElapsed % period) == 0:
                if period in p2ap:
                    # delay until the next frame if we've already processed N profiles this frame
                    if counter >= 3:
                        counter = 0
                        yield Task.cont
                    self.notify.info(
                        'aggregate profile of sampled frames over last %s\n%s'
                        % (formatTimeExact(period), p2ap[period].getResults()))
                    counter += 1
                    # aggregate this profile into the next larger profile
                    nextIndex = pi + 1
                    if nextIndex >= len(self._logSchedule):
                        # if we're adding a new period to the end of the log period table,
                        # set it to double the duration of the current longest period
                        nextPeriod = period * 2
                        self._logSchedule.append(nextPeriod)
                    else:
                        nextPeriod = self._logSchedule[nextIndex]
                    if nextPeriod not in p2ap:
                        p2ap[nextPeriod] = p2ap[period].getReference()
                    else:
                        p2ap[nextPeriod].aggregate(p2ap[period])
                    # this profile is now represented in the next larger profile
                    # throw it out
                    p2ap[period].release()
                    del p2ap[period]
            else:
                # current time is not divisible evenly into selected period, and all higher
                # periods are multiples of this one
                break

        yield Task.done
class DistCogdoGame(DistCogdoGameBase, DistributedObject):
    notify = directNotify.newCategory('DistCogdoGame')

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        base.cogdoGame = self
        cr.cogdoGame = self
        self._waitingStartLabel = DirectLabel(
            text=TTL.MinigameWaitingForOtherPlayers,
            text_fg=VBase4(1, 1, 1, 1),
            relief=None,
            pos=(-0.6, 0, -0.75),
            scale=0.075)
        self._waitingStartLabel.hide()
        self.loadFSM = ClassicFSM.ClassicFSM('DistCogdoGame.loaded', [
            State.State('NotLoaded', self.enterNotLoaded, self.exitNotLoaded,
                        ['Loaded']),
            State.State('Loaded', self.enterLoaded, self.exitLoaded,
                        ['NotLoaded'])
        ], 'NotLoaded', 'NotLoaded')
        self.loadFSM.enterInitialState()
        self.fsm = ClassicFSM.ClassicFSM('DistCogdoGame', [
            State.State('Visible', self.enterVisible, self.exitVisible,
                        ['Intro']),
            State.State('Intro', self.enterIntro, self.exitIntro,
                        ['WaitServerStart']),
            State.State('WaitServerStart', self.enterWaitServerStart,
                        self.exitWaitServerStart, ['Game']),
            State.State('Game', self.enterGame, self.exitGame, ['Finish']),
            State.State('Finish', self.enterFinish, self.exitFinish, ['Off']),
            State.State('Off', self.enterOff, self.exitOff, ['Visible'])
        ], 'Off', 'Off')
        self.fsm.enterInitialState()
        self.difficultyOverride = None
        self.exteriorZoneOverride = None
        self._gotInterior = StateVar(False)
        self._toonsInEntranceElev = StateVar(False)
        self._wantStashElevator = StateVar(False)
        self._stashElevatorFC = FunctionCall(self._doStashElevator,
                                             self._toonsInEntranceElev,
                                             self._gotInterior,
                                             self._wantStashElevator)
        return

    def getTitle(self):
        pass

    def getInstructions(self):
        pass

    def setInteriorId(self, interiorId):
        self._interiorId = interiorId

    def setExteriorZone(self, exteriorZone):
        self.exteriorZone = exteriorZone

    def setDifficultyOverrides(self, difficultyOverride, exteriorZoneOverride):
        if difficultyOverride != CogdoGameConsts.NoDifficultyOverride:
            self.difficultyOverride = difficultyOverride / float(
                CogdoGameConsts.DifficultyOverrideMult)
        if exteriorZoneOverride != CogdoGameConsts.NoExteriorZoneOverride:
            self.exteriorZoneOverride = exteriorZoneOverride

    def getInterior(self):
        return self.cr.getDo(self._interiorId)

    def getEntranceElevator(self, callback):
        return self.getInterior().getEntranceElevator(callback)

    def getToonIds(self):
        interior = self.getInterior()
        if interior is not None:
            return interior.getToonIds()
        else:
            return []
        return

    def getToon(self, toonId):
        if self.cr.doId2do.has_key(toonId):
            return self.cr.doId2do[toonId]
        else:
            return None
        return None

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

    def isSinglePlayer(self):
        if self.getNumPlayers() == 1:
            return 1
        else:
            return 0

    def announceGenerate(self):
        DistributedObject.announceGenerate(self)
        self.loadFSM.request('Loaded')
        self._requestInterior()
        self.notify.info('difficulty: %s, safezoneId: %s' %
                         (self.getDifficulty(), self.getSafezoneId()))

    def _requestInterior(self):
        self.cr.relatedObjectMgr.requestObjects(
            [self._interiorId], allCallback=self._handleGotInterior)

    def _handleGotInterior(self, objs):
        self._gotInterior.set(True)
        self.getEntranceElevator(self.placeEntranceElev)

    def stashEntranceElevator(self):
        self._wantStashElevator.set(True)

    def placeEntranceElev(self, elev):
        pass

    def _doStashElevator(self, toonsInEntranceElev, gotInterior,
                         wantStashElevator):
        if gotInterior:
            interior = self.getInterior()
            if interior:
                if not toonsInEntranceElev and wantStashElevator:
                    interior.stashElevatorIn()
                else:
                    interior.stashElevatorIn(False)

    def disable(self):
        base.cogdoGame = None
        self.cr.cogdoGame = None
        self.fsm.requestFinalState()
        self.loadFSM.requestFinalState()
        self.fsm = None
        self.loadFSM = None
        DistributedObject.disable(self)
        return

    def delete(self):
        self._stashElevatorFC.destroy()
        self._wantStashElevator.destroy()
        self._toonsInEntranceElev.destroy()
        self._gotInterior.destroy()
        self._waitingStartLabel.destroy()
        self._waitingStartLabel = None
        DistributedObject.delete(self)
        return

    def getDifficulty(self):
        if self.difficultyOverride is not None:
            return self.difficultyOverride
        if hasattr(base, 'cogdoGameDifficulty'):
            return float(base.cogdoGameDifficulty)
        return CogdoGameConsts.getDifficulty(self.getSafezoneId())

    def getSafezoneId(self):
        if self.exteriorZoneOverride is not None:
            return self.exteriorZoneOverride
        if hasattr(base, 'cogdoGameSafezoneId'):
            return CogdoGameConsts.getSafezoneId(base.cogdoGameSafezoneId)
        return CogdoGameConsts.getSafezoneId(self.exteriorZone)

    def enterNotLoaded(self):
        pass

    def exitNotLoaded(self):
        pass

    def enterLoaded(self):
        pass

    def exitLoaded(self):
        pass

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def setVisible(self):
        self.fsm.request('Visible')

    def setIntroStart(self):
        self.fsm.request('Intro')

    def enterVisible(self):
        self._toonsInEntranceElev.set(True)

    def exitVisible(self):
        pass

    def enterIntro(self, duration=MinigameGlobals.rulesDuration):
        base.cr.playGame.getPlace().fsm.request('Game')
        self._rulesDoneEvent = self.uniqueName('cogdoGameRulesDone')
        self.accept(self._rulesDoneEvent, self._handleRulesDone)
        self._rulesPanel = CogdoGameRulesPanel('CogdoGameRulesPanel',
                                               self.getTitle(),
                                               '',
                                               self._rulesDoneEvent,
                                               timeout=duration)
        self._rulesPanel.load()
        self._rulesPanel.enter()

    def exitIntro(self):
        self._toonsInEntranceElev.set(False)
        self.ignore(self._rulesDoneEvent)
        if self._rulesPanel:
            self._rulesPanel.exit()
            self._rulesPanel.unload()
            self._rulesPanel = None
        return

    def _handleRulesDone(self):
        self.ignore(self._rulesDoneEvent)
        self._rulesPanel.exit()
        self._rulesPanel.unload()
        self._rulesPanel = None
        self.fsm.request('WaitServerStart')
        self.d_setAvatarReady()
        return

    def d_setAvatarReady(self):
        self.sendUpdate('setAvatarReady', [])

    def enterWaitServerStart(self):
        numToons = 1
        interior = self.getInterior()
        if interior:
            numToons = len(interior.getToonIds())
        if numToons > 1:
            msg = TTL.MinigameWaitingForOtherPlayers
        else:
            msg = TTL.MinigamePleaseWait
        self._waitingStartLabel['text'] = msg
        self._waitingStartLabel.show()

    def exitWaitServerStart(self):
        self._waitingStartLabel.hide()

    def setGameStart(self, timestamp):
        self._startTime = globalClockDelta.networkToLocalTime(timestamp)
        self.fsm.request('Game')

    def getStartTime(self):
        return self._startTime

    #def enterGame(self):
    #if SCHELLGAMES_DEV:
    #self.acceptOnce('escape', messenger.send, ['magicWord', ['~endMaze']])

    def exitGame(self):
        if SCHELLGAMES_DEV:
            self.ignore('escape')

    def setGameFinish(self, timestamp):
        self._finishTime = globalClockDelta.networkToLocalTime(timestamp)
        self.fsm.request('Finish')

    def getFinishTime(self):
        return self._finishTime

    def enterFinish(self):
        pass

    def exitFinish(self):
        pass

    def setToonSad(self, toonId):
        pass

    def setToonDisconnect(self, toonId):
        pass
コード例 #5
0
class DistributedPartyTugOfWarActivity(DistributedPartyTeamActivity):
    notify = directNotify.newCategory('DistributedPartyTugOfWarActivity')

    def __init__(self, cr):
        DistributedPartyTeamActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTugOfWar, startDelay=PartyGlobals.TugOfWarStartDelay)
        self.buttons = [0, 1]
        self.arrowKeys = None
        self.keyTTL = []
        self.idealRate = 0.0
        self.keyRate = 0
        self.allOutMode = False
        self.rateMatchAward = 0.0
        self.toonIdsToStartPositions = {}
        self.toonIdsToIsPullingFlags = {}
        self.toonIdsToRightHands = {}
        self.fallenToons = []
        self.fallenPositions = []
        self.unusedFallenPositionsIndices = [0,
         1,
         2,
         3]
        self.toonIdsToAnimIntervals = {}
        self.tugRopes = []
        return

    def generate(self):
        DistributedPartyTeamActivity.generate(self)
        self._hopOffFinishedSV = StateVar(True)
        self._rewardFinishedSV = StateVar(True)
        self._isWalkStateReadyFC = FunctionCall(self._testWalkStateReady, self._hopOffFinishedSV, self._rewardFinishedSV)

    def delete(self):
        self._isWalkStateReadyFC.destroy()
        self._hopOffFinishedSV.destroy()
        self._rewardFinishedSV.destroy()
        DistributedPartyTeamActivity.delete(self)

    def handleToonJoined(self, toonId):
        DistributedPartyTeamActivity.handleToonJoined(self, toonId)
        self.toonIdsToAnimIntervals[toonId] = None
        if toonId == base.localAvatar.doId:
            base.cr.playGame.getPlace().fsm.request('activity')
            camera.wrtReparentTo(self.root)
            self.cameraMoveIval = LerpPosHprInterval(camera, 1.5, PartyGlobals.TugOfWarCameraPos, PartyGlobals.TugOfWarCameraInitialHpr, other=self.root)
            self.cameraMoveIval.start()
            self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam)
            self.notify.debug('posIndex: %d' % self.localToonPosIndex)
            toon = self.getAvatar(toonId)
            targetPos = self.dockPositions[self.localToonTeam][self.localToonPosIndex]
            if toon.getZ(self.root) < PartyGlobals.TugOfWarToonPositionZ:
                toon.setZ(self.root, PartyGlobals.TugOfWarToonPositionZ)
            targetH = fitDestAngle2Src(toon.getH(self.root), PartyGlobals.TugOfWarHeadings[self.localToonTeam])
            travelVector = targetPos - toon.getPos(self.root)
            duration = travelVector.length() / 5.0
            if self.toonIdsToAnimIntervals[toonId] is not None:
                self.toonIdsToAnimIntervals[toonId].finish()
            self.toonIdsToAnimIntervals[toonId] = Sequence(Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, 'run'), LerpPosHprInterval(toon, duration, targetPos, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, 'neutral'))
            self.toonIdsToAnimIntervals[toonId].start()
        return

    def handleToonExited(self, toonId):
        DistributedPartyTeamActivity.handleToonExited(self, toonId)
        if toonId == base.localAvatar.doId:
            self.cameraMoveIval.pause()
            if toonId not in self.fallenToons:
                if toonId in self.toonIdsToAnimIntervals and self.toonIdsToAnimIntervals[toonId] is not None:
                    self.toonIdsToAnimIntervals[toonId].finish()
                toon = self.getAvatar(toonId)
                targetH = fitDestAngle2Src(toon.getH(self.root), 180.0)
                targetPos = self.hopOffPositions[self.getTeam(toonId)][self.getIndex(toonId, self.getTeam(toonId))]
                hopOffAnim = Sequence(Func(toon.startPosHprBroadcast, 0.1), toon.hprInterval(0.2, VBase3(targetH, 0.0, 0.0), other=self.root), Func(toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, toon, targetPos, 5.0, self.root), Func(toon.stopPosHprBroadcast), Func(toon.sendCurrentPosition), Func(self.hopOffFinished, toonId))
                self.toonIdsToAnimIntervals[toonId] = hopOffAnim
                self._hopOffFinishedSV.set(False)
                self.toonIdsToAnimIntervals[toonId].start()
            else:
                self._hopOffFinishedSV.set(True)
                del self.toonIdsToAnimIntervals[toonId]
        return

    def handleRewardDone(self):
        self._rewardFinishedSV.set(True)

    def _testWalkStateReady(self, hoppedOff, rewardFinished):
        if hoppedOff and rewardFinished:
            DistributedPartyTeamActivity.handleRewardDone(self)

    def hopOffFinished(self, toonId):
        if hasattr(self, 'toonIdsToAnimIntervals') and toonId in self.toonIdsToAnimIntervals:
            del self.toonIdsToAnimIntervals[toonId]
        if toonId == base.localAvatar.doId:
            if hasattr(self._hopOffFinishedSV, '_value'):
                self._hopOffFinishedSV.set(True)

    def handleToonShifted(self, toonId):
        if toonId == base.localAvatar.doId:
            self.localToonPosIndex = self.getIndex(base.localAvatar.doId, self.localToonTeam)
            if self.toonIdsToAnimIntervals[toonId] is not None:
                self.toonIdsToAnimIntervals[toonId].finish()
            toon = self.getAvatar(toonId)
            targetPos = self.dockPositions[self.localToonTeam][self.localToonPosIndex]
            self.toonIdsToAnimIntervals[toonId] = Sequence(Wait(0.6), Func(toon.startPosHprBroadcast, 0.1), Func(toon.b_setAnimState, 'run'), toon.posInterval(0.5, targetPos, other=self.root), Func(toon.stopPosHprBroadcast), Func(toon.b_setAnimState, 'neutral'))
            self.toonIdsToAnimIntervals[toonId].start()
        return

    def handleToonDisabled(self, toonId):
        if self.toonIdsToAnimIntervals.has_key(toonId):
            if self.toonIdsToAnimIntervals[toonId]:
                if self.toonIdsToAnimIntervals[toonId].isPlaying():
                    self.toonIdsToAnimIntervals[toonId].finish()
            else:
                self.notify.debug('self.toonIdsToAnimIntervals[%d] is none' % toonId)

    def setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds):
        DistributedPartyTeamActivity.setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds)
        self.toonIdsToRightHands.clear()
        for toonId in self.getToonIdsAsList():
            toon = self.getAvatar(toonId)
            if toon:
                self.toonIdsToRightHands[toonId] = toon.getRightHands()[0]

    def load(self):
        DistributedPartyTeamActivity.load(self)
        self.loadModels()
        self.loadGuiElements()
        self.loadSounds()
        self.loadIntervals()
        self.arrowKeys = ArrowKeys()

    def loadModels(self):
        self.playArea = loader.loadModel('phase_13/models/parties/partyTugOfWar')
        self.playArea.reparentTo(self.root)
        self.sign.reparentTo(self.playArea.find('**/TugOfWar_sign_locator'))
        self.dockPositions = [[], []]
        for i in xrange(4):
            self.dockPositions[0].append(Point3(-PartyGlobals.TugOfWarInitialToonPositionsXOffset - PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ))

        for i in xrange(4):
            self.dockPositions[1].append(Point3(PartyGlobals.TugOfWarInitialToonPositionsXOffset + PartyGlobals.TugOfWarToonPositionXSeparation * i, 0.0, PartyGlobals.TugOfWarToonPositionZ))

        self.hopOffPositions = [[], []]
        for i in xrange(1, 5):
            self.hopOffPositions[PartyGlobals.TeamActivityTeams.LeftTeam].append(self.playArea.find('**/leftTeamHopOff%d_locator' % i).getPos())
            self.hopOffPositions[PartyGlobals.TeamActivityTeams.RightTeam].append(self.playArea.find('**/rightTeamHopOff%d_locator' % i).getPos())

        for i in xrange(1, 5):
            pos = self.playArea.find('**/fallenToon%d_locator' % i).getPos()
            self.fallenPositions.append(pos)

        self.joinCollision = []
        self.joinCollisionNodePaths = []
        for i in xrange(len(PartyGlobals.TeamActivityTeams)):
            collShape = CollisionTube(PartyGlobals.TugOfWarJoinCollisionEndPoints[0], PartyGlobals.TugOfWarJoinCollisionEndPoints[1], PartyGlobals.TugOfWarJoinCollisionRadius)
            collShape.setTangible(True)
            self.joinCollision.append(CollisionNode('TugOfWarJoinCollision%d' % i))
            self.joinCollision[i].addSolid(collShape)
            tubeNp = self.playArea.attachNewNode(self.joinCollision[i])
            tubeNp.node().setCollideMask(ToontownGlobals.WallBitmask)
            self.joinCollisionNodePaths.append(tubeNp)
            self.joinCollisionNodePaths[i].setPos(PartyGlobals.TugOfWarJoinCollisionPositions[i])

        self.__enableCollisions()
        ropeModel = loader.loadModel('phase_4/models/minigames/tug_of_war_rope')
        self.ropeTexture = ropeModel.findTexture('*')
        ropeModel.removeNode()
        for i in xrange(PartyGlobals.TugOfWarMaximumPlayersPerTeam * 2 - 1):
            rope = Rope(self.uniqueName('TugRope%d' % i))
            if rope.showRope:
                rope.ropeNode.setRenderMode(RopeNode.RMBillboard)
                rope.ropeNode.setThickness(0.2)
                rope.setTexture(self.ropeTexture)
                rope.ropeNode.setUvMode(RopeNode.UVDistance)
                rope.ropeNode.setUvDirection(1)
                rope.setTransparency(1)
                rope.setColor(0.89, 0.89, 0.6, 1.0)
                rope.reparentTo(self.root)
                rope.stash()
            self.tugRopes.append(rope)

        self.splash = Splash.Splash(self.root)
        self.splash.setScale(2.0, 4.0, 1.0)
        pos = self.fallenPositions[0]
        self.splash.setPos(pos[0], pos[1], PartyGlobals.TugOfWarSplashZOffset)
        self.splash.hide()

    def loadGuiElements(self):
        self.powerMeter = MinigamePowerMeter(PartyGlobals.TugOfWarPowerMeterSize)
        self.powerMeter.reparentTo(aspect2d)
        self.powerMeter.setPos(0.0, 0.0, 0.6)
        self.powerMeter.hide()
        self.arrows = [None] * 2
        for x in xrange(len(self.arrows)):
            self.arrows[x] = loader.loadModel('phase_3/models/props/arrow')
            self.arrows[x].reparentTo(self.powerMeter)
            self.arrows[x].setScale(0.2 - 0.4 * x, 0.2, 0.2)
            self.arrows[x].setPos(0.12 - 0.24 * x, 0, -.26)

        return

    def loadSounds(self):
        self.splashSound = base.loadSfx('phase_4/audio/sfx/MG_cannon_splash.ogg')
        self.whistleSound = base.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg')

    def loadIntervals(self):
        self.updateIdealRateInterval = Sequence()
        self.updateIdealRateInterval.append(Wait(PartyGlobals.TugOfWarTargetRateList[0][0]))
        for i in xrange(1, len(PartyGlobals.TugOfWarTargetRateList)):
            duration = PartyGlobals.TugOfWarTargetRateList[i][0]
            idealRate = PartyGlobals.TugOfWarTargetRateList[i][1]
            self.updateIdealRateInterval.append(Func(self.setIdealRate, idealRate))
            if i == len(PartyGlobals.TugOfWarTargetRateList) - 1:
                self.updateIdealRateInterval.append(Func(setattr, self, 'allOutMode', True))
            else:
                self.updateIdealRateInterval.append(Wait(duration))

        self.updateKeyPressRateInterval = Sequence(Wait(PartyGlobals.TugOfWarKeyPressUpdateRate), Func(self.updateKeyPressRate))
        self.reportToServerInterval = Sequence(Wait(PartyGlobals.TugOfWarKeyPressReportRate), Func(self.reportToServer))
        self.setupInterval = Parallel()
        self.globalSetupInterval = Sequence(Wait(PartyGlobals.TugOfWarReadyDuration + PartyGlobals.TugOfWarGoDuration), Func(self.tightenRopes))
        self.localSetupInterval = Sequence(Func(self.setStatus, TTLocalizer.PartyTugOfWarReady), Func(self.showStatus), Wait(PartyGlobals.TugOfWarReadyDuration), Func(base.playSfx, self.whistleSound), Func(self.setStatus, TTLocalizer.PartyTugOfWarGo), Wait(PartyGlobals.TugOfWarGoDuration), Func(self.enableKeys), Func(self.hideStatus), Func(self.updateIdealRateInterval.start), Func(self.updateKeyPressRateInterval.loop), Func(self.reportToServerInterval.loop))
        self.splashInterval = Sequence(Func(base.playSfx, self.splashSound), Func(self.splash.play))

    def unload(self):
        DistributedPartyTeamActivity.unload(self)
        self.arrowKeys.destroy()
        self.unloadIntervals()
        self.unloadModels()
        self.unloadGuiElements()
        self.unloadSounds()
        if hasattr(self, 'toonIds'):
            del self.toonIds
        del self.buttons
        del self.arrowKeys
        del self.keyTTL
        del self.idealRate
        del self.keyRate
        del self.allOutMode
        del self.rateMatchAward
        del self.toonIdsToStartPositions
        del self.toonIdsToIsPullingFlags
        del self.toonIdsToRightHands
        del self.fallenToons
        del self.fallenPositions
        del self.unusedFallenPositionsIndices
        self.toonIdsToAnimIntervals.clear()
        del self.toonIdsToAnimIntervals

    def unloadModels(self):
        self.playArea.removeNode()
        del self.playArea
        del self.dockPositions
        del self.hopOffPositions
        self.__disableCollisions()
        while len(self.joinCollision) > 0:
            collNode = self.joinCollision.pop()
            del collNode

        while len(self.joinCollisionNodePaths) > 0:
            collNodePath = self.joinCollisionNodePaths.pop()
            collNodePath.removeNode()
            del collNodePath

        while len(self.tugRopes) > 0:
            rope = self.tugRopes.pop()
            if rope is not None:
                rope.removeNode()
            del rope

        del self.tugRopes
        self.splash.destroy()
        del self.splash
        return

    def unloadGuiElements(self):
        for arrow in self.arrows:
            if arrow is not None:
                arrow.removeNode()
                del arrow

        del self.arrows
        if self.powerMeter is not None:
            self.powerMeter.cleanup()
            del self.powerMeter
        return

    def unloadSounds(self):
        del self.splashSound
        del self.whistleSound

    def unloadIntervals(self):
        self.updateIdealRateInterval.pause()
        del self.updateIdealRateInterval
        self.updateKeyPressRateInterval.pause()
        del self.updateKeyPressRateInterval
        self.reportToServerInterval.pause()
        del self.reportToServerInterval
        self.setupInterval.pause()
        del self.setupInterval
        self.globalSetupInterval.pause()
        del self.globalSetupInterval
        self.localSetupInterval.pause()
        del self.localSetupInterval
        self.splashInterval.pause()
        del self.splashInterval

    def __enableCollisions(self):
        for i in xrange(len(PartyGlobals.TeamActivityTeams)):
            self.accept('enterTugOfWarJoinCollision%d' % i, getattr(self, '_join%s' % PartyGlobals.TeamActivityTeams.getString(i)))

    def __disableCollisions(self):
        for i in xrange(len(PartyGlobals.TeamActivityTeams)):
            self.ignore('enterTugOfWarJoinCollision%d' % i)

    def startWaitForEnough(self):
        DistributedPartyTeamActivity.startWaitForEnough(self)
        self.__enableCollisions()

    def finishWaitForEnough(self):
        DistributedPartyTeamActivity.finishWaitForEnough(self)
        self.__disableCollisions()

    def startWaitToStart(self, waitStartTimestamp):
        DistributedPartyTeamActivity.startWaitToStart(self, waitStartTimestamp)
        self.__enableCollisions()

    def finishWaitToStart(self):
        DistributedPartyTeamActivity.finishWaitToStart(self)
        self.__disableCollisions()

    def startRules(self):
        DistributedPartyTeamActivity.startRules(self)
        self.setUpRopes()
        if self.isLocalToonPlaying:
            self.showControls()

    def finishRules(self):
        DistributedPartyTeamActivity.finishRules(self)
        if self.activityFSM.getCurrentOrNextState() == 'WaitForEnough':
            self.hideRopes()
            self.hideControls()

    def finishWaitForServer(self):
        DistributedPartyTeamActivity.finishWaitForServer(self)
        if self.activityFSM.getCurrentOrNextState() == 'WaitForEnough':
            self.hideRopes()
            self.hideControls()

    def startActive(self):
        DistributedPartyTeamActivity.startActive(self)
        self.toonIdsToStartPositions.clear()
        self.toonIdsToIsPullingFlags.clear()
        for toonId in self.getToonIdsAsList():
            self.toonIdsToIsPullingFlags[toonId] = False
            toon = self.getAvatar(toonId)
            if toon:
                self.toonIdsToStartPositions[toonId] = toon.getPos(self.root)
            else:
                self.notify.warning("couldn't find toon %d assigning 0,0,0 to startPos" % toonId)
                self.toonIdsToStartPositions[toonId] = Point3(0, 0, 0)

        self.unusedFallenPositionsIndices = [0,
         1,
         2,
         3]
        self.setupInterval = Parallel(self.globalSetupInterval)
        if self.isLocalToonPlaying:
            self.keyTTL = []
            self.idealForce = 0.0
            self.keyRate = 0
            self.rateMatchAward = 0.0
            self.allOutMode = False
            self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
            self.setupInterval.append(self.localSetupInterval)
        self.setupInterval.start()

    def finishActive(self):
        DistributedPartyTeamActivity.finishActive(self)
        self.hideControls()
        self.disableKeys()
        self.setupInterval.pause()
        self.reportToServerInterval.pause()
        self.updateKeyPressRateInterval.pause()
        self.updateIdealRateInterval.pause()
        self.hideRopes()

    def startConclusion(self, losingTeam):
        DistributedPartyTeamActivity.startConclusion(self, losingTeam)
        if self.isLocalToonPlaying:
            self._rewardFinishedSV.set(False)
            if losingTeam == PartyGlobals.TeamActivityNeitherTeam:
                self.setStatus(TTLocalizer.PartyTeamActivityGameTie)
            else:
                self.setStatus(TTLocalizer.PartyTugOfWarGameEnd)
            self.showStatus()
        if losingTeam == PartyGlobals.TeamActivityNeitherTeam:
            for toonId in self.getToonIdsAsList():
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop('neutral')

        else:
            for toonId in self.toonIds[losingTeam]:
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop('neutral')

            for toonId in self.toonIds[1 - losingTeam]:
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop('victory')

        for ival in self.toonIdsToAnimIntervals.values():
            if ival is not None:
                ival.finish()

        return

    def finishConclusion(self):
        DistributedPartyTeamActivity.finishConclusion(self)
        self.fallenToons = []

    def getTitle(self):
        return TTLocalizer.PartyTugOfWarTitle

    def getInstructions(self):
        return TTLocalizer.TugOfWarInstructions

    def showControls(self):
        for arrow in self.arrows:
            arrow.setColor(PartyGlobals.TugOfWarDisabledArrowColor)

        self.powerMeter.setTarget(PartyGlobals.TugOfWarTargetRateList[0][1])
        self.powerMeter.setPower(PartyGlobals.TugOfWarTargetRateList[0][1])
        self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5))
        self.powerMeter.clearTooSlowTooFast()
        self.powerMeter.show()

    def hideControls(self):
        self.powerMeter.hide()

    def setUpRopes(self):
        self.notify.debug('setUpRopes')
        ropeIndex = 0
        leftToonId = -1
        if self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]:
            leftToonId = self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]
        rightToonId = -1
        if self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]:
            rightToonId = self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam][0]
        if leftToonId in self.toonIdsToRightHands and rightToonId in self.toonIdsToRightHands:
            self.tugRopes[ropeIndex].setup(3, ((self.toonIdsToRightHands[leftToonId], (0, 0, 0)), (self.root, (0.0, 0.0, 2.5)), (self.toonIdsToRightHands[rightToonId], (0, 0, 0))), [0,
             0,
             0,
             1,
             1,
             1])
            self.tugRopes[ropeIndex].unstash()
            ropeIndex += 1
        teams = [PartyGlobals.TeamActivityTeams.LeftTeam, PartyGlobals.TeamActivityTeams.RightTeam]
        for currTeam in teams:
            numToons = len(self.toonIds[currTeam])
            if numToons > 1:
                for i in xrange(numToons - 1, 0, -1):
                    toon1 = self.toonIds[currTeam][i]
                    toon2 = self.toonIds[currTeam][i - 1]
                    if not self.toonIdsToRightHands.has_key(toon1):
                        self.notify.warning('Toon in tug of war activity but not properly setup:  %s' % toon1)
                    elif not self.toonIdsToRightHands.has_key(toon2):
                        self.notify.warning('Toon in tug of war activity but not properly setup:  %s' % toon2)
                    else:
                        self.notify.debug('Connecting rope between toon %d and toon %d of team %d.' % (i, i - 1, currTeam))
                        self.tugRopes[ropeIndex].setup(3, ((self.toonIdsToRightHands[toon1], (0, 0, 0)), (self.toonIdsToRightHands[toon1], (0, 0, 0)), (self.toonIdsToRightHands[toon2], (0, 0, 0))), [0,
                         0,
                         0,
                         1,
                         1,
                         1])
                        self.tugRopes[ropeIndex].unstash()
                        ropeIndex += 1

    def tightenRopes(self):
        self.notify.debug('tightenRopes')
        self.tugRopes[0].setup(3, ((self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)), (self.toonIdsToRightHands[self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam][0]], (0, 0, 0))), [0,
         0,
         0,
         1,
         1,
         1])

    def hideRopes(self):
        self.notify.debug('hideRopes')
        for rope in self.tugRopes:
            rope.stash()

    def handleGameTimerExpired(self):
        self.disableKeys()

    def setIdealRate(self, idealRate):
        self.notify.debug('setIdealRate( %d )' % idealRate)
        self.idealRate = idealRate
        self.idealForce = self.advantage * (4 + 0.4 * self.idealRate)

    def updateKeyPressRate(self):
        for i in xrange(len(self.keyTTL)):
            self.keyTTL[i] -= PartyGlobals.TugOfWarKeyPressUpdateRate

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

        self.keyRate = len(self.keyTTL)
        if self.keyRate == self.idealRate or self.keyRate == self.idealRate + 1:
            self.rateMatchAward += 0.3
        else:
            self.rateMatchAward = 0.0

    def reportToServer(self):
        self.currentForce = self.computeForce(self.keyRate)
        self.sendUpdate('reportKeyRateForce', [self.keyRate, self.currentForce])
        self.setSpeedGauge()
        self.setAnimState(base.localAvatar.doId, self.keyRate)

    def computeForce(self, keyRate):
        F = 0
        if self.allOutMode:
            F = 0.75 * keyRate
        else:
            stdDev = 0.25 * self.idealRate
            F = self.advantage * (self.rateMatchAward + 4 + 0.4 * self.idealRate) * math.pow(math.e, -math.pow(keyRate - self.idealRate, 2) / (2.0 * math.pow(stdDev, 2)))
        return F

    def setSpeedGauge(self):
        self.powerMeter.setPower(self.keyRate)
        self.powerMeter.setTarget(self.idealRate)
        if not self.allOutMode:
            self.powerMeter.updateTooSlowTooFast()
            index = float(self.currentForce) / self.idealForce
            bonus = 0.0
            if index > 1.0:
                bonus = max(1.0, index - 1.0)
                index = 1.0
            color = (0,
             0.75 * index + 0.25 * bonus,
             0.75 * (1 - index),
             0.5)
            self.powerMeter.setBarColor(color)
        else:
            self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5))

    def updateToonKeyRate(self, toonId, keyRate):
        if toonId != base.localAvatar.doId:
            self.setAnimState(toonId, keyRate)

    def setAnimState(self, toonId, keyRate):
        if self.activityFSM.state != 'Active':
            return
        toon = self.getAvatar(toonId)
        if not self.toonIdsToIsPullingFlags.has_key(toonId):
            if self.getTeam(toonId) == None:
                self.notify.warning("setAnimState called with toonId (%d) that wasn't in self.toonIds" % toonId)
                return
            else:
                self.notify.warning('setAnimState called with toonId (%d) that was in self.toonIds but not in self.toonIdsToIsPullingFlags. Adding it.' % toonId)
                self.toonIdsToIsPullingFlags[toonId] = False
        if keyRate > 0 and not self.toonIdsToIsPullingFlags[toonId]:
            if toon:
                toon.loop('tug-o-war')
            else:
                self.notify.warning('toon %d is None, skipping toon.loop(tugowar)' % toonId)
            self.toonIdsToIsPullingFlags[toonId] = True
        if keyRate <= 0 and self.toonIdsToIsPullingFlags[toonId]:
            if toon:
                toon.pose('tug-o-war', 3)
                toon.startLookAround()
            else:
                self.notify.warning('toon %d is None, skipping toon.startLookAround' % toonId)
            self.toonIdsToIsPullingFlags[toonId] = False
        return

    def enableKeys(self):
        self.notify.debug('enableKeys')
        self.arrowKeys.setPressHandlers([lambda : self.__pressHandler(2),
         lambda : self.__pressHandler(3),
         lambda : self.__pressHandler(1),
         lambda : self.__pressHandler(0)])
        self.arrowKeys.setReleaseHandlers([lambda : self.__releaseHandler(2),
         lambda : self.__releaseHandler(3),
         lambda : self.__releaseHandler(1),
         lambda : self.__releaseHandler(0)])
        for arrow in self.arrows:
            arrow.setColor(PartyGlobals.TugOfWarEnabledArrowColor)

    def disableKeys(self):
        self.arrowKeys.setPressHandlers(self.arrowKeys.NULL_HANDLERS)
        self.arrowKeys.setReleaseHandlers(self.arrowKeys.NULL_HANDLERS)

    def __pressHandler(self, index):
        if index == self.buttons[0]:
            self.arrows[index].setColor(PartyGlobals.TugOfWarHilightedArrowColor)
            self.keyTTL.insert(0, PartyGlobals.TugOfWarKeyPressTimeToLive)
            self.buttons.reverse()

    def __releaseHandler(self, index):
        if index in self.buttons:
            self.arrows[index].setColor(PartyGlobals.TugOfWarEnabledArrowColor)

    def updateToonPositions(self, offset):
        if self.activityFSM.state != 'Active':
            return
        if self.isLocalToonPlaying:
            camera.lookAt(self.root, offset, 0.0, PartyGlobals.TugOfWarCameraLookAtHeightOffset)
        for toonId in self.getToonIdsAsList():
            if hasattr(self, 'fallenToons') and toonId not in self.fallenToons:
                toon = self.getAvatar(toonId)
                if toon is not None:
                    origPos = self.toonIdsToStartPositions[toonId]
                    curPos = toon.getPos(self.root)
                    newPos = Point3(origPos[0] + offset, curPos[1], curPos[2])
                    if self.toonIdsToAnimIntervals[toonId] != None:
                        if self.toonIdsToAnimIntervals[toonId].isPlaying():
                            self.toonIdsToAnimIntervals[toonId].finish()
                            self.checkIfFallen(toonId)
                    if toonId not in self.fallenToons:
                        self.toonIdsToAnimIntervals[toonId] = Sequence(LerpPosInterval(toon, duration=PartyGlobals.TugOfWarKeyPressReportRate, pos=newPos, other=self.root), Func(self.checkIfFallen, toonId))
                        self.toonIdsToAnimIntervals[toonId].start()

        return

    def checkIfFallen(self, toonId):
        if hasattr(self, 'fallenToons') and toonId not in self.fallenToons:
            toon = self.getAvatar(toonId)
            if toon:
                curPos = toon.getPos(self.root)
                team = self.getTeam(toonId)
                if team == PartyGlobals.TeamActivityTeams.LeftTeam and curPos[0] > -2.0 or team == PartyGlobals.TeamActivityTeams.RightTeam and curPos[0] < 2.0:
                    losingTeam = self.getTeam(toonId)
                    self.throwTeamInWater(losingTeam)
                    self.sendUpdate('reportFallIn', [losingTeam])

    def throwTeamInWater(self, losingTeam):
        self.notify.debug('throwTeamInWater( %s )' % PartyGlobals.TeamActivityTeams.getString(losingTeam))
        splashSet = False
        for toonId in self.toonIds[losingTeam]:
            self.fallenToons.append(toonId)
            toon = self.getAvatar(toonId)
            fallenPosIndex = self.toonIds[losingTeam].index(toonId)
            if fallenPosIndex < 0 or fallenPosIndex >= 4:
                fallenPosIndex = 0
            newPos = self.fallenPositions[fallenPosIndex]
            if self.toonIdsToAnimIntervals.has_key(toonId) and self.toonIdsToAnimIntervals[toonId] is not None:
                if self.toonIdsToAnimIntervals[toonId].isPlaying():
                    self.toonIdsToAnimIntervals[toonId].finish()
            if toon:
                parallel = Parallel(ActorInterval(actor=toon, animName='slip-forward', duration=2.0), LerpPosInterval(toon, duration=2.0, pos=newPos, other=self.root))
            else:
                self.notify.warning('toon %d is none, skipping slip-forward' % toonId)
                parallel = Parallel()
            if not splashSet:
                splashSet = True
                parallel.append(self.splashInterval)
            if toon:
                self.toonIdsToAnimIntervals[toonId] = Sequence(parallel, Func(toon.loop, 'neutral'))
            else:
                self.notify.warning('toon %d is none, skipping toon.loop(neutral)' % toonId)
                self.toonIdsToAnimIntervals[toonId] = parallel
            self.toonIdsToAnimIntervals[toonId].start()

        return

    def setAdvantage(self, advantage):
        DistributedPartyTeamActivity.setAdvantage(self, advantage)
        if self.isLocalToonPlaying:
            self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
コード例 #6
0
class DistributedCogdoInterior(DistributedObject.DistributedObject):
    """
    """

    if __debug__:
        notify = DirectNotifyGlobal.directNotify.newCategory(
            'DistributedCogdoInterior')

    id = 0

    cageHeights = [11.36, 0.01]

    def __init__(self, cr):
        DistributedObject.DistributedObject.__init__(self, cr)

        self.toons = []
        self.activeIntervals = {}

        self.openSfx = base.loader.loadSfx(
            "phase_5/audio/sfx/elevator_door_open.mp3")
        self.closeSfx = base.loader.loadSfx(
            "phase_5/audio/sfx/elevator_door_close.mp3")

        self.suits = []
        self.reserveSuits = []
        self.joiningReserves = []

        self.distBldgDoId = None

        self._CogdoGameRepeat = ConfigVariableBool('cogdo-game-repeat',
                                                   0).getValue()

        # we increment this each time we come out of an elevator:
        self.currentFloor = -1

        self.elevatorName = self.__uniqueName('elevator')
        self.floorModel = None

        self.elevatorOutOpen = 0

        # initial cog positions vary based on the cog office model
        self.BottomFloor_SuitPositions = [
            Point3(0, 15, 0),
            Point3(10, 20, 0),
            Point3(-7, 24, 0),
            Point3(-10, 0, 0)
        ]
        self.BottomFloor_SuitHs = [75, 170, -91, -44]  # Heading angles

        self.Cubicle_SuitPositions = [
            Point3(0, 18, 0),
            Point3(10, 12, 0),
            Point3(-9, 11, 0),
            Point3(-3, 13, 0)
        ]
        self.Cubicle_SuitHs = [170, 56, -52, 10]

        self.BossOffice_SuitPositions = [
            Point3(0, 15, 0),
            Point3(10, 20, 0),
            Point3(-10, 6, 0),
            Point3(-17, 30, 0),
        ]
        self.BossOffice_SuitHs = [170, 120, 12, 38]

        self._wantBarrelRoom = ConfigVariableBool('cogdo-want-barrel-room',
                                                  0).getValue()
        self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom()
        self.brResults = [[], []]
        self.barrelRoomIntroTrack = None

        self.penthouseOutroTrack = None
        self.penthouseOutroChatDoneTrack = None
        self.penthouseIntroTrack = None

        self.waitMusic = base.loader.loadMusic(
            'phase_7/audio/bgm/encntr_toon_winning_indoor.mid')
        self.elevatorMusic = base.loader.loadMusic(
            'phase_7/audio/bgm/tt_elevator.mid')

        self.fsm = ClassicFSM.ClassicFSM(
            'DistributedCogdoInterior',
            [
                State.State('WaitForAllToonsInside',
                            self.enterWaitForAllToonsInside,
                            self.exitWaitForAllToonsInside, ['Elevator']),
                State.State('Elevator', self.enterElevator, self.exitElevator,
                            ['Game']),
                State.State('Game', self.enterGame, self.exitGame,
                            ['Resting', 'Failed', 'BattleIntro']),
                State.State('BarrelRoomIntro', self.enterBarrelRoomIntro,
                            self.exitBarrelRoomIntro,
                            ['CollectBarrels', 'Off']),
                State.State('CollectBarrels', self.enterCollectBarrels,
                            self.exitCollectBarrels,
                            ['BarrelRoomReward', 'Off']),
                State.State(
                    'BarrelRoomReward', self.enterBarrelRoomReward,
                    self.exitBarrelRoomReward,
                    ['Battle', 'ReservesJoining', 'BattleIntro', 'Off']),
                State.State('BattleIntro', self.enterBattleIntro,
                            self.exitBattleIntro,
                            ['Battle', 'ReservesJoining', 'Off']),
                State.State('Battle', self.enterBattle, self.exitBattle,
                            ['Resting', 'Reward', 'ReservesJoining']),
                State.State('ReservesJoining', self.enterReservesJoining,
                            self.exitReservesJoining, ['Battle']),
                State.State('Resting', self.enterResting, self.exitResting,
                            ['Elevator']),
                State.State('Reward', self.enterReward, self.exitReward,
                            ['Off']),
                State.State('Failed', self.enterFailed, self.exitFailed,
                            ['Off']),
                State.State('Off', self.enterOff, self.exitOff,
                            ['Elevator', 'WaitForAllToonsInside', 'Battle']),
            ],
            # Initial State
            'Off',
            # Final State
            'Off',
        )

        # make sure we're in the initial state
        self.fsm.enterInitialState()
        self._haveEntranceElevator = StateVar(False)
        self._stashEntranceElevator = StateVar(False)
        self._stashEntranceElevatorFC = FunctionCall(
            self._doStashEntranceElevator, self._haveEntranceElevator,
            self._stashEntranceElevator)
        self._entranceElevCallbacks = []
        self._doEntranceElevCallbacksFC = FunctionCall(
            self._doEntranceElevCallbacks, self._haveEntranceElevator)
        self.cage = None
        self.shopOwnerNpcId = None
        self.shopOwnerNpc = None
        self._movie = None
        self.SOSToonName = None
        self.FOType = None

    def setShopOwnerNpcId(self, npcId):
        self.shopOwnerNpcId = npcId

    def setSOSNpcId(self, npcId):
        self.SOSToonName = NPCToons.getNPCName(npcId)

    def setFOType(self, typeId):
        self.FOType = chr(typeId)

    def __uniqueName(self, name):
        DistributedCogdoInterior.id += 1
        return (name + '%d' % DistributedCogdoInterior.id)

    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.
        """
        assert (self.notify.debug("generate()"))
        DistributedObject.DistributedObject.generate(self)

        # listen for the generate event, which will be thrown after the
        # required fields are filled in
        self.announceGenerateName = self.uniqueName('generate')
        self.accept(self.announceGenerateName, self.handleAnnounceGenerate)

        # Load the elevator model
        self.elevatorModelIn = loader.loadModel(
            'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB')
        self.leftDoorIn = self.elevatorModelIn.find('**/left-door')
        self.rightDoorIn = self.elevatorModelIn.find('**/right-door')

        self.elevatorModelOut = loader.loadModel(
            'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB')
        self.leftDoorOut = self.elevatorModelOut.find('**/left-door')
        self.rightDoorOut = self.elevatorModelOut.find('**/right-door')

    def __makeShopOwnerNpc(self):
        if self.shopOwnerNpc:
            return
        self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId)
        if not self.shopOwnerNpc:
            self.notify.warning(
                "No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons"
            )
            random.seed(self.doId)
            shopkeeper = random.randint(7001, 7009)
            self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper)
        self.shopOwnerNpc.addActive()
        self.shopOwnerNpc.reparentTo(self.cage)
        self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0)
        self.shopOwnerNpc.loop('neutral')

    def setElevatorLights(self, elevatorModel):
        """
        Sets up the lights on the interior elevators to represent the
        number of floors in the building, and to light up the current
        floor number.
        """
        npc = elevatorModel.findAllMatches("**/floor_light_?;+s")
        for i in range(npc.getNumPaths()):
            np = npc.getPath(i)
            # Get the last character, and make it zero based:
            floor = int(np.getName()[-1:]) - 1

            if (floor == self.currentFloor):
                np.setColor(LIGHT_ON_COLOR)
            elif floor < self.layout.getNumGameFloors():
                if self.isBossFloor(self.currentFloor):
                    np.setColor(LIGHT_ON_COLOR)
                else:
                    np.setColor(LIGHT_OFF_COLOR)
            else:
                np.hide()

    def startAlertElevatorLightIval(self, elevatorModel):
        light = elevatorModel.find("**/floor_light_%s" %
                                   (self.currentFloor + 1))
        track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)),
                         Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR),
                         Wait(0.9))
        self.activeIntervals["alertElevatorLight"] = track
        track.loop()

    def stopAlertElevatorLightIval(self, elevatorModel):
        self.__finishInterval("alertElevatorLight")
        self.setElevatorLights(elevatorModel)

    def handleAnnounceGenerate(self, obj):
        """
        handleAnnounceGenerate is called after all of the required fields are
        filled in
        'obj' is another copy of self
        """
        self.ignore(self.announceGenerateName)

        self.cageDoorSfx = loader.loadSfx(
            'phase_5/audio/sfx/CHQ_SOS_cage_door.mp3')
        self.cageLowerSfx = loader.loadSfx(
            'phase_5/audio/sfx/CHQ_SOS_cage_lower.mp3')

        assert (self.notify.debug('joining DistributedCogdoInterior'))
        # Update the minigame AI to join our local toon doId
        self.sendUpdate('setAvatarJoined', [])

    def disable(self):
        assert (self.notify.debug('disable()'))
        self.fsm.requestFinalState()
        self.__cleanupIntervals()
        self.ignoreAll()
        self.__cleanup()
        self.__cleanupShopOwnerNpc()
        self.__cleanupPenthouseIntro()
        DistributedObject.DistributedObject.disable(self)

    def __cleanupShopOwnerNpc(self):
        if self.shopOwnerNpc:
            self.shopOwnerNpc.removeActive()
            self.shopOwnerNpc.delete()
            self.shopOwnerNpc = None

    def __cleanupPenthouseIntro(self):
        if hasattr(self, '_movie') and self._movie:
            self._movie.unload()
            self._movie = None

    def delete(self):
        assert (self.notify.debug('delete()'))
        self._stashEntranceElevatorFC.destroy()
        self._doEntranceElevCallbacksFC.destroy()
        self._haveEntranceElevator.destroy()
        self._stashEntranceElevator.destroy()
        self._entranceElevCallbacks = None
        del self.waitMusic
        del self.elevatorMusic
        del self.openSfx
        del self.closeSfx
        del self.fsm
        # No more battle multiplier
        base.localAvatar.inventory.setBattleCreditMultiplier(1)
        DistributedObject.DistributedObject.delete(self)

    def isBossFloor(self, floorNum):
        if self.layout.hasBossBattle():
            if self.layout.getBossBattleFloor() == floorNum:
                return True
        return False

    def __cleanup(self):
        self.toons = []
        self.suits = []
        self.reserveSuits = []
        self.joiningReserves = []
        # Clean up elevator models
        if (self.elevatorModelIn != None):
            self.elevatorModelIn.removeNode()
        if (self.elevatorModelOut != None):
            self.elevatorModelOut.removeNode()
        # Clean up current floor
        if (self.floorModel != None):
            self.floorModel.removeNode()
        # Clean up current cage
        if (self.cage != None):
            self.cage = None
        # Clean up current barrel room
        if (self.barrelRoom != None):
            self.barrelRoom.destroy()
            self.barrelRoom = None
        self.leftDoorIn = None
        self.rightDoorIn = None
        self.leftDoorOut = None
        self.rightDoorOut = None

    def __addToon(self, toon):
        assert (self.notify.debug('addToon(%d)' % toon.doId))
        self.accept(toon.uniqueName('disable'),
                    self.__handleUnexpectedExit,
                    extraArgs=[toon])

    def __handleUnexpectedExit(self, toon):
        self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId)
        self.__removeToon(toon, unexpected=1)

    def __removeToon(self, toon, unexpected=0):
        assert (self.notify.debug('removeToon() - toon: %d' % toon.doId))
        if (self.toons.count(toon) == 1):
            self.toons.remove(toon)
        self.ignore(toon.uniqueName('disable'))

    def __finishInterval(self, name):
        """ Force the specified interval to jump to the end
        """
        if (name in self.activeIntervals):
            interval = self.activeIntervals[name]
            if (interval.isPlaying()):
                assert(self.notify.debug('finishInterval(): %s' % \
                        interval.getName()))
                interval.finish()

    def __cleanupIntervals(self):
        for interval in list(self.activeIntervals.values()):
            interval.finish()
        self.activeIntervals = {}

    def __closeInElevator(self):
        self.leftDoorIn.setPos(3.5, 0, 0)
        self.rightDoorIn.setPos(-3.5, 0, 0)

    ##### Messages from the server #####

    def getZoneId(self):
        return self.zoneId

    def setZoneId(self, zoneId):
        self.zoneId = zoneId

    def getExtZoneId(self):
        return self.extZoneId

    def setExtZoneId(self, extZoneId):
        self.extZoneId = extZoneId

    def getDistBldgDoId(self):
        return self.distBldgDoId

    def setDistBldgDoId(self, distBldgDoId):
        self.distBldgDoId = distBldgDoId

    def setNumFloors(self, numFloors):
        self.layout = CogdoLayout(numFloors)

    def getToonIds(self):
        toonIds = []
        for toon in self.toons:
            toonIds.append(toon.doId)
        return toonIds

    def setToons(self, toonIds, hack):
        assert (self.notify.debug('setToons(): %s' % toonIds))
        self.toonIds = toonIds
        oldtoons = self.toons
        self.toons = []
        for toonId in toonIds:
            if (toonId != 0):
                if (toonId in self.cr.doId2do):
                    toon = self.cr.doId2do[toonId]
                    toon.stopSmooth()
                    self.toons.append(toon)
                    if (oldtoons.count(toon) == 0):
                        assert(self.notify.debug('setToons() - new toon: %d' % \
                                toon.doId))
                        self.__addToon(toon)
                else:
                    self.notify.warning('setToons() - no toon: %d' % toonId)
        for toon in oldtoons:
            if (self.toons.count(toon) == 0):
                self.__removeToon(toon)

    def setSuits(self, suitIds, reserveIds, values):
        assert(self.notify.debug('setSuits(): active %s reserve %s values %s' \
                % (suitIds, reserveIds, values)))
        oldsuits = self.suits
        self.suits = []
        self.joiningReserves = []
        for suitId in suitIds:
            if (suitId in self.cr.doId2do):
                suit = self.cr.doId2do[suitId]
                self.suits.append(suit)
                # Set this on the client
                suit.fsm.request('Battle')
                # This will allow client to respond to setState() from the
                # server from here on out
                suit.buildingSuit = 1
                suit.reparentTo(render)
                if (oldsuits.count(suit) == 0):
                    assert(self.notify.debug('setSuits() suit: %d joining' % \
                        suit.doId))
                    self.joiningReserves.append(suit)
            else:
                self.notify.warning('setSuits() - no suit: %d' % suitId)
        self.reserveSuits = []
        assert (len(reserveIds) == len(values))
        for index in range(len(reserveIds)):
            suitId = reserveIds[index]
            if (suitId in self.cr.doId2do):
                suit = self.cr.doId2do[suitId]
                self.reserveSuits.append((suit, values[index]))
            else:
                self.notify.warning('setSuits() - no suit: %d' % suitId)

        if (len(self.joiningReserves) > 0):
            assert (self.notify.debug('setSuits() reserves joining'))
            self.fsm.request('ReservesJoining')

    def setState(self, state, timestamp):
        assert(self.notify.debug("setState(%s, %d)" % \
                                (state, timestamp)))
        self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])

    def stashElevatorIn(self, stash=True):
        self._stashEntranceElevator.set(stash)

    def getEntranceElevator(self, callback):
        if self._haveEntranceElevator.get():
            callback(self.elevIn)
        else:
            self._entranceElevCallbacks.append(callback)

    def _doEntranceElevCallbacks(self, haveElev):
        if haveElev:
            while len(self._entranceElevCallbacks):
                cbs = self._entranceElevCallbacks[:]
                self._entranceElevCallbacks = []
                for callback in cbs:
                    callback(self.elevIn)

    def _doStashEntranceElevator(self, haveElev, doStash):
        if haveElev:
            if doStash:
                self.elevIn.stash()
            else:
                self.elevIn.unstash()

    ##### Messages to the server #####

    def d_elevatorDone(self):
        assert (self.notify.debug('network:elevatorDone(%d)' %
                                  base.localAvatar.doId))
        self.sendUpdate('elevatorDone', [])

    def d_reserveJoinDone(self):
        assert (self.notify.debug('network:reserveJoinDone(%d)' %
                                  base.localAvatar.doId))
        self.sendUpdate('reserveJoinDone', [])

    # Specific State Functions

    ##### Off state #####

    def enterOff(self, ts=0):
        assert (self.notify.debug('enterOff()'))
        messenger.send('sellbotFieldOfficeChanged', [False])
        return None

    def exitOff(self):
        return None

    ##### WaitForAllToonsInside state #####

    def enterWaitForAllToonsInside(self, ts=0):
        assert (self.notify.debug('enterWaitForAllToonsInside()'))
        base.transitions.fadeOut(0)
        return None

    def exitWaitForAllToonsInside(self):
        return None

    def enterGame(self, ts=0):
        assert (self.notify.debug('enterElevator()'))
        base.cr.forbidCheesyEffects(1)

    def exitGame(self):
        base.cr.forbidCheesyEffects(0)

    ##### Elevator state #####

    def __playElevator(self, ts, name, callback):
        # Load the floor model

        SuitHs = []  # Heading angles
        SuitPositions = []

        if self.floorModel:
            self.floorModel.removeNode()
            self.floorModel = None
        if self.cage:
            self.cage = None

        if (self.currentFloor == 0):
            # bottom floor
            SuitHs = self.BottomFloor_SuitHs
            SuitPositions = self.BottomFloor_SuitPositions
        if self.isBossFloor(self.currentFloor):
            # Top floor
            self.barrelRoom.unload()
            self.floorModel = loader.loadModel(
                'phase_5/models/cogdominium/tt_m_ara_crg_penthouse')
            self.cage = self.floorModel.find('**/cage')
            pos = self.cage.getPos()
            self.cagePos = []
            for height in self.cageHeights:
                self.cagePos.append(Point3(pos[0], pos[1], height))

            self.cageDoor = self.floorModel.find('**/cage_door')
            self.cageDoor.wrtReparentTo(self.cage)
            if self.FOType:
                paintingModelName = PAINTING_DICT.get(self.FOType)
                for i in range(4):
                    paintingModel = loader.loadModel(
                        'phase_5/models/cogdominium/%s' % paintingModelName)
                    loc = self.floorModel.find('**/loc_painting%d' % (i + 1))
                    paintingModel.reparentTo(loc)
            SuitHs = self.BossOffice_SuitHs
            SuitPositions = self.BossOffice_SuitPositions
            self.__makeShopOwnerNpc()
        else:
            if self._wantBarrelRoom:
                self.barrelRoom.load()
                self.barrelRoom.hide()
            # middle floor
            SuitHs = self.Cubicle_SuitHs
            SuitPositions = self.Cubicle_SuitPositions

        if self.floorModel:
            self.floorModel.reparentTo(render)

            if self.isBossFloor(self.currentFloor):
                self.notify.debug('Load boss_suit_office')
                elevIn = self.floorModel.find(
                    CogdoGameConsts.PenthouseElevatorInPath).copyTo(render)
                elevOut = self.floorModel.find(
                    CogdoGameConsts.PenthouseElevatorOutPath)
                frame = self.elevatorModelOut.find('**/frame')
                if not frame.isEmpty():
                    frame.hide()
                frame = self.elevatorModelIn.find('**/frame')
                if not frame.isEmpty():
                    frame.hide()
                self.elevatorModelOut.reparentTo(elevOut)
            else:
                # We need to name this something more useful (and we'll need the
                # location of the opposite elevator as well)
                elevIn = self.floorModel.find('**/elevator-in')
                elevOut = self.floorModel.find('**/elevator-out')
        elif self._wantBarrelRoom and self.barrelRoom.isLoaded():
            elevIn = self.barrelRoom.dummyElevInNode
            elevOut = self.barrelRoom.model.find(
                CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath)
            y = elevOut.getY(render)
            elevOut = elevOut.copyTo(render)
            elevOut.setY(render, y - 0.75)
        else:
            # TODO: TEMP
            floorModel = loader.loadModel(
                'phase_7/models/modules/boss_suit_office')
            elevIn = floorModel.find('**/elevator-in').copyTo(render)
            elevOut = floorModel.find('**/elevator-out').copyTo(render)
            floorModel.removeNode()
        self.elevIn = elevIn

        # store elevOut until it's needed
        self.elevOut = elevOut
        self._haveEntranceElevator.set(True)

        # Position the suits

        assert (len(self.suits) <= 4)
        for index in range(len(self.suits)):
            assert(self.notify.debug('setting suit: %d to pos: %s' % \
                (self.suits[index].doId, SuitPositions[index])))
            self.suits[index].setPos(SuitPositions[index])
            if (len(self.suits) > 2):
                self.suits[index].setH(SuitHs[index])
            else:
                self.suits[index].setH(
                    170
                )  # if there's 2 or 1 suits, make them face fwd since there's no other suits they would be to be talking to
            self.suits[index].loop('neutral')

        # Position the toons
        for toon in self.toons:
            toon.reparentTo(self.elevatorModelIn)
            assert (self.toonIds.count(toon.doId) == 1)
            index = self.toonIds.index(toon.doId)
            assert (index >= 0 and index <= 3)
            toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1],
                        ElevatorPoints[index][2])
            toon.setHpr(180, 0, 0)
            toon.loop('neutral')

        # Show the elevator and position it in the correct place for the floor
        self.elevatorModelIn.reparentTo(elevIn)
        # Start with the doors in closed position
        self.leftDoorIn.setPos(3.5, 0, 0)
        self.rightDoorIn.setPos(-3.5, 0, 0)

        # Position the camera behind the toons
        camera.reparentTo(self.elevatorModelIn)
        camera.setH(180)
        camera.setP(0)
        camera.setPos(0, 14, 4)

        # Play elevator music
        base.playMusic(self.elevatorMusic, looping=1, volume=0.8)

        # Ride the elevator, then open the doors.
        track = Sequence(
            Func(base.transitions.noTransitions),
            ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL),
            ElevatorUtils.getOpenInterval(self,
                                          self.leftDoorIn,
                                          self.rightDoorIn,
                                          self.openSfx,
                                          None,
                                          type=ELEVATOR_NORMAL),
            Func(camera.wrtReparentTo, render),
        )

        for toon in self.toons:
            track.append(Func(toon.wrtReparentTo, render))
        track.append(Func(callback))
        track.start(ts)
        self.activeIntervals[name] = track

    def enterElevator(self, ts=0):
        # Load model for the current floor and the suit models for the floor
        assert (self.notify.debug('enterElevator()'))

        if not self._CogdoGameRepeat:
            self.currentFloor += 1
        self.cr.playGame.getPlace().currentFloor = self.currentFloor
        self.setElevatorLights(self.elevatorModelIn)
        self.setElevatorLights(self.elevatorModelOut)

        # hide elevator from previous floor (if any)
        # unless it's the top floor, in that case leave it where it is
        if not self.isBossFloor(self.currentFloor):
            self.elevatorModelOut.detachNode()
            messenger.send('sellbotFieldOfficeChanged', [True])
        else:
            self._movie = CogdoElevatorMovie()
            self._movie.load()
            self._movie.play()

        self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone)

        # Get the floor multiplier
        mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor)
        # Now set the inventory battleCreditMult
        base.localAvatar.inventory.setBattleCreditMultiplier(mult)

    def __handleElevatorDone(self):
        assert (self.notify.debug('handleElevatorDone()'))
        self.d_elevatorDone()

    def exitElevator(self):
        self.elevatorMusic.stop()
        if self._movie:
            self._movie.end()
            self.__cleanupPenthouseIntro()
        self.__finishInterval(self.elevatorName)
        return None

    def __setupBarrelRoom(self):
        base.cr.playGame.getPlace().fsm.request('stopped')
        base.transitions.irisOut(0.0)
        self.elevatorModelIn.detachNode()
        self._showExitElevator()
        self.barrelRoom.show()
        self.barrelRoom.placeToonsAtEntrance(self.toons)

    def barrelRoomIntroDone(self):
        self.sendUpdate('toonBarrelRoomIntroDone', [])

    def enterBarrelRoomIntro(self, ts=0):
        if not self.isBossFloor(self.currentFloor):
            if self._wantBarrelRoom:
                self.__setupBarrelRoom()
                self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval(
                )
                self.barrelRoomIntroDoneEvent = trackName
                self.accept(self.barrelRoomIntroDoneEvent,
                            self.barrelRoomIntroDone)
                self.activeIntervals[trackName] = self.barrelRoomIntroTrack
                self.barrelRoomIntroTrack.start(ts)
            else:
                self._showExitElevator()

    def exitBarrelRoomIntro(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            self.ignore(self.barrelRoomIntroDoneEvent)
            if self.barrelRoomIntroTrack:
                self.barrelRoomIntroTrack.finish()
                DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack)
                self.barrelRoomIntroTrack = None
        return

    def __handleLocalToonLeftBarrelRoom(self):
        self.notify.info('Local toon teleported out of barrel room.')
        self.sendUpdate('toonLeftBarrelRoom', [])
        self.barrelRoom.deactivate()

    def enterCollectBarrels(self, ts=0):
        if not self.isBossFloor(self.currentFloor):
            if self._wantBarrelRoom:
                self.acceptOnce('localToonLeft',
                                self.__handleLocalToonLeftBarrelRoom)
                self.barrelRoom.activate()
                base.playMusic(self.waitMusic, looping=1, volume=0.7)

    def exitCollectBarrels(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            self.ignore('localToonLeft')
            self.barrelRoom.deactivate()
            self.waitMusic.stop()

    def __brRewardDone(self, task=None):
        self.notify.info('Toon finished watching the barrel room reward.')
        self.sendUpdate('toonBarrelRoomRewardDone', [])

    def setBarrelRoomReward(self, avIds, laffs):
        self.brResults = [avIds, laffs]
        self.barrelRoom.setRewardResults(self.brResults)

    def enterBarrelRoomReward(self, ts=0):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            base.cr.playGame.getPlace().fsm.request('stopped')
            self.startAlertElevatorLightIval(self.elevatorModelOut)
            track, trackName = self.barrelRoom.showRewardUi(
                self.brResults, callback=self.__brRewardDone)
            self.activeIntervals[trackName] = track
            track.start()
            self.barrelRoom.placeToonsNearBattle(self.toons)

    def exitBarrelRoomReward(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            base.cr.playGame.getPlace().fsm.request('walk')
            self.stopAlertElevatorLightIval(self.elevatorModelOut)
            self.barrelRoom.hideRewardUi()

    def enterBattleIntro(self, ts=0):
        self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc)
        self._movie.load()
        self._movie.play()

    def exitBattleIntro(self):
        self._movie.end()
        self.__cleanupPenthouseIntro()

    ##### Battle state #####

    def __playCloseElevatorOut(self, name, delay=0):
        # Close the elevator doors
        track = Sequence(
            Wait(delay + SUIT_LEAVE_ELEVATOR_TIME),
            Parallel(
                SoundInterval(self.closeSfx),
                LerpPosInterval(
                    self.leftDoorOut,
                    ElevatorData[ELEVATOR_NORMAL]['closeTime'],
                    ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL),
                    startPos=Point3(0, 0, 0),
                    blendType='easeOut'),
                LerpPosInterval(
                    self.rightDoorOut,
                    ElevatorData[ELEVATOR_NORMAL]['closeTime'],
                    ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL),
                    startPos=Point3(0, 0, 0),
                    blendType='easeOut')),
        )
        track.start()
        self.activeIntervals[name] = track

    def enterBattle(self, ts=0):
        assert (self.notify.debug('enterBattle()'))

        if self._wantBarrelRoom and self.elevatorOutOpen == 1:
            self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'),
                                        delay=2)
            camera.setPos(0, -15, 6)
            camera.headsUp(self.elevatorModelOut)

    def _showExitElevator(self):

        # now that we're in the barrel room, show the exit elevator
        # Show the elevator and position it in the correct place for the floor
        self.elevatorModelOut.reparentTo(self.elevOut)
        # Start with the doors in closed position
        self.leftDoorOut.setPos(3.5, 0, 0)
        self.rightDoorOut.setPos(-3.5, 0, 0)

        if not (self._wantBarrelRoom and self.elevatorOutOpen == 1):
            self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'))
            # Watch reserve suits as they walk from the elevator
            camera.setPos(0, -15, 6)
            camera.headsUp(self.elevatorModelOut)
        return None

    def exitBattle(self):
        if (self.elevatorOutOpen == 1):
            self.__finishInterval(self.uniqueName('close-out-elevator'))
            self.elevatorOutOpen = 0
        return None

    ##### ReservesJoining state #####

    def __playReservesJoining(self, ts, name, callback):
        # Position the joining suits
        index = 0
        assert (len(self.joiningReserves) <= 4)
        for suit in self.joiningReserves:
            suit.reparentTo(render)
            suit.setPos(
                self.elevatorModelOut,
                Point3(ElevatorPoints[index][0], ElevatorPoints[index][1],
                       ElevatorPoints[index][2]))
            index += 1
            suit.setH(180)
            suit.loop('neutral')

        if len(self.suits) == len(self.joiningReserves):
            camSequence = Sequence(Func(camera.wrtReparentTo, localAvatar),
                                   Func(camera.setPos, Point3(0, 5, 5)),
                                   Func(camera.headsUp, self.elevatorModelOut))
        else:
            camSequence = Sequence(
                Func(camera.wrtReparentTo, self.elevatorModelOut),
                Func(camera.setPos, Point3(0, -8, 2)),
                Func(camera.setHpr, Vec3(0, 10, 0)))

        # Aim the camera at the far elevator
        track = Sequence(
            Func(camera.wrtReparentTo, self.elevatorModelOut),
            Func(camera.setPos, Point3(0, -8, 2)),
            Func(camera.setHpr, Vec3(0, 10, 0)),

            # Open the elevator doors
            Parallel(
                SoundInterval(self.openSfx),
                LerpPosInterval(
                    self.leftDoorOut,
                    ElevatorData[ELEVATOR_NORMAL]['closeTime'],
                    Point3(0, 0, 0),
                    startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL),
                    blendType='easeOut'),
                LerpPosInterval(
                    self.rightDoorOut,
                    ElevatorData[ELEVATOR_NORMAL]['closeTime'],
                    Point3(0, 0, 0),
                    startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL),
                    blendType='easeOut'),
            ),

            # Hold the camera angle for a couple of beats
            Wait(SUIT_HOLD_ELEVATOR_TIME),

            # Reparent the camera to render (enterWaitForInput will
            # position it properly again by the battle)
            Func(camera.wrtReparentTo, render),
            Func(callback),
        )
        track.start(ts)
        self.activeIntervals[name] = track

    def enterReservesJoining(self, ts=0):
        assert (self.notify.debug('enterReservesJoining()'))
        self.__playReservesJoining(ts, self.uniqueName('reserves-joining'),
                                   self.__handleReserveJoinDone)
        return None

    def __handleReserveJoinDone(self):
        assert (self.notify.debug('handleReserveJoinDone()'))
        self.joiningReserves = []
        self.elevatorOutOpen = 1
        self.d_reserveJoinDone()

    def exitReservesJoining(self):
        self.__finishInterval(self.uniqueName('reserves-joining'))
        return None

    ##### Resting state #####

    def enterResting(self, ts=0):
        assert (self.notify.debug('enterResting()'))
        self._showExitElevator()
        self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit)
        if self._wantBarrelRoom:
            self.barrelRoom.showBattleAreaLight(True)
        base.playMusic(self.waitMusic, looping=1, volume=0.7)
        self.__closeInElevator()
        self._haveEntranceElevator.set(False)
        self._stashEntranceElevator.set(False)
        return

    def _setAvPosToExit(self):
        base.localAvatar.setPos(self.elevOut, 0, -10, 0)
        base.localAvatar.setHpr(self.elevOut, 0, 0, 0)
        base.cr.playGame.getPlace().fsm.request('walk')

    def exitResting(self):
        self._setAvPosFDC.destroy()
        self.waitMusic.stop()
        return

    ##### Reward state #####

    def enterReward(self, ts=0):
        assert (self.notify.debug('enterReward()'))
        if self.isBossFloor(self.currentFloor):
            self.penthouseOutroTrack = self.__outroPenthouse()
            self.penthouseOutroTrack.start(ts)
        else:
            self.exitCogdoBuilding()
        return None

    def exitReward(self):
        self.notify.debug('exitReward')
        if self.penthouseOutroTrack:
            self.penthouseOutroTrack.finish()
            DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack)
            self.penthouseOutroTrack = None
            if not self.penthouseOutroChatDoneTrack:
                self.notify.debug(
                    'exitReward: instanting outroPenthouseChatDone track')
                self.__outroPenthouseChatDone()
            self.penthouseOutroChatDoneTrack.finish()
            self.penthouseOutroChatDoneTrack = None
        return

    ##### Failed state #####

    def enterFailed(self, ts=0):
        self.exitCogdoBuilding()
        return None

    def exitFailed(self):
        self.notify.debug('exitFailed()')
        self.exitCogdoBuilding()
        return None

    def exitCogdoBuilding(self):
        if base.localAvatar.hp < 0:
            return
        base.localAvatar.b_setParent(ToontownGlobals.SPHidden)
        request = {
            'loader': ZoneUtil.getBranchLoaderName(self.extZoneId),
            'where': ZoneUtil.getToonWhereName(self.extZoneId),
            'how': 'elevatorIn',
            'hoodId': ZoneUtil.getHoodId(self.extZoneId),
            'zoneId': self.extZoneId,
            'shardId': None,
            'avId': -1,
            'bldgDoId': self.distBldgDoId
        }
        messenger.send('DSIDoneEvent', [request])
        return

    def displayBadges(self):
        numFloors = self.layout.getNumGameFloors()
        if numFloors > 5 or numFloors < 3:
            pass
        else:
            self.notify.warning('Invalid floor number for display badges.')
        for player in range(len(self.toons)):
            goldBadge = loader.loadModel(
                'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy')
            goldBadge.setScale(1.2)
            goldNode = render.find('**/gold_0' + str(player + 1))
            goldBadge.reparentTo(goldNode)
            for floor in range(numFloors):
                silverBadge = loader.loadModel(
                    'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam')
                silverBadge.setScale(1.2)
                silverNode = render.find('**/silver_0' + str(floor * 4 +
                                                             (player + 1)))
                silverBadge.reparentTo(silverNode)

    ##### Outro state #####

    def __outroPenthouse(self):
        avatar = base.localAvatar
        trackName = '__outroPenthouse-%d' % avatar.doId
        track = Parallel(name=trackName)
        base.cr.playGame.getPlace().fsm.request('stopped')
        speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName
        track.append(
            Sequence(
                Func(camera.wrtReparentTo, localAvatar),
                Func(camera.setPos, 0, -9, 9),
                Func(camera.lookAt, Point3(5, 15, 0)),
                Parallel(
                    self.cage.posInterval(0.75,
                                          self.cagePos[1],
                                          blendType='easeOut'),
                    SoundInterval(self.cageLowerSfx, duration=0.5)),
                Parallel(
                    self.cageDoor.hprInterval(0.5,
                                              VBase3(0, 90, 0),
                                              blendType='easeOut'),
                    Sequence(SoundInterval(self.cageDoorSfx), duration=0)),
                Wait(0.25), Func(self.shopOwnerNpc.wrtReparentTo, render),
                Func(self.shopOwnerNpc.setScale, 1),
                Func(self.shopOwnerNpc.loop, 'walk'),
                Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)),
                ParallelEndTogether(
                    self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)),
                    self.shopOwnerNpc.hprInterval(0.5,
                                                  VBase3(180, 0, 0),
                                                  blendType='easeInOut')),
                Func(self.shopOwnerNpc.setChatAbsolute,
                     TTLocalizer.CagedToonYippee, CFSpeech),
                ActorInterval(self.shopOwnerNpc, 'jump'),
                Func(self.shopOwnerNpc.loop, 'neutral'),
                Func(self.shopOwnerNpc.headsUp, localAvatar),
                Func(self.shopOwnerNpc.setLocalPageChat, speech, 0),
                Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2))))
        self.activeIntervals[trackName] = track
        self.accept('doneChatPage', self.__outroPenthouseChatDone)
        return track

    def __outroPenthouseChatDone(self, elapsed=None):
        self.shopOwnerNpc.setChatAbsolute(
            TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech)
        self.ignore('doneChatPage')
        track = Parallel(
            Sequence(ActorInterval(self.shopOwnerNpc, 'wave'),
                     Func(self.shopOwnerNpc.loop, 'neutral')),
            Sequence(
                Wait(2.0),
                Func(self.exitCogdoBuilding),
                Func(base.camLens.setMinFov, ToontownGlobals.DefaultCameraFov),
            ),
        )
        track.start()
        self.penthouseOutroChatDoneTrack = track
コード例 #7
0
class DistributedCogdoInterior(DistributedObject.DistributedObject):
    id = 0
    cageHeights = [11.36, 0.01]

    def __init__(self, cr):
        DistributedObject.DistributedObject.__init__(self, cr)
        self.toons = []
        self.activeIntervals = {}
        self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg')
        self.closeSfx = base.loadSfx(
            'phase_5/audio/sfx/elevator_door_close.ogg')
        self.suits = []
        self.reserveSuits = []
        self.joiningReserves = []
        self.distBldgDoId = None
        self._CogdoGameRepeat = config.GetBool('cogdo-game-repeat', 0)
        self.currentFloor = -1
        self.elevatorName = self.__uniqueName('elevator')
        self.floorModel = None
        self.elevatorOutOpen = 0
        self.BottomFloor_SuitPositions = [
            Point3(0, 15, 0),
            Point3(10, 20, 0),
            Point3(-7, 24, 0),
            Point3(-10, 0, 0)
        ]

        self.BottomFloor_SuitHs = [75, 170, -91, -44]

        self.Cubicle_SuitPositions = [
            Point3(0, 18, 0),
            Point3(10, 12, 0),
            Point3(-9, 11, 0),
            Point3(-3, 13, 0)
        ]

        self.Cubicle_SuitHs = [170, 56, -52, 10]

        self.BossOffice_SuitPositions = [
            Point3(0, 15, 0),
            Point3(10, 20, 0),
            Point3(-10, 6, 0),
            Point3(-17, 30, 0)
        ]

        self.BossOffice_SuitHs = [170, 120, 12, 38]

        self._wantBarrelRoom = config.GetBool('cogdo-want-barrel-room', 1)
        self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom()
        self.brResults = [[], []]
        self.barrelRoomIntroTrack = None
        self.penthouseOutroTrack = None
        self.penthouseOutroChatDoneTrack = None
        self.penthouseIntroTrack = None
        self.waitMusic = base.loadMusic(
            'phase_7/audio/bgm/encntr_toon_winning_indoor.ogg')
        self.elevatorMusic = base.loadMusic(
            'phase_7/audio/bgm/tt_elevator.ogg')
        self.fsm = ClassicFSM.ClassicFSM('DistributedCogdoInterior', [
            State.State('WaitForAllToonsInside',
                        self.enterWaitForAllToonsInside,
                        self.exitWaitForAllToonsInside, ['Elevator']),
            State.State('Elevator', self.enterElevator, self.exitElevator,
                        ['Game', 'BattleIntro', 'BarrelRoomIntro']),
            State.State('Game', self.enterGame, self.exitGame, [
                'Resting', 'Failed', 'BattleIntro', 'BarrelRoomIntro',
                'Elevator'
            ]),
            State.State('BarrelRoomIntro', self.enterBarrelRoomIntro,
                        self.exitBarrelRoomIntro, ['CollectBarrels', 'Off']),
            State.State('CollectBarrels', self.enterCollectBarrels,
                        self.exitCollectBarrels, ['BarrelRoomReward', 'Off']),
            State.State('BarrelRoomReward', self.enterBarrelRoomReward,
                        self.exitBarrelRoomReward,
                        ['Battle', 'ReservesJoining', 'BattleIntro', 'Off']),
            State.State('BattleIntro', self.enterBattleIntro,
                        self.exitBattleIntro,
                        ['Battle', 'ReservesJoining', 'Off']),
            State.State('Battle', self.enterBattle, self.exitBattle,
                        ['Resting', 'Reward', 'ReservesJoining']),
            State.State('ReservesJoining', self.enterReservesJoining,
                        self.exitReservesJoining, ['Battle']),
            State.State('Resting', self.enterResting, self.exitResting,
                        ['Elevator']),
            State.State('Reward', self.enterReward, self.exitReward, ['Off']),
            State.State('Failed', self.enterFailed, self.exitFailed, ['Off']),
            State.State('Off', self.enterOff, self.exitOff,
                        ['Elevator', 'WaitForAllToonsInside', 'Battle'])
        ], 'Off', 'Off')

        self.fsm.enterInitialState()
        self._haveEntranceElevator = StateVar(False)
        self._stashEntranceElevator = StateVar(False)
        self._stashEntranceElevatorFC = FunctionCall(
            self._doStashEntranceElevator, self._haveEntranceElevator,
            self._stashEntranceElevator)
        self._entranceElevCallbacks = []
        self._doEntranceElevCallbacksFC = FunctionCall(
            self._doEntranceElevCallbacks, self._haveEntranceElevator)
        self.cage = None
        self.shopOwnerNpcId = None
        self.shopOwnerNpc = None
        self._movie = None
        self.SOSToonName = None
        self.FOType = None

    def setShopOwnerNpcId(self, npcId):
        self.shopOwnerNpcId = npcId

    def setSOSNpcId(self, npcId):
        self.SOSToonName = NPCToons.getNPCName(npcId)

    def setFOType(self, typeId):
        self.FOType = chr(typeId)

    def getFOType(self):
        return self.FOType

    def __uniqueName(self, name):
        DistributedCogdoInterior.id += 1
        return name + '%d' % DistributedCogdoInterior.id

    def generate(self):
        DistributedObject.DistributedObject.generate(self)
        self.announceGenerateName = self.uniqueName('generate')
        self.accept(self.announceGenerateName, self.handleAnnounceGenerate)
        self.elevatorModelIn = loader.loadModel(
            'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB')
        self.leftDoorIn = self.elevatorModelIn.find('**/left_door')
        self.rightDoorIn = self.elevatorModelIn.find('**/right_door')
        self.elevatorModelOut = loader.loadModel(
            'phase_5/models/cogdominium/tt_m_ara_csa_elevator')
        self.leftDoorOut = self.elevatorModelOut.find('**/left_door')
        self.rightDoorOut = self.elevatorModelOut.find('**/right_door')

    def __makeShopOwnerNpc(self):
        if self.shopOwnerNpc:
            return

        self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId)
        if not self.shopOwnerNpc:
            self.notify.warning(
                'No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons'
            )
            random.seed(self.doId)
            shopkeeper = random.randint(7001, 7009)
            self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper)

        self.shopOwnerNpc.addActive()
        self.shopOwnerNpc.reparentTo(self.cage)
        self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0)
        self.shopOwnerNpc.loop('neutral')

    def setElevatorLights(self, elevatorModel):
        npc = elevatorModel.findAllMatches('**/floor_light_?;+s')
        for i in xrange(npc.getNumPaths()):
            np = npc.getPath(i)
            np.setDepthOffset(120)
            floor = int(np.getName()[-1:]) - 1
            if floor == self.currentFloor:
                np.setColor(LIGHT_ON_COLOR)
            elif floor < self.layout.getNumGameFloors() + (
                    1 if self.FOType != "s" else 0):
                if self.isBossFloor(self.currentFloor):
                    np.setColor(LIGHT_ON_COLOR)
                else:
                    np.setColor(LIGHT_OFF_COLOR)
            else:
                np.hide()

    def startAlertElevatorLightIval(self, elevatorModel):
        light = elevatorModel.find('**/floor_light_%s' %
                                   (self.currentFloor + 1))
        track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)),
                         Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR),
                         Wait(0.9))
        self.activeIntervals['alertElevatorLight'] = track
        track.loop()

    def stopAlertElevatorLightIval(self, elevatorModel):
        self.__finishInterval('alertElevatorLight')
        self.setElevatorLights(elevatorModel)

    def handleAnnounceGenerate(self, obj):
        self.ignore(self.announceGenerateName)
        self.cageDoorSfx = loader.loadSfx(
            'phase_5/audio/sfx/CHQ_SOS_cage_door.ogg')
        self.cageLowerSfx = loader.loadSfx(
            'phase_5/audio/sfx/CHQ_SOS_cage_lower.ogg')
        self.sendUpdate('setAvatarJoined', [])

    def disable(self):
        self.fsm.requestFinalState()
        self.__cleanupIntervals()
        self.ignoreAll()
        self.__cleanup()
        self.__cleanupShopOwnerNpc()
        self.__cleanupPenthouseIntro()
        DistributedObject.DistributedObject.disable(self)

    def __cleanupShopOwnerNpc(self):
        if self.shopOwnerNpc:
            self.shopOwnerNpc.removeActive()
            self.shopOwnerNpc.delete()
            self.shopOwnerNpc = None

    def __cleanupPenthouseIntro(self):
        if hasattr(self, '_movie') and self._movie:
            self._movie.unload()
            self._movie = None

    def delete(self):
        self._stashEntranceElevatorFC.destroy()
        self._doEntranceElevCallbacksFC.destroy()
        self._haveEntranceElevator.destroy()
        self._stashEntranceElevator.destroy()
        self._entranceElevCallbacks = None
        del self.waitMusic
        del self.elevatorMusic
        del self.openSfx
        del self.closeSfx
        del self.fsm
        base.localAvatar.inventory.setBattleCreditMultiplier(1)
        DistributedObject.DistributedObject.delete(self)

    def isBossFloor(self, floorNum):
        if not self.layout.hasBossBattle():
            return False

        return (self.layout.getBossBattleFloor() + 0) == floorNum

    def __cleanup(self):
        self.toons = []
        self.suits = []
        self.reserveSuits = []
        self.joiningReserves = []
        if self.elevatorModelIn != None:
            self.elevatorModelIn.removeNode()

        if self.elevatorModelOut != None:
            self.elevatorModelOut.removeNode()

        if self.floorModel != None:
            self.floorModel.removeNode()

        if self.cage != None:
            self.cage = None

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

        self.leftDoorIn = None
        self.rightDoorIn = None
        self.leftDoorOut = None
        self.rightDoorOut = None

    def __addToon(self, toon):
        self.accept(toon.uniqueName('disable'),
                    self.__handleUnexpectedExit,
                    extraArgs=[toon])

    def __handleUnexpectedExit(self, toon):
        self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId)
        self.__removeToon(toon, unexpected=1)

    def __removeToon(self, toon, unexpected=0):
        if self.toons.count(toon) == 1:
            self.toons.remove(toon)
        self.ignore(toon.uniqueName('disable'))

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

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

        self.activeIntervals = {}

    def __closeInElevator(self):
        self.leftDoorIn.setPos(3.5, 0, 0)
        self.rightDoorIn.setPos(-3.5, 0, 0)

    def getZoneId(self):
        return self.zoneId

    def setZoneId(self, zoneId):
        self.zoneId = zoneId

    def getExtZoneId(self):
        return self.extZoneId

    def setExtZoneId(self, extZoneId):
        self.extZoneId = extZoneId

    def getDistBldgDoId(self):
        return self.distBldgDoId

    def setDistBldgDoId(self, distBldgDoId):
        self.distBldgDoId = distBldgDoId

    def setNumFloors(self, numFloors):
        self.layout = CogdoLayout(numFloors)

    def getToonIds(self):
        toonIds = []
        for toon in self.toons:
            toonIds.append(toon.doId)

        return toonIds

    def setToons(self, toonIds, hack):
        self.toonIds = toonIds
        oldtoons = self.toons
        self.toons = []
        for toonId in toonIds:
            if toonId != 0:
                if toonId in self.cr.doId2do:
                    toon = self.cr.doId2do[toonId]
                    toon.stopSmooth()
                    self.toons.append(toon)
                    if not oldtoons.count(toon):
                        self.__addToon(toon)
                else:
                    self.notify.warning('setToons() - no toon: %d' % toonId)

        for toon in oldtoons:
            if not self.toons.count(toon):
                self.__removeToon(toon)

    def setSuits(self, suitIds, reserveIds, values):
        oldsuits = self.suits
        self.suits = []
        self.joiningReserves = []
        for suitId in suitIds:
            if suitId in self.cr.doId2do:
                suit = self.cr.doId2do[suitId]
                self.suits.append(suit)
                suit.fsm.request('Battle')
                suit.buildingSuit = 1
                suit.reparentTo(render)
                if not oldsuits.count(suit):
                    self.joiningReserves.append(suit)

                if 'Elevator' in repr(self.fsm):
                    pos, h = BattleBase.BattleBase.suitPoints[
                        len(suitIds) - 1][suitIds.index(suitId)]
                    suit.setPos(pos)
                    suit.setH(h)
            else:
                self.notify.warning('setSuits() - no suit: %d' % suitId)

        self.reserveSuits = []
        for index in xrange(len(reserveIds)):
            suitId = reserveIds[index]
            if suitId in self.cr.doId2do:
                suit = self.cr.doId2do[suitId]
                self.reserveSuits.append((suit, values[index]))
            else:
                self.notify.warning('setSuits() - no suit: %d' % suitId)

        if len(self.joiningReserves) > 0:
            self.fsm.request('ReservesJoining')

    def setState(self, state, timestamp):
        self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])

    def stashElevatorIn(self, stash=True):
        self._stashEntranceElevator.set(stash)

    def getEntranceElevator(self, callback):
        if self._haveEntranceElevator.get():
            callback(self.elevIn)
        else:
            self._entranceElevCallbacks.append(callback)

    def _doEntranceElevCallbacks(self, haveElev):
        if haveElev:
            while len(self._entranceElevCallbacks):
                cbs = self._entranceElevCallbacks[:]
                self._entranceElevCallbacks = []
                for callback in cbs:
                    callback(self.elevIn)

    def _doStashEntranceElevator(self, haveElev, doStash):
        if haveElev:
            if doStash:
                self.elevIn.stash()
            else:
                self.elevIn.unstash()

    def d_elevatorDone(self):
        self.sendUpdate('elevatorDone', [])

    def d_reserveJoinDone(self):
        self.sendUpdate('reserveJoinDone', [])

    def enterOff(self, ts=0):
        messenger.send('sellbotFieldOfficeChanged', [False])

    def exitOff(self):
        pass

    def enterWaitForAllToonsInside(self, ts=0):
        base.transitions.fadeOut(0)

    def exitWaitForAllToonsInside(self):
        pass

    def enterGame(self, ts=0):
        base.cr.forbidCheesyEffects(1)

    def exitGame(self):
        base.cr.forbidCheesyEffects(0)

    def __playElevator(self, ts, name, callback):
        SuitHs = []
        SuitPositions = []
        if self.floorModel:
            self.floorModel.removeNode()
            self.floorModel = None

        if self.cage:
            self.cage = None

        if self.currentFloor == 0:
            SuitHs = self.BottomFloor_SuitHs
            SuitPositions = self.BottomFloor_SuitPositions

        if self.isBossFloor(self.currentFloor):
            self.notify.info('__playElevator: currentFloor %s is boss' %
                             self.currentFloor)
            self.barrelRoom.unload()
            if self.FOType:
                penthouseName = SUITE_DICT.get(self.FOType)
                for i in range(4):
                    self.floorModel = loader.loadModel(
                        'phase_5/models/cogdominium/%s' % penthouseName)
            self.cage = self.floorModel.find('**/cage')
            pos = self.cage.getPos()
            self.cagePos = []
            for height in self.cageHeights:
                self.cagePos.append(Point3(pos[0], pos[1], height))
            self.cageDoor = self.floorModel.find('**/cage_door')
            self.cageDoor.wrtReparentTo(self.cage)
            if self.FOType:
                paintingModelName = PAINTING_DICT.get(self.FOType)
                for i in xrange(4):
                    paintingModel = loader.loadModel(
                        'phase_5/models/cogdominium/%s' % paintingModelName)
                    loc = self.floorModel.find('**/loc_painting%d' % (i + 1))
                    paintingModel.reparentTo(loc)
            if not self.floorModel.find('**/trophyCase').isEmpty():
                for i in range(4):
                    goldEmblem = loader.loadModel(
                        'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy.bam'
                    )
                    loc = self.floorModel.find('**/gold_0%d' % (i + 1))
                    goldEmblem.reparentTo(loc)
                for i in range(20):
                    silverEmblem = loader.loadModel(
                        'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam'
                    )
                    loc = self.floorModel.find('**/silver_0%d' % (i + 1))
                    silverEmblem.reparentTo(loc)

            SuitHs = self.BossOffice_SuitHs
            SuitPositions = self.BossOffice_SuitPositions
            self.__makeShopOwnerNpc()
        else:
            if self._wantBarrelRoom:
                self.barrelRoom.load()
                self.barrelRoom.hide()
            SuitHs = self.Cubicle_SuitHs
            SuitPositions = self.Cubicle_SuitPositions

        if self.floorModel:
            self.floorModel.reparentTo(render)
            if self.isBossFloor(self.currentFloor):
                self.notify.info('Load boss_suit_office')
                elevIn = self.floorModel.find(
                    CogdoGameConsts.PenthouseElevatorInPath).copyTo(render)
                elevOut = self.floorModel.find(
                    CogdoGameConsts.PenthouseElevatorOutPath)
                frame = self.elevatorModelOut.find('**/frame')
                if not frame.isEmpty():
                    frame.hide()
                frame = self.elevatorModelIn.find('**/frame')
                if not frame.isEmpty():
                    frame.hide()
                self.elevatorModelOut.reparentTo(elevOut)
                self.elevatorModelOut.setY(0)
            else:
                elevIn = self.floorModel.find('**/elevator-in')
                elevOut = self.floorModel.find('**/elevator-out')
        elif self._wantBarrelRoom and self.barrelRoom.isLoaded(
        ) and self.currentFloor == 2 and self.FOType == 'l':
            elevIn = self.barrelRoom.model.find(
                CogdoBarrelRoomConsts.BarrelRoomElevatorInPath)
            elevOut = self.barrelRoom.model.find(
                CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath)
            y = elevOut.getY(render)
            elevOut = elevOut.copyTo(render)
            elevOut.setY(render, y - 0.75)
        else:
            floorModel = loader.loadModel(
                'phase_7/models/modules/boss_suit_office')
            elevIn = floorModel.find('**/elevator-in').copyTo(render)
            elevOut = floorModel.find('**/elevator-out').copyTo(render)
            floorModel.removeNode()

        self.elevIn = elevIn
        self.elevOut = elevOut
        self._haveEntranceElevator.set(True)
        for index in range(len(self.suits)):
            if not self.suits[index].isEmpty():
                self.suits[index].setPos(SuitPositions[index])
                if len(self.suits) > 2:
                    self.suits[index].setH(SuitHs[index])
                else:
                    self.suits[index].setH(170)
                self.suits[index].loop('neutral')

        for toon in self.toons:
            toon.reparentTo(self.elevatorModelIn)
            index = self.toonIds.index(toon.doId)
            toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1],
                        ElevatorPoints[index][2])
            toon.setHpr(180, 0, 0)
            toon.loop('neutral')

        self.elevatorModelIn.reparentTo(elevIn)
        self.leftDoorIn.setPos(3.5, 0, 0)
        self.rightDoorIn.setPos(-3.5, 0, 0)
        camera.reparentTo(self.elevatorModelIn)
        camera.setH(180)
        camera.setP(0)
        camera.setPos(0, 14, 4)
        base.playMusic(self.elevatorMusic, looping=1, volume=0.8)
        track = Sequence(
            Func(base.transitions.noTransitions),
            ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL),
            ElevatorUtils.getOpenInterval(self,
                                          self.leftDoorIn,
                                          self.rightDoorIn,
                                          self.openSfx,
                                          None,
                                          type=ELEVATOR_NORMAL),
            Func(camera.wrtReparentTo, render))
        for toon in self.toons:
            track.append(Func(toon.wrtReparentTo, render))

        track.append(Func(callback))
        track.start(ts)
        self.activeIntervals[name] = track

    def enterElevator(self, ts=0):
        if not self._CogdoGameRepeat:
            self.currentFloor += 1

        self.cr.playGame.getPlace().currentFloor = self.currentFloor
        self.setElevatorLights(self.elevatorModelIn)
        self.setElevatorLights(self.elevatorModelOut)
        if not self.isBossFloor(self.currentFloor):
            self.elevatorModelOut.detachNode()
            messenger.send('sellbotFieldOfficeChanged', [True])
        else:
            if self.FOType == 's':
                self._movie = CogdoElevatorMovie()
                self._movie.load()
                self._movie.play()

        self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone)
        mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor)
        base.localAvatar.inventory.setBattleCreditMultiplier(mult)

    def __handleElevatorDone(self):
        self.d_elevatorDone()

    def exitElevator(self):
        self.elevatorMusic.stop()
        if self._movie:
            self._movie.end()
            self.__cleanupPenthouseIntro()

        self.__finishInterval(self.elevatorName)

    def __setupBarrelRoom(self):
        self.currentFloor += 1
        base.transitions.irisOut(0.0)
        self.elevatorModelOut.setY(-12)
        self.elevatorModelIn.reparentTo(
            self.barrelRoom.model.find(
                CogdoBarrelRoomConsts.BarrelRoomElevatorInPath))
        self.leftDoorIn.setPos(3.5, 0, 0)
        self.rightDoorIn.setPos(-3.5, 0, 0)
        self._showExitElevator()
        self.barrelRoom.show()
        self.barrelRoom.placeToonsAtEntrance(self.toons)
        self.setElevatorLights(self.elevatorModelOut)

    def barrelRoomIntroDone(self):
        self.sendUpdate('toonBarrelRoomIntroDone', [])

    def enterBarrelRoomIntro(self, ts=0):
        if not self.isBossFloor(self.currentFloor):
            if self._wantBarrelRoom:
                self.__setupBarrelRoom()
                self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval(
                )
                self.barrelRoomIntroDoneEvent = trackName
                self.accept(self.barrelRoomIntroDoneEvent,
                            self.barrelRoomIntroDone)
                self.activeIntervals[trackName] = self.barrelRoomIntroTrack
                self.barrelRoomIntroTrack.start(ts)
                self._movie = CogdoBarrelRoomIntro()
                self._movie.load()
                self._movie.play()
            else:
                self._showExitElevator()

    def exitBarrelRoomIntro(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            self.ignore(self.barrelRoomIntroDoneEvent)
            if self.barrelRoomIntroTrack:
                self.barrelRoomIntroTrack.finish()
                DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack)
                self.barrelRoomIntroTrack = None

    def __handleLocalToonLeftBarrelRoom(self):
        self.notify.info('Local toon teleported out of barrel room.')
        self.sendUpdate('toonLeftBarrelRoom', [])
        self.barrelRoom.deactivate()

    def enterCollectBarrels(self, ts=0):
        if not self.isBossFloor(self.currentFloor):
            if self._wantBarrelRoom:
                self.acceptOnce('localToonLeft',
                                self.__handleLocalToonLeftBarrelRoom)
                self.barrelRoom.activate()
                base.playMusic(self.waitMusic, looping=1, volume=0.7)
                base.localAvatar.questMap.stop()

    def exitCollectBarrels(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            self.ignore('localToonLeft')
            self.barrelRoom.deactivate()
            self.waitMusic.stop()

    def __brRewardDone(self, task=None):
        self.notify.info('Toon finished watching the barrel room reward.')
        self.sendUpdate('toonBarrelRoomRewardDone', [])
        self.fsm.request('Battle')

    def enterBarrelRoomReward(self, ts=0):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            base.cr.playGame.getPlace().fsm.request('stopped')
            self.startAlertElevatorLightIval(self.elevatorModelOut)
            track, trackName = self.barrelRoom.showRewardUi(
                callback=self.__brRewardDone)
            self.activeIntervals[trackName] = track
            track.start()
            self.barrelRoom.placeToonsNearBattle(self.toons)

    def exitBarrelRoomReward(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            base.cr.playGame.getPlace().fsm.request('walk')
            self.stopAlertElevatorLightIval(self.elevatorModelOut)
            self.barrelRoom.hideRewardUi()

    def enterBattleIntro(self, ts=0):
        self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc)
        self._movie.load()
        self._movie.play()

    def exitBattleIntro(self):
        self._movie.end()
        self.__cleanupPenthouseIntro()

    def __playCloseElevatorOut(self, name, delay=0):
        track = Sequence(
            Wait(delay + SUIT_LEAVE_ELEVATOR_TIME),
            Parallel(
                SoundInterval(self.closeSfx),
                LerpPosInterval(
                    self.leftDoorOut,
                    ElevatorData[ELEVATOR_NORMAL]['closeTime'],
                    ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL),
                    startPos=Point3(0, 0, 0),
                    blendType='easeOut'),
                LerpPosInterval(
                    self.rightDoorOut,
                    ElevatorData[ELEVATOR_NORMAL]['closeTime'],
                    ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL),
                    startPos=Point3(0, 0, 0),
                    blendType='easeOut')))
        track.start()
        self.activeIntervals[name] = track

    def enterBattle(self, ts=0):
        if self._wantBarrelRoom and self.elevatorOutOpen == 1:
            self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'),
                                        delay=2)
            camera.setPos(0, -15, 6)
            camera.headsUp(self.elevatorModelOut)

    def _showExitElevator(self):
        self.elevatorModelOut.reparentTo(self.elevOut)
        self.leftDoorOut.setPos(3.5, 0, 0)
        self.rightDoorOut.setPos(-3.5, 0, 0)
        if not self._wantBarrelRoom and self.elevatorOutOpen == 1:
            self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'))
            camera.setPos(0, -15, 6)
            camera.headsUp(self.elevatorModelOut)

    def exitBattle(self):
        if self.elevatorOutOpen == 1:
            self.__finishInterval(self.uniqueName('close-out-elevator'))
            self.elevatorOutOpen = 0

    def __playReservesJoining(self, ts, name, callback):
        index = 0
        for suit in self.joiningReserves:
            suit.reparentTo(render)
            suit.setPos(
                self.elevatorModelOut,
                Point3(ElevatorPoints[index][0], ElevatorPoints[index][1],
                       ElevatorPoints[index][2]))
            index += 1
            suit.setH(180)
            suit.loop('neutral')
        if len(self.suits) == len(self.joiningReserves):
            camSequence = Sequence(Func(camera.wrtReparentTo, localAvatar),
                                   Func(camera.setPos, Point3(0, 5, 5)),
                                   Func(camera.headsUp, self.elevatorModelOut))
        else:
            camSequence = Sequence(
                Func(camera.wrtReparentTo, self.elevatorModelOut),
                Func(camera.setPos, Point3(0, -8, 2)),
                Func(camera.setHpr, Vec3(0, 10, 0)))

        track = Sequence(
            camSequence,
            Parallel(
                SoundInterval(self.openSfx),
                LerpPosInterval(
                    self.leftDoorOut,
                    ElevatorData[ELEVATOR_NORMAL]['closeTime'],
                    Point3(0, 0, 0),
                    startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL),
                    blendType='easeOut'),
                LerpPosInterval(
                    self.rightDoorOut,
                    ElevatorData[ELEVATOR_NORMAL]['closeTime'],
                    Point3(0, 0, 0),
                    startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL),
                    blendType='easeOut')), Wait(SUIT_HOLD_ELEVATOR_TIME),
            Func(camera.wrtReparentTo, render), Func(callback))
        track.start(ts)
        self.activeIntervals[name] = track

    def enterReservesJoining(self, ts=0):
        self.__playReservesJoining(ts, self.uniqueName('reserves-joining'),
                                   self.__handleReserveJoinDone)
        return None

    def __handleReserveJoinDone(self):
        self.joiningReserves = []
        self.elevatorOutOpen = 1
        self.d_reserveJoinDone()

    def exitReservesJoining(self):
        self.__finishInterval(self.uniqueName('reserves-joining'))
        return None

    def enterResting(self, ts=0):
        self._showExitElevator()
        self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit)
        if self._wantBarrelRoom:
            self.barrelRoom.showBattleAreaLight(True)

        base.playMusic(self.waitMusic, looping=1, volume=0.7)
        self.__closeInElevator()
        self._haveEntranceElevator.set(False)
        self._stashEntranceElevator.set(False)

    def _setAvPosToExit(self):
        base.localAvatar.setPos(self.elevOut, 0, -22, 0)
        base.localAvatar.setHpr(self.elevOut, 0, 0, 0)
        base.cr.playGame.getPlace().fsm.request('walk')

    def exitResting(self):
        self._setAvPosFDC.destroy()
        self.waitMusic.stop()

    def enterReward(self, ts=0):
        if self.isBossFloor(self.currentFloor):
            self.penthouseOutroTrack = self.__outroPenthouse()
            self.penthouseOutroTrack.start(ts)
        else:
            self.exitCogdoBuilding()

    def exitReward(self):
        self.notify.debug('exitReward')
        if self.penthouseOutroTrack:
            self.penthouseOutroTrack.finish()
            DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack)
            self.penthouseOutroTrack = None
            if not self.penthouseOutroChatDoneTrack:
                self.notify.debug(
                    'exitReward: instanting outroPenthouseChatDone track')
                self.__outroPenthouseChatDone()
            self.penthouseOutroChatDoneTrack.finish()
            self.penthouseOutroChatDoneTrack = None

    def enterFailed(self, ts=0):
        self.exitCogdoBuilding()

    def exitFailed(self):
        self.notify.debug('exitFailed()')
        self.exitCogdoBuilding()

    def exitCogdoBuilding(self):
        if base.localAvatar.hp < 0:
            return

        base.localAvatar.b_setParent(ToontownGlobals.SPHidden)
        request = {
            'loader': ZoneUtil.getBranchLoaderName(self.extZoneId),
            'where': ZoneUtil.getToonWhereName(self.extZoneId),
            'how': 'elevatorIn',
            'hoodId': ZoneUtil.getHoodId(self.extZoneId),
            'zoneId': self.extZoneId,
            'shardId': None,
            'avId': -1,
            'bldgDoId': self.distBldgDoId
        }

        messenger.send('DSIDoneEvent', [request])

    def displayBadges(self):
        numFloors = self.layout.getNumGameFloors()
        if numFloors > 5 or numFloors < 3:
            pass
        else:
            self.notify.warning('Invalid floor number for display badges.')

        for player in xrange(len(self.toons)):
            goldBadge = loader.loadModel(
                'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy')
            goldBadge.setScale(1.2)
            goldNode = render.find('**/gold_0' + str(player + 1))
            goldBadge.reparentTo(goldNode)

            for floor in xrange(numFloors):
                silverBadge = loader.loadModel(
                    'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam')
                silverBadge.setScale(1.2)
                silverNode = render.find('**/silver_0' + str(floor * 4 +
                                                             (player + 1)))
                silverBadge.reparentTo(silverNode)

    def __outroPenthouse(self):
        avatar = base.localAvatar
        trackName = '__outroPenthouse-%d' % avatar.doId
        track = Parallel(name=trackName)
        base.cr.playGame.getPlace().fsm.request('stopped')
        if self.FOType == "l":
            speech = TTLocalizer.CogdoLawbotExecutiveSuiteToonThankYou
        else:
            speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName

        track.append(
            Sequence(
                Func(camera.wrtReparentTo, localAvatar),
                Func(camera.setPos, 0, -9, 9),
                Func(camera.lookAt, Point3(5, 15, 0)),
                Parallel(
                    self.cage.posInterval(0.75,
                                          self.cagePos[1],
                                          blendType='easeOut'),
                    SoundInterval(self.cageLowerSfx, duration=0.5)),
                Parallel(
                    self.cageDoor.hprInterval(0.5,
                                              VBase3(0, 90, 0),
                                              blendType='easeOut'),
                    Sequence(SoundInterval(self.cageDoorSfx), duration=0)),
                Wait(0.25), Func(self.shopOwnerNpc.wrtReparentTo, render),
                Func(self.shopOwnerNpc.setScale, 1),
                Func(self.shopOwnerNpc.loop, 'walk'),
                Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)),
                ParallelEndTogether(
                    self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)),
                    self.shopOwnerNpc.hprInterval(0.5,
                                                  VBase3(180, 0, 0),
                                                  blendType='easeInOut')),
                Func(self.shopOwnerNpc.setChatAbsolute,
                     TTLocalizer.CagedToonYippee, CFSpeech),
                ActorInterval(self.shopOwnerNpc, 'jump'),
                Func(self.shopOwnerNpc.loop, 'neutral'),
                Func(self.shopOwnerNpc.headsUp, localAvatar),
                Func(self.shopOwnerNpc.setLocalPageChat, speech, 0),
                Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2))))
        self.activeIntervals[trackName] = track
        self.accept('doneChatPage', self.__outroPenthouseChatDone)
        return track

    def __outroPenthouseChatDone(self, elapsed=None):
        self.shopOwnerNpc.setChatAbsolute(
            TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech)
        self.ignore('doneChatPage')
        track = Parallel(
            Sequence(ActorInterval(self.shopOwnerNpc, 'wave'),
                     Func(self.shopOwnerNpc.loop, 'neutral')),
            Sequence(Wait(2.0), Func(self.exitCogdoBuilding),
                     Func(base.camLens.setFov, settings['fieldofview'])))
        track.start()
        self.penthouseOutroChatDoneTrack = track
コード例 #8
0
class FrameProfiler:
    notify = directNotify.newCategory('FrameProfiler')
    Minute = 60
    Hour = 60 * Minute
    Day = 24 * Hour
    
    def __init__(self):
        Hour = FrameProfiler.Hour
        self._period = 2 * FrameProfiler.Minute
        if config.GetBool('frequent-frame-profiles', 0):
            self._period = 1 * FrameProfiler.Minute
        
        self._jitterMagnitude = self._period * 0.75
        self._logSchedule = [
            1 * FrameProfiler.Hour,
            4 * FrameProfiler.Hour,
            12 * FrameProfiler.Hour,
            1 * FrameProfiler.Day]
        if config.GetBool('frequent-frame-profiles', 0):
            self._logSchedule = [
                1 * FrameProfiler.Minute,
                4 * FrameProfiler.Minute,
                12 * FrameProfiler.Minute,
                24 * FrameProfiler.Minute]
        
        for t in self._logSchedule:
            pass
        
        for i in xrange(len(self._logSchedule)):
            e = self._logSchedule[i]
            for j in xrange(i, len(self._logSchedule)):
                pass
            
        
        self._enableFC = FunctionCall(self._setEnabled, taskMgr.getProfileFramesSV())
        self._enableFC.pushCurrentState()

    
    def destroy(self):
        self._enableFC.set(False)
        self._enableFC.destroy()

    
    def _setEnabled(self, enabled):
        if enabled:
            self.notify.info('frame profiler started')
            self._startTime = globalClock.getFrameTime()
            self._profileCounter = 0
            self._jitter = None
            self._period2aggregateProfile = { }
            self._id2session = { }
            self._id2task = { }
            self._task = taskMgr.doMethodLater(self._period, self._scheduleNextProfileDoLater, 'FrameProfilerStart-%s' % serialNum())
        else:
            self._task.remove()
            del self._task
            for session in self._period2aggregateProfile.itervalues:
                session.release()
            
            del self._period2aggregateProfile
            for task in self._id2task.itervalues():
                task.remove()
            
            del self._id2task
            for session in self._id2session.itervalues():
                session.release()
            
            del self._id2session
            self.notify.info('frame profiler stopped')

    
    def _scheduleNextProfileDoLater(self, task):
        self._scheduleNextProfile()
        return task.done

    
    def _scheduleNextProfile(self):
        self._profileCounter += 1
        self._timeElapsed = self._profileCounter * self._period
        time = self._startTime + self._timeElapsed
        jitter = self._jitter
        if jitter is None:
            jitter = normalDistrib(-(self._jitterMagnitude), self._jitterMagnitude)
            time += jitter
        else:
            time -= jitter
            jitter = None
        self._jitter = jitter
        sessionId = serialNum()
        session = taskMgr.getProfileSession('FrameProfile-%s' % sessionId)
        self._id2session[sessionId] = session
        taskMgr.profileFrames(num = 1, session = session, callback = Functor(self._analyzeResults, sessionId))
        delay = max(time - globalClock.getFrameTime(), 0.0)
        self._task = taskMgr.doMethodLater(delay, self._scheduleNextProfileDoLater, 'FrameProfiler-%s' % serialNum())

    
    def _analyzeResults(self, sessionId):
        self._id2task[sessionId] = taskMgr.add(Functor(self._doAnalysis, sessionId), 'FrameProfilerAnalysis-%s' % sessionId)

    
    def _doAnalysis(self, sessionId, task):
        if hasattr(task, '_generator'):
            gen = task._generator
        else:
            gen = self._doAnalysisGen(sessionId)
            task._generator = gen
        result = gen.next()
        if result == Task.done:
            del task._generator
        
        return result

    
    def _doAnalysisGen(self, sessionId):
        p2ap = self._period2aggregateProfile
        self._id2task.pop(sessionId)
        session = self._id2session.pop(sessionId)
        if session.profileSucceeded():
            period = self._logSchedule[0]
            if period not in self._period2aggregateProfile:
                p2ap[period] = session.getReference()
            else:
                p2ap[period].aggregate(session)
        else:
            self.notify.warning('frame profile did not succeed')
        session.release()
        session = None
        counter = 0
        for pi in xrange(len(self._logSchedule)):
            period = self._logSchedule[pi]
            if self._timeElapsed % period == 0:
                if period in p2ap:
                    if counter >= 3:
                        counter = 0
                        yield Task.cont
                    
                    self.notify.info('aggregate profile of sampled frames over last %s\n%s' % (formatTimeExact(period), p2ap[period].getResults()))
                    counter += 1
                    nextIndex = pi + 1
                    if nextIndex >= len(self._logSchedule):
                        nextPeriod = period * 2
                        self._logSchedule.append(nextPeriod)
                    else:
                        nextPeriod = self._logSchedule[nextIndex]
                    if nextPeriod not in p2ap:
                        p2ap[nextPeriod] = p2ap[period].getReference()
                    else:
                        p2ap[nextPeriod].aggregate(p2ap[period])
                    p2ap[period].release()
                    del p2ap[period]
                
            period in p2ap
            break
        
        yield Task.done
コード例 #9
0
class DistributedPartyTugOfWarActivity(DistributedPartyTeamActivity):

    notify = directNotify.newCategory("DistributedPartyTugOfWarActivity")

    def __init__(self, cr):
        """
        cr: instance of ClientRepository
        """
        DistributedPartyTeamActivity.__init__(
            self,
            cr,
            PartyGlobals.ActivityIds.PartyTugOfWar,
            startDelay=PartyGlobals.TugOfWarStartDelay)
        assert (self.notify.debug("__init__"))

        # these are the indices of the active buttons
        self.buttons = [0, 1]

        # these variables are used for calculation how fast the player is pressing the keys
        self.arrowKeys = None
        self.keyTTL = []
        self.idealRate = 0.0
        self.keyRate = 0
        self.allOutMode = False
        self.rateMatchAward = 0.0  # bonus for consistently hitting the ideal rate

        self.toonIdsToStartPositions = {}  # initial positions of toons
        self.toonIdsToIsPullingFlags = {}  # whether or not a toon is pulling
        self.toonIdsToRightHands = {}  # used for setting up ropes
        self.fallenToons = []  # toons in the water
        self.fallenPositions = []
        self.unusedFallenPositionsIndices = [0, 1, 2, 3]
        self.toonIdsToAnimIntervals = {}
        self.tugRopes = []

    def generate(self):
        DistributedPartyTeamActivity.generate(self)
        assert (self.notify.debug("generate"))

        self._hopOffFinishedSV = StateVar(True)
        self._rewardFinishedSV = StateVar(True)
        self._isWalkStateReadyFC = FunctionCall(self._testWalkStateReady,
                                                self._hopOffFinishedSV,
                                                self._rewardFinishedSV)

    def delete(self):
        self._isWalkStateReadyFC.destroy()
        self._hopOffFinishedSV.destroy()
        self._rewardFinishedSV.destroy()

        DistributedPartyTeamActivity.delete(self)

    def handleToonJoined(self, toonId):
        DistributedPartyTeamActivity.handleToonJoined(self, toonId)

        self.toonIdsToAnimIntervals[toonId] = None

        if toonId == base.localAvatar.doId:
            base.cr.playGame.getPlace().fsm.request("activity")

            # set camera to a 3rd person view of play area
            camera.wrtReparentTo(self.root)
            self.cameraMoveIval = LerpPosHprInterval(
                camera,
                1.5,
                PartyGlobals.TugOfWarCameraPos,
                PartyGlobals.TugOfWarCameraInitialHpr,
                other=self.root,
            )
            self.cameraMoveIval.start()

            self.localToonPosIndex = self.getIndex(base.localAvatar.doId,
                                                   self.localToonTeam)
            self.notify.debug("posIndex: %d" % self.localToonPosIndex)

            toon = self.getAvatar(toonId)
            targetPos = self.dockPositions[self.localToonTeam][
                self.localToonPosIndex]
            # prevent toons from clipping through the dock by warping them to dock height
            if toon.getZ(self.root) < PartyGlobals.TugOfWarToonPositionZ:
                toon.setZ(self.root, PartyGlobals.TugOfWarToonPositionZ)
            targetH = fitDestAngle2Src(
                toon.getH(self.root),
                PartyGlobals.TugOfWarHeadings[self.localToonTeam])
            travelVector = targetPos - toon.getPos(self.root)
            duration = travelVector.length() / 5.0
            if self.toonIdsToAnimIntervals[toonId] is not None:
                self.toonIdsToAnimIntervals[toonId].finish()
            self.toonIdsToAnimIntervals[toonId] = Sequence(
                Func(toon.startPosHprBroadcast, 0.1),
                Func(toon.b_setAnimState, "run"),
                LerpPosHprInterval(toon,
                                   duration,
                                   targetPos,
                                   VBase3(targetH, 0.0, 0.0),
                                   other=self.root),
                Func(toon.stopPosHprBroadcast),
                Func(toon.b_setAnimState, "neutral"),
            )
            self.toonIdsToAnimIntervals[toonId].start()

    def handleToonExited(self, toonId):
        DistributedPartyTeamActivity.handleToonExited(self, toonId)

        # clean up local toon stuff
        if toonId == base.localAvatar.doId:
            self.cameraMoveIval.pause()

            # make toon jump off the dock if needed
            if toonId not in self.fallenToons:
                # finish any existing interval for that toon
                if toonId in self.toonIdsToAnimIntervals and \
                   self.toonIdsToAnimIntervals[toonId] is not None:
                    self.toonIdsToAnimIntervals[toonId].finish()
                toon = self.getAvatar(toonId)
                # clamp targetHeading to minimize spin
                targetH = fitDestAngle2Src(toon.getH(self.root), 180.0)
                targetPos = self.hopOffPositions[self.getTeam(toonId)][
                    self.getIndex(toonId, self.getTeam(toonId))]
                hopOffAnim = Sequence(
                    Func(toon.startPosHprBroadcast, 0.1),
                    toon.hprInterval(0.2,
                                     VBase3(targetH, 0.0, 0.0),
                                     other=self.root),
                    Func(toon.b_setAnimState, "jump", 1.0),
                    Wait(0.4),
                    PartyUtils.arcPosInterval(0.75, toon, targetPos, 5.0,
                                              self.root),
                    Func(toon.stopPosHprBroadcast),
                    # make sure toon ends up on the ground on remote clients
                    Func(toon.sendCurrentPosition),
                    Func(self.hopOffFinished, toonId),
                )
                self.toonIdsToAnimIntervals[toonId] = hopOffAnim
                self._hopOffFinishedSV.set(False)
                self.toonIdsToAnimIntervals[toonId].start()
            # local toons not on the dock are put back into the walk state
            else:
                self._hopOffFinishedSV.set(True)
                del self.toonIdsToAnimIntervals[toonId]

    def handleRewardDone(self):
        # don't call down, it puts the toon in a bad state because it interferes with
        # the 'hopOffAnim'
        self._rewardFinishedSV.set(True)

    def _testWalkStateReady(self, hoppedOff, rewardFinished):
        assert (self.notify.debug("_testWalkStateReady %d %d" %
                                  (hoppedOff, rewardFinished)))

        if hoppedOff and rewardFinished:
            DistributedPartyTeamActivity.handleRewardDone(self)

    def hopOffFinished(self, toonId):
        assert (self.notify.debug("hopOffFinished( toonId=%d )" % toonId))

        if hasattr(self,"toonIdsToAnimIntervals") and \
           toonId in self.toonIdsToAnimIntervals:
            del self.toonIdsToAnimIntervals[toonId]  # clean up anim dictionary

        if toonId == base.localAvatar.doId:
            if hasattr(self._hopOffFinishedSV, '_value'):
                self._hopOffFinishedSV.set(True)

    def handleToonShifted(self, toonId):
        assert (self.notify.debug("handleToonShifted( toonId=%d )" % toonId))

        if toonId == base.localAvatar.doId:
            # update local toon's position on the dock if they got shifted
            self.localToonPosIndex = self.getIndex(base.localAvatar.doId,
                                                   self.localToonTeam)
            if self.toonIdsToAnimIntervals[toonId] is not None:
                self.toonIdsToAnimIntervals[toonId].finish()
            toon = self.getAvatar(toonId)
            targetPos = self.dockPositions[self.localToonTeam][
                self.localToonPosIndex]
            self.toonIdsToAnimIntervals[toonId] = Sequence(
                Wait(0.6),  # give leaving toon time to jump off dock
                Func(toon.startPosHprBroadcast, 0.1),
                Func(toon.b_setAnimState, "run"),
                toon.posInterval(0.5, targetPos, other=self.root),
                Func(toon.stopPosHprBroadcast),
                Func(toon.b_setAnimState, "neutral"),
            )
            self.toonIdsToAnimIntervals[toonId].start()

    def handleToonDisabled(self, toonId):
        """
        A toon dropped unexpectedly from the game. Handle it!
        """
        assert (self.notify.debug("handleToonDisabled( toonId:%d )" % toonId))

        if self.toonIdsToAnimIntervals.has_key(toonId):
            if self.toonIdsToAnimIntervals[toonId]:
                if self.toonIdsToAnimIntervals[toonId].isPlaying():
                    self.toonIdsToAnimIntervals[toonId].finish()
            else:
                self.notify.debug("self.toonIdsToAnimIntervals[%d] is none" %
                                  toonId)

    def setToonsPlaying(self, leftTeamToonIds, rightTeamToonIds):
        """Overrides DistributedPartyActivity's setToonsPlaying"""
        DistributedPartyTeamActivity.setToonsPlaying(self, leftTeamToonIds,
                                                     rightTeamToonIds)

        # update table of right hands
        self.toonIdsToRightHands.clear()
        for toonId in self.getToonIdsAsList():
            toon = self.getAvatar(toonId)
            if toon:
                self.toonIdsToRightHands[toonId] = toon.getRightHands()[0]

    def load(self):
        """
        Load the necessary assets
        """
        DistributedPartyTeamActivity.load(self)

        assert (self.notify.debug("load"))

        self.loadModels()
        self.loadGuiElements()
        self.loadSounds()
        self.loadIntervals()
        self.arrowKeys = ArrowKeys()

    def loadModels(self):
        # load the tug of war play area
        self.playArea = loader.loadModel(
            "phase_13/models/parties/partyTugOfWar")
        # reparent to the party ground root
        self.playArea.reparentTo(self.root)

        # place the activity sign
        self.sign.reparentTo(self.playArea.find("**/TugOfWar_sign_locator"))

        # define initial positions, with index 0 being closest to the other team
        self.dockPositions = [
            [],  # left team positions
            [],  # right team positions
        ]
        for i in range(4):
            self.dockPositions[0].append(
                Point3(
                    -PartyGlobals.TugOfWarInitialToonPositionsXOffset -
                    PartyGlobals.TugOfWarToonPositionXSeparation * i,
                    0.0,
                    PartyGlobals.TugOfWarToonPositionZ,
                ))
        for i in range(4):
            self.dockPositions[1].append(
                Point3(
                    PartyGlobals.TugOfWarInitialToonPositionsXOffset +
                    PartyGlobals.TugOfWarToonPositionXSeparation * i,
                    0.0,
                    PartyGlobals.TugOfWarToonPositionZ,
                ))
        self.hopOffPositions = [
            [],  # left team positions
            [],  # right team positions
        ]
        for i in range(1, 5):
            self.hopOffPositions[
                PartyGlobals.TeamActivityTeams.LeftTeam].append(
                    self.playArea.find("**/leftTeamHopOff%d_locator" %
                                       i).getPos())
            self.hopOffPositions[
                PartyGlobals.TeamActivityTeams.RightTeam].append(
                    self.playArea.find("**/rightTeamHopOff%d_locator" %
                                       i).getPos())

        # load positions for when toons fall into the water
        for i in range(1, 5):
            pos = self.playArea.find("**/fallenToon%d_locator" % i).getPos()
            self.fallenPositions.append(pos)

        # load collision that allows toons to play the game
        # create one for each dock that lets toons join a particular team
        self.joinCollision = []
        self.joinCollisionNodePaths = []
        for i in range(len(PartyGlobals.TeamActivityTeams)):
            collShape = CollisionTube(
                PartyGlobals.TugOfWarJoinCollisionEndPoints[0],
                PartyGlobals.TugOfWarJoinCollisionEndPoints[1],
                PartyGlobals.TugOfWarJoinCollisionRadius)
            collShape.setTangible(True)

            self.joinCollision.append(
                CollisionNode("TugOfWarJoinCollision%d" % i))
            self.joinCollision[i].addSolid(collShape)
            tubeNp = self.playArea.attachNewNode(self.joinCollision[i])
            tubeNp.node().setCollideMask(ToontownGlobals.WallBitmask)
            self.joinCollisionNodePaths.append(tubeNp)
            self.joinCollisionNodePaths[i].setPos(
                PartyGlobals.TugOfWarJoinCollisionPositions[i])
        self.__enableCollisions()

        # Get the rope texture by extracting it from its model.
        ropeModel = loader.loadModel(
            "phase_4/models/minigames/tug_of_war_rope")
        self.ropeTexture = ropeModel.findTexture("*")
        ropeModel.removeNode()

        # create as many ropes as we will ever need
        for i in range(PartyGlobals.TugOfWarMaximumPlayersPerTeam * 2 - 1):
            rope = Rope(self.uniqueName("TugRope%d" % i))
            if rope.showRope:
                rope.ropeNode.setRenderMode(RopeNode.RMBillboard)
                rope.ropeNode.setThickness(0.2)
                rope.setTexture(self.ropeTexture)
                rope.ropeNode.setUvMode(RopeNode.UVDistance)
                rope.ropeNode.setUvDirection(1)
                rope.setTransparency(1)
                rope.setColor(0.89, 0.89, 0.6, 1.0)
                rope.reparentTo(self.root)
                rope.stash()
            self.tugRopes.append(rope)

        # Splash object for when toon hits the water
        self.splash = Splash.Splash(self.root)
        self.splash.setScale(2.0, 4.0, 1.0)
        pos = self.fallenPositions[0]
        self.splash.setPos(pos[0], pos[1], PartyGlobals.TugOfWarSplashZOffset)
        self.splash.hide()

    def loadGuiElements(self):
        # load gui power meter
        self.powerMeter = MinigamePowerMeter(
            PartyGlobals.TugOfWarPowerMeterSize)
        self.powerMeter.reparentTo(aspect2d)
        self.powerMeter.setPos(0.0, 0.0, 0.6)
        self.powerMeter.hide()

        # Load the arrows for button indicator
        self.arrows = [None] * 2
        for x in range(len(self.arrows)):
            self.arrows[x] = loader.loadModel('phase_3/models/props/arrow')
            self.arrows[x].reparentTo(self.powerMeter)
            self.arrows[x].setScale(.2 - .4 * x, .2, .2)
            self.arrows[x].setPos(.12 - .24 * x, 0, -.26)

    def loadSounds(self):
        self.splashSound = base.loadSfx(
            "phase_4/audio/sfx/MG_cannon_splash.mp3")
        self.whistleSound = base.loadSfx(
            "phase_4/audio/sfx/AA_sound_whistle.mp3")

    def loadIntervals(self):
        # create an interval that updates the ideal key press rate for each stage
        self.updateIdealRateInterval = Sequence()
        # other code handles setting the initial ideal rate, so only add the
        # wait for the first state
        self.updateIdealRateInterval.append(
            Wait(PartyGlobals.TugOfWarTargetRateList[0][0]), )
        # for each stage after the first
        for i in range(1, len(PartyGlobals.TugOfWarTargetRateList)):
            duration = PartyGlobals.TugOfWarTargetRateList[i][0]
            idealRate = PartyGlobals.TugOfWarTargetRateList[i][1]
            # set ideal speed
            self.updateIdealRateInterval.append(
                Func(self.setIdealRate, idealRate))
            # add delay for stage's length or set last stage flag
            if i == (len(PartyGlobals.TugOfWarTargetRateList) - 1):
                self.updateIdealRateInterval.append(
                    Func(setattr, self, "allOutMode", True))
            else:
                self.updateIdealRateInterval.append(Wait(duration), )
        # create an interval that updates the local player's key press rate
        self.updateKeyPressRateInterval = Sequence(
            Wait(PartyGlobals.TugOfWarKeyPressUpdateRate),
            Func(self.updateKeyPressRate),
        )
        # create an interval that updates the local player's force and tells the
        # server
        self.reportToServerInterval = Sequence(
            Wait(PartyGlobals.TugOfWarKeyPressReportRate),
            Func(self.reportToServer),
        )

        self.setupInterval = Parallel()
        # run this even if the local toon is not playing
        self.globalSetupInterval = Sequence(
            Wait(PartyGlobals.TugOfWarReadyDuration +
                 PartyGlobals.TugOfWarGoDuration),
            Func(self.tightenRopes),
        )
        # only run this when a local toon is playing
        self.localSetupInterval = Sequence(
            Func(self.setStatus, TTLocalizer.PartyTugOfWarReady),
            Func(self.showStatus),
            Wait(PartyGlobals.TugOfWarReadyDuration),
            Func(base.playSfx, self.whistleSound),
            Func(self.setStatus, TTLocalizer.PartyTugOfWarGo),
            Wait(PartyGlobals.TugOfWarGoDuration),
            Func(self.enableKeys),
            Func(self.hideStatus),
            Func(self.updateIdealRateInterval.start),
            Func(self.updateKeyPressRateInterval.loop),
            Func(self.reportToServerInterval.loop),
        )

        # interval for playing the splash sound and showing the splash visual effect
        self.splashInterval = Sequence(
            Func(base.playSfx, self.splashSound),
            Func(self.splash.play),
        )

    def unload(self):
        DistributedPartyTeamActivity.unload(self)

        self.arrowKeys.destroy()
        self.unloadIntervals()
        self.unloadModels()
        self.unloadGuiElements()
        self.unloadSounds()

        # delete variables
        if hasattr(self, "toonIds"):
            del self.toonIds
        del self.buttons
        del self.arrowKeys
        del self.keyTTL
        del self.idealRate
        del self.keyRate
        del self.allOutMode
        del self.rateMatchAward

        del self.toonIdsToStartPositions
        del self.toonIdsToIsPullingFlags
        del self.toonIdsToRightHands
        del self.fallenToons
        del self.fallenPositions
        del self.unusedFallenPositionsIndices
        self.toonIdsToAnimIntervals.clear()
        del self.toonIdsToAnimIntervals

    def unloadModels(self):
        self.playArea.removeNode()
        del self.playArea

        del self.dockPositions
        del self.hopOffPositions

        self.__disableCollisions()
        while len(self.joinCollision) > 0:
            collNode = self.joinCollision.pop()
            del collNode
        while len(self.joinCollisionNodePaths) > 0:
            collNodePath = self.joinCollisionNodePaths.pop()
            collNodePath.removeNode()
            del collNodePath

        while len(self.tugRopes) > 0:
            rope = self.tugRopes.pop()
            if rope is not None:
                rope.removeNode()
            del rope
        del self.tugRopes

        self.splash.destroy()
        del self.splash

    def unloadGuiElements(self):
        for arrow in self.arrows:
            if arrow is not None:
                arrow.removeNode()
                del arrow
        del self.arrows

        if self.powerMeter is not None:
            self.powerMeter.cleanup()
            del self.powerMeter

    def unloadSounds(self):
        del self.splashSound
        del self.whistleSound

    def unloadIntervals(self):
        self.updateIdealRateInterval.pause()
        del self.updateIdealRateInterval

        self.updateKeyPressRateInterval.pause()
        del self.updateKeyPressRateInterval

        self.reportToServerInterval.pause()
        del self.reportToServerInterval

        self.setupInterval.pause()
        del self.setupInterval

        self.globalSetupInterval.pause()
        del self.globalSetupInterval

        self.localSetupInterval.pause()
        del self.localSetupInterval

        self.splashInterval.pause()
        del self.splashInterval

    def __enableCollisions(self):
        assert (self.notify.debug("__enableCollisions"))

        for i in range(len(PartyGlobals.TeamActivityTeams)):
            self.accept(
                "enterTugOfWarJoinCollision%d" % i,
                getattr(
                    self,
                    "_join%s" % PartyGlobals.TeamActivityTeams.getString(i)))

    def __disableCollisions(self):
        assert (self.notify.debug("__disableCollisions"))

        for i in range(len(PartyGlobals.TeamActivityTeams)):
            self.ignore("enterTugOfWarJoinCollision%d" % i)

    # FSM transition methods
    def startWaitForEnough(self):
        DistributedPartyTeamActivity.startWaitForEnough(self)

        self.__enableCollisions()

    def finishWaitForEnough(self):
        DistributedPartyTeamActivity.finishWaitForEnough(self)

        self.__disableCollisions()

    def startWaitToStart(self, waitStartTimestamp):
        DistributedPartyTeamActivity.startWaitToStart(self, waitStartTimestamp)

        self.__enableCollisions()

    def finishWaitToStart(self):
        DistributedPartyTeamActivity.finishWaitToStart(self)

        self.__disableCollisions()

    def startRules(self):
        DistributedPartyTeamActivity.startRules(self)

        self.setUpRopes()
        # display rules to the local toon if we have one
        if self.isLocalToonPlaying:
            self.showControls()

    def finishRules(self):
        DistributedPartyTeamActivity.finishRules(self)

        # check for a non-standard transition and do additional cleanup as needed
        if self.activityFSM.getCurrentOrNextState() == "WaitForEnough":
            self.hideRopes()
            self.hideControls()

    def finishWaitForServer(self):
        DistributedPartyTeamActivity.finishWaitForServer(self)

        # check for a non-standard transition and do additional cleanup as needed
        if self.activityFSM.getCurrentOrNextState() == "WaitForEnough":
            self.hideRopes()
            self.hideControls()

    def startActive(self):
        DistributedPartyTeamActivity.startActive(self)

        # reset active variables
        self.toonIdsToStartPositions.clear()
        self.toonIdsToIsPullingFlags.clear()

        for toonId in self.getToonIdsAsList():
            self.toonIdsToIsPullingFlags[toonId] = False
            toon = self.getAvatar(toonId)

            if toon:
                self.toonIdsToStartPositions[toonId] = toon.getPos(self.root)
            else:
                # what the heck do we do at this point? lets try 0,0,0
                self.notify.warning(
                    "couldn't find toon %d assigning 0,0,0 to startPos" %
                    toonId)
                self.toonIdsToStartPositions[toonId] = Point3(0, 0, 0)

        self.unusedFallenPositionsIndices = [0, 1, 2, 3]
        self.setupInterval = Parallel(self.globalSetupInterval)

        if self.isLocalToonPlaying:
            self.keyTTL = []
            self.idealForce = 0.0
            self.keyRate = 0
            self.rateMatchAward = 0.0
            self.allOutMode = False
            self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
            self.setupInterval.append(self.localSetupInterval)

        self.setupInterval.start()

    def finishActive(self):
        DistributedPartyTeamActivity.finishActive(self)

        self.hideControls()
        self.disableKeys()
        self.setupInterval.pause()
        self.reportToServerInterval.pause()
        self.updateKeyPressRateInterval.pause()
        self.updateIdealRateInterval.pause()
        self.hideRopes()

    def startConclusion(self, losingTeam):
        DistributedPartyTeamActivity.startConclusion(self, losingTeam)

        if self.isLocalToonPlaying:
            self._rewardFinishedSV.set(False)

            if losingTeam == PartyGlobals.TeamActivityNeitherTeam:
                self.setStatus(TTLocalizer.PartyTeamActivityGameTie)
            else:
                self.setStatus(TTLocalizer.PartyTugOfWarGameEnd)

            self.showStatus()

        if losingTeam == PartyGlobals.TeamActivityNeitherTeam:
            # tie
            for toonId in self.getToonIdsAsList():
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop("neutral")
        else:
            # winning and losing team
            for toonId in self.toonIds[losingTeam]:
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop("neutral")
            for toonId in self.toonIds[1 - losingTeam]:
                if self.getAvatar(toonId):
                    self.getAvatar(toonId).loop("victory")

        for ival in self.toonIdsToAnimIntervals.values():
            if ival is not None:
                ival.finish()

    def finishConclusion(self):
        DistributedPartyTeamActivity.finishConclusion(self)

        self.fallenToons = []

    def getTitle(self):
        return TTLocalizer.PartyTugOfWarTitle

    def getInstructions(self):
        return TTLocalizer.TugOfWarInstructions

    def showControls(self):
        # show the power meter and arrows so player can see them while they
        # read the rules
        for arrow in self.arrows:
            arrow.setColor(PartyGlobals.TugOfWarDisabledArrowColor)
        # set meter to first stage values
        self.powerMeter.setTarget(PartyGlobals.TugOfWarTargetRateList[0][1])
        self.powerMeter.setPower(PartyGlobals.TugOfWarTargetRateList[0][1])
        self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5))
        self.powerMeter.clearTooSlowTooFast()
        self.powerMeter.show()

    def hideControls(self):
        self.powerMeter.hide()

    def setUpRopes(self):
        self.notify.debug("setUpRopes")
        ropeIndex = 0
        # setup rope linking the left team to the right team
        leftToonId = -1
        if self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]:
            leftToonId = self.toonIds[
                PartyGlobals.TeamActivityTeams.LeftTeam][0]
        rightToonId = -1
        if self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]:
            rightToonId = self.toonIds[
                PartyGlobals.TeamActivityTeams.RightTeam][0]
        if leftToonId in self.toonIdsToRightHands and \
           rightToonId in self.toonIdsToRightHands:
            self.tugRopes[ropeIndex].setup(
                3,
                (
                    (self.toonIdsToRightHands[self.toonIds[
                        PartyGlobals.TeamActivityTeams.LeftTeam][0]],
                     (0, 0, 0)),
                    (self.root, (0.0, 0.0, 2.5)),
                    (self.toonIdsToRightHands[self.toonIds[
                        PartyGlobals.TeamActivityTeams.RightTeam][0]],
                     (0, 0, 0)),
                ),
                [0, 0, 0, 1, 1, 1],
            )
            self.tugRopes[ropeIndex].unstash()
            ropeIndex += 1

        # setup ropes linking toons on the left team
        if len(self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam]) > 1:
            for i in range(
                    len(self.toonIds[PartyGlobals.TeamActivityTeams.LeftTeam])
                    - 1, 0, -1):
                self.notify.debug(
                    "Connecting rope between toon %d and toon %d of left team."
                    % (i, i - 1))
                self.tugRopes[ropeIndex].setup(
                    3,
                    (
                        (self.toonIdsToRightHands[self.toonIds[
                            PartyGlobals.TeamActivityTeams.LeftTeam][i]],
                         (0, 0, 0)),
                        (self.toonIdsToRightHands[self.toonIds[
                            PartyGlobals.TeamActivityTeams.LeftTeam][i]],
                         (0, 0, 0)),
                        (self.toonIdsToRightHands[self.toonIds[
                            PartyGlobals.TeamActivityTeams.LeftTeam][i - 1]],
                         (0, 0, 0)),
                    ),
                    [0, 0, 0, 1, 1, 1],
                )
                self.tugRopes[ropeIndex].unstash()
                ropeIndex += 1

        # setup ropes linking toons on the right team
        if len(self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam]) > 1:
            for i in range(
                    len(self.toonIds[PartyGlobals.TeamActivityTeams.RightTeam])
                    - 1):
                self.notify.debug(
                    "Connecting rope between toon %d and toon %d of left team."
                    % (i, i + 1))
                self.tugRopes[ropeIndex].setup(
                    3,
                    (
                        (self.toonIdsToRightHands[self.toonIds[
                            PartyGlobals.TeamActivityTeams.RightTeam][i]],
                         (0, 0, 0)),
                        (self.toonIdsToRightHands[self.toonIds[
                            PartyGlobals.TeamActivityTeams.RightTeam][i]],
                         (0, 0, 0)),
                        (self.toonIdsToRightHands[self.toonIds[
                            PartyGlobals.TeamActivityTeams.RightTeam][i + 1]],
                         (0, 0, 0)),
                    ),
                    [0, 0, 0, 1, 1, 1],
                )
                self.tugRopes[ropeIndex].unstash()
                ropeIndex += 1

    def tightenRopes(self):
        """
        The pulling part has started. Make the rope between the teams taut.
        """
        self.notify.debug("tightenRopes")
        self.tugRopes[0].setup(
            3,
            (
                (self.toonIdsToRightHands[self.toonIds[
                    PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)),
                (self.toonIdsToRightHands[self.toonIds[
                    PartyGlobals.TeamActivityTeams.LeftTeam][0]], (0, 0, 0)),
                (self.toonIdsToRightHands[self.toonIds[
                    PartyGlobals.TeamActivityTeams.RightTeam][0]], (0, 0, 0)),
            ),
            [0, 0, 0, 1, 1, 1],
        )

    def hideRopes(self):
        self.notify.debug("hideRopes")
        for rope in self.tugRopes:
            rope.stash()

    def handleGameTimerExpired(self):
        assert (self.notify.debug("game timer expired"))

        self.disableKeys()  # do not allow any more input

    def setIdealRate(self, idealRate):
        self.notify.debug("setIdealRate( %d )" % idealRate)
        self.idealRate = idealRate
        self.idealForce = self.advantage * (4 + 0.4 * self.idealRate)

    def updateKeyPressRate(self):
        # decrement times to live for each key press entry in keyTTL
        for i in range(len(self.keyTTL)):
            self.keyTTL[i] -= PartyGlobals.TugOfWarKeyPressUpdateRate

        # remove all key presses that have run out of time to live
        # I think this only removes at most 1 item from the list, which is not
        # what we want, but worked for Trolley tug of war so I'm afraid to "fix" it
        for i in range(len(self.keyTTL)):
            if self.keyTTL[i] <= 0.0:
                a = self.keyTTL[0:i]
                del self.keyTTL
                self.keyTTL = a
                break

        self.keyRate = len(self.keyTTL)

        # if the user has matched the idealRate several times in a row, add
        # a little bit to their power
        if self.keyRate == self.idealRate or self.keyRate == self.idealRate + 1:
            self.rateMatchAward += 0.3
        else:
            self.rateMatchAward = 0.0

    def reportToServer(self):
        self.currentForce = self.computeForce(self.keyRate)
        self.sendUpdate("reportKeyRateForce",
                        [self.keyRate, self.currentForce])
        self.setSpeedGauge()
        self.setAnimState(base.localAvatar.doId, self.keyRate)

    def computeForce(self, keyRate):
        # return a force in the range 0-self.idealRate
        F = 0
        # if this is the last stage, make force directly proportional to keyrate
        if self.allOutMode:
            F = 0.75 * keyRate
        # otherwise, make force proportional to how close you are to ideal key rate
        else:
            stdDev = 0.25 * self.idealRate
            F = self.advantage * (
                self.rateMatchAward + 4 + 0.4 * self.idealRate) * math.pow(
                    math.e, -math.pow(keyRate - self.idealRate, 2) /
                    (2.0 * math.pow(stdDev, 2)))
        return F

    def setSpeedGauge(self):
        # update the power meter to show the toon's speed and the target speed
        self.powerMeter.setPower(self.keyRate)
        self.powerMeter.setTarget(self.idealRate)

        # change the color of the power meter to indicate how well the toon is doing
        # the color should be dark if you are doing badly, and green if you are doing well
        if not self.allOutMode:
            # tell the toon if he is pulling too fast or too slow
            self.powerMeter.updateTooSlowTooFast()
            index = float(self.currentForce) / self.idealForce
            bonus = 0.0
            if index > 1.0:
                bonus = max(1.0, index - 1.0)
                index = 1.0
            color = (0, 0.75 * index + 0.25 * bonus, 0.75 * (1 - index), 0.5)
            self.powerMeter.setBarColor(color)
        else:
            self.powerMeter.setBarColor((0.0, 1.0, 0.0, 0.5))

    def updateToonKeyRate(self, toonId, keyRate):
        # since we set the local toon's pulling animation locally, don't do it
        # here
        if toonId != base.localAvatar.doId:
            self.setAnimState(toonId, keyRate)

    def setAnimState(self, toonId, keyRate):
        if self.activityFSM.state != "Active":
            return
        toon = self.getAvatar(toonId)
        if not self.toonIdsToIsPullingFlags.has_key(toonId):
            if self.getTeam(toonId) == None:
                self.notify.warning(
                    "setAnimState called with toonId (%d) that wasn't in self.toonIds"
                    % toonId)
                return
            else:
                self.notify.warning(
                    "setAnimState called with toonId (%d) that was in self.toonIds but not in self.toonIdsToIsPullingFlags. Adding it."
                    % toonId)
                self.toonIdsToIsPullingFlags[toonId] = False

        if keyRate > 0 and not self.toonIdsToIsPullingFlags[toonId]:
            if toon:
                toon.loop('tug-o-war')
            else:
                self.notify.warning(
                    "toon %d is None, skipping toon.loop(tugowar)" % toonId)
            self.toonIdsToIsPullingFlags[toonId] = True
        if keyRate <= 0 and self.toonIdsToIsPullingFlags[toonId]:
            if toon:
                toon.pose('tug-o-war', 3)
                toon.startLookAround()
            else:
                self.notify.warning(
                    "toon %d is None, skipping toon.startLookAround" % toonId)
            self.toonIdsToIsPullingFlags[toonId] = False

    def enableKeys(self):
        self.notify.debug("enableKeys")
        # Change the order of the press handlers because we are only using 2 keys
        self.arrowKeys.setPressHandlers([
            lambda: self.__pressHandler(2),
            lambda: self.__pressHandler(3),
            lambda: self.__pressHandler(1),
            lambda: self.__pressHandler(0),
        ])
        self.arrowKeys.setReleaseHandlers([
            lambda: self.__releaseHandler(2),
            lambda: self.__releaseHandler(3),
            lambda: self.__releaseHandler(1),
            lambda: self.__releaseHandler(0),
        ])
        for arrow in self.arrows:
            arrow.setColor(PartyGlobals.TugOfWarEnabledArrowColor)

    def disableKeys(self):
        self.arrowKeys.setPressHandlers(self.arrowKeys.NULL_HANDLERS)
        self.arrowKeys.setReleaseHandlers(self.arrowKeys.NULL_HANDLERS)

    # callbacks for when the buttons are pressed and released
    def __pressHandler(self, index):
        if index == self.buttons[0]:
            self.arrows[index].setColor(
                PartyGlobals.TugOfWarHilightedArrowColor)
            self.keyTTL.insert(0, PartyGlobals.TugOfWarKeyPressTimeToLive)
            self.buttons.reverse()

    def __releaseHandler(self, index):
        if index in self.buttons:
            self.arrows[index].setColor(PartyGlobals.TugOfWarEnabledArrowColor)

    def updateToonPositions(self, offset):
        # Since the timer expires locally, we may still get a few
        # messages from the AI that were on the wire when we left
        # the play state, just ignore it
        if self.activityFSM.state != "Active":
            return

        # adjust the camera angle
        if self.isLocalToonPlaying:
            camera.lookAt(self.root, offset, 0.0,
                          PartyGlobals.TugOfWarCameraLookAtHeightOffset)

        # this client sets the position of all toons playing
        for toonId in self.getToonIdsAsList():
            if hasattr(self,"fallenToons") and \
               toonId not in self.fallenToons:
                toon = self.getAvatar(toonId)
                if toon is not None:
                    origPos = self.toonIdsToStartPositions[toonId]
                    curPos = toon.getPos(self.root)
                    newPos = Point3(origPos[0] + offset, curPos[1], curPos[2])
                    # finish any existing animation interval
                    if self.toonIdsToAnimIntervals[toonId] != None:
                        if self.toonIdsToAnimIntervals[toonId].isPlaying():
                            self.toonIdsToAnimIntervals[toonId].finish()
                            self.checkIfFallen(toonId)

                    if toonId not in self.fallenToons:
                        self.toonIdsToAnimIntervals[toonId] = Sequence(
                            LerpPosInterval(
                                toon,
                                duration=PartyGlobals.
                                TugOfWarKeyPressReportRate,
                                pos=newPos,
                                other=self.root,
                            ), Func(self.checkIfFallen, toonId))
                        self.toonIdsToAnimIntervals[toonId].start()

    def checkIfFallen(self, toonId):
        # check if toon has fallen
        if hasattr(self,"fallenToons") and \
           toonId not in self.fallenToons:
            toon = self.getAvatar(toonId)
            if toon:
                curPos = toon.getPos(self.root)
                team = self.getTeam(toonId)
                if ((team == PartyGlobals.TeamActivityTeams.LeftTeam
                     and curPos[0] > -2.0)
                        or (team == PartyGlobals.TeamActivityTeams.RightTeam
                            and curPos[0] < 2.0)):
                    # throw all toons from this side in the water
                    losingTeam = self.getTeam(toonId)
                    self.throwTeamInWater(losingTeam)
                    # tell AI that a team fell in the water
                    self.sendUpdate("reportFallIn", [losingTeam])

    def throwTeamInWater(self, losingTeam):
        self.notify.debug("throwTeamInWater( %s )" %
                          PartyGlobals.TeamActivityTeams.getString(losingTeam))
        splashSet = False
        for toonId in self.toonIds[losingTeam]:
            # throw toon in water
            self.fallenToons.append(toonId)
            toon = self.getAvatar(toonId)
            # getting a a crash of popping from empty list
            #fallenPosIndex = self.unusedFallenPositionsIndices.pop(0)
            fallenPosIndex = self.toonIds[losingTeam].index(toonId)
            if (fallenPosIndex < 0) or (fallenPosIndex >= 4):
                fallenPosIndex = 0
            newPos = self.fallenPositions[fallenPosIndex]

            # animate the toons falling into the water
            if self.toonIdsToAnimIntervals[toonId] is not None:
                if self.toonIdsToAnimIntervals[toonId].isPlaying():
                    self.toonIdsToAnimIntervals[toonId].finish()

            # Fall into water
            if toon:
                parallel = Parallel(
                    ActorInterval(actor=toon,
                                  animName='slip-forward',
                                  duration=2.0),
                    LerpPosInterval(toon,
                                    duration=2.0,
                                    pos=newPos,
                                    other=self.root),
                )
            else:
                self.notify.warning("toon %d is none, skipping slip-forward" %
                                    toonId)
                parallel = Parallel()

            # only setup splash for the first toon
            if not splashSet:
                splashSet = True
                parallel.append(self.splashInterval)

            if toon:
                self.toonIdsToAnimIntervals[toonId] = Sequence(
                    parallel,
                    Func(toon.loop, 'neutral'),
                )
            else:
                self.notify.warning(
                    "toon %d is none, skipping toon.loop(neutral)" % toonId)
                self.toonIdsToAnimIntervals[toonId] = parallel
            self.toonIdsToAnimIntervals[toonId].start()

    def setAdvantage(self, advantage):
        DistributedPartyTeamActivity.setAdvantage(self, advantage)

        if self.isLocalToonPlaying:
            self.setIdealRate(PartyGlobals.TugOfWarTargetRateList[0][1])
コード例 #10
0
class DistributedCogdoInterior(DistributedObject.DistributedObject):
    id = 0
    cageHeights = [11.36, 0.01]

    def __init__(self, cr):
        DistributedObject.DistributedObject.__init__(self, cr)
        self.toons = []
        self.activeIntervals = {}
        self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg')
        self.closeSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_close.ogg')
        self.suits = []
        self.reserveSuits = []
        self.joiningReserves = []
        self.distBldgDoId = None
        self._CogdoGameRepeat = config.GetBool('cogdo-game-repeat', 0)
        self.currentFloor = -1
        self.elevatorName = self.__uniqueName('elevator')
        self.floorModel = None
        self.elevatorOutOpen = 0
        self.BottomFloor_SuitPositions = [Point3(0, 15, 0),
         Point3(10, 20, 0),
         Point3(-7, 24, 0),
         Point3(-10, 0, 0)]
        self.BottomFloor_SuitHs = [75,
         170,
         -91,
         -44]
        self.Cubicle_SuitPositions = [Point3(0, 18, 0),
         Point3(10, 12, 0),
         Point3(-9, 11, 0),
         Point3(-3, 13, 0)]
        self.Cubicle_SuitHs = [170,
         56,
         -52,
         10]
        self.BossOffice_SuitPositions = [Point3(0, 15, 0),
         Point3(10, 20, 0),
         Point3(-10, 6, 0),
         Point3(-17, 30, 0)]
        self.BossOffice_SuitHs = [170,
         120,
         12,
         38]
        self._wantBarrelRoom = config.GetBool('cogdo-want-barrel-room', 1)
        self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom()
        self.brResults = [[], []]
        self.barrelRoomIntroTrack = None
        self.penthouseOutroTrack = None
        self.penthouseOutroChatDoneTrack = None
        self.penthouseIntroTrack = None
        self.waitMusic = base.loadMusic('phase_7/audio/bgm/encntr_toon_winning_indoor.ogg')
        self.elevatorMusic = base.loadMusic('phase_7/audio/bgm/tt_elevator.ogg')
        self.fsm = ClassicFSM.ClassicFSM('DistributedCogdoInterior', [State.State('WaitForAllToonsInside', self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside, ['Elevator']),
         State.State('Elevator', self.enterElevator, self.exitElevator, ['Game', 'BattleIntro', 'BarrelRoomIntro']),
         State.State('Game', self.enterGame, self.exitGame, ['Resting', 'Failed', 'BattleIntro', 'BarrelRoomIntro', 'Elevator']),
         State.State('BarrelRoomIntro', self.enterBarrelRoomIntro, self.exitBarrelRoomIntro, ['CollectBarrels', 'Off']),
         State.State('CollectBarrels', self.enterCollectBarrels, self.exitCollectBarrels, ['BarrelRoomReward', 'Off']),
         State.State('BarrelRoomReward', self.enterBarrelRoomReward, self.exitBarrelRoomReward, ['Battle',
          'ReservesJoining',
          'BattleIntro',
          'Off']),
         State.State('BattleIntro', self.enterBattleIntro, self.exitBattleIntro, ['Battle', 'ReservesJoining', 'Off']),
         State.State('Battle', self.enterBattle, self.exitBattle, ['Resting', 'Reward', 'ReservesJoining']),
         State.State('ReservesJoining', self.enterReservesJoining, self.exitReservesJoining, ['Battle']),
         State.State('Resting', self.enterResting, self.exitResting, ['Elevator']),
         State.State('Reward', self.enterReward, self.exitReward, ['Off']),
         State.State('Failed', self.enterFailed, self.exitFailed, ['Off']),
         State.State('Off', self.enterOff, self.exitOff, ['Elevator', 'WaitForAllToonsInside', 'Battle'])], 'Off', 'Off')
        self.fsm.enterInitialState()
        self._haveEntranceElevator = StateVar(False)
        self._stashEntranceElevator = StateVar(False)
        self._stashEntranceElevatorFC = FunctionCall(self._doStashEntranceElevator, self._haveEntranceElevator, self._stashEntranceElevator)
        self._entranceElevCallbacks = []
        self._doEntranceElevCallbacksFC = FunctionCall(self._doEntranceElevCallbacks, self._haveEntranceElevator)
        self.cage = None
        self.shopOwnerNpcId = None
        self.shopOwnerNpc = None
        self._movie = None
        self.SOSToonName = None
        self.FOType = None

    def setShopOwnerNpcId(self, npcId):
        self.shopOwnerNpcId = npcId

    def setSOSNpcId(self, npcId):
        self.SOSToonName = NPCToons.getNPCName(npcId)

    def setFOType(self, typeId):
        self.FOType = chr(typeId)

    def getFOType(self):
        return self.FOType

    def __uniqueName(self, name):
        DistributedCogdoInterior.id += 1
        return name + '%d' % DistributedCogdoInterior.id

    def generate(self):
        DistributedObject.DistributedObject.generate(self)
        self.announceGenerateName = self.uniqueName('generate')
        self.accept(self.announceGenerateName, self.handleAnnounceGenerate)
        self.elevatorModelIn = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_csa_elevatorB')
        self.leftDoorIn = self.elevatorModelIn.find('**/left_door')
        self.rightDoorIn = self.elevatorModelIn.find('**/right_door')
        self.elevatorModelOut = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_csa_elevator')
        self.leftDoorOut = self.elevatorModelOut.find('**/left_door')
        self.rightDoorOut = self.elevatorModelOut.find('**/right_door')

    def __makeShopOwnerNpc(self):
        if self.shopOwnerNpc:
            return
        self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId)
        if not self.shopOwnerNpc:
            self.notify.warning('No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons')
            random.seed(self.doId)
            shopkeeper = random.randint(7001, 7009)
            self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper)
        self.shopOwnerNpc.addActive()
        self.shopOwnerNpc.reparentTo(self.cage)
        self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0)
        self.shopOwnerNpc.loop('neutral')

    def setElevatorLights(self, elevatorModel):
        npc = elevatorModel.findAllMatches('**/floor_light_?;+s')
        for i in xrange(npc.getNumPaths()):
            np = npc.getPath(i)
            np.setDepthOffset(120)
            floor = int(np.getName()[-1:]) - 1
            if floor == self.currentFloor:
                np.setColor(LIGHT_ON_COLOR)
            elif floor < self.layout.getNumGameFloors() + (1 if self.FOType != "s" else 0):
                if self.isBossFloor(self.currentFloor):
                    np.setColor(LIGHT_ON_COLOR)
                else:
                    np.setColor(LIGHT_OFF_COLOR)
            else:
                np.hide()

    def startAlertElevatorLightIval(self, elevatorModel):
        light = elevatorModel.find('**/floor_light_%s' % (self.currentFloor + 1))
        track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)), Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR), Wait(0.9))
        self.activeIntervals['alertElevatorLight'] = track
        track.loop()

    def stopAlertElevatorLightIval(self, elevatorModel):
        self.__finishInterval('alertElevatorLight')
        self.setElevatorLights(elevatorModel)

    def handleAnnounceGenerate(self, obj):
        self.ignore(self.announceGenerateName)
        self.cageDoorSfx = loader.loadSfx('phase_5/audio/sfx/CHQ_SOS_cage_door.ogg')
        self.cageLowerSfx = loader.loadSfx('phase_5/audio/sfx/CHQ_SOS_cage_lower.ogg')
        self.sendUpdate('setAvatarJoined', [])

    def disable(self):
        self.fsm.requestFinalState()
        self.__cleanupIntervals()
        self.ignoreAll()
        self.__cleanup()
        self.__cleanupShopOwnerNpc()
        self.__cleanupPenthouseIntro()
        DistributedObject.DistributedObject.disable(self)

    def __cleanupShopOwnerNpc(self):
        if self.shopOwnerNpc:
            self.shopOwnerNpc.removeActive()
            self.shopOwnerNpc.delete()
            self.shopOwnerNpc = None

    def __cleanupPenthouseIntro(self):
        if hasattr(self, '_movie') and self._movie:
            self._movie.unload()
            self._movie = None

    def delete(self):
        self._stashEntranceElevatorFC.destroy()
        self._doEntranceElevCallbacksFC.destroy()
        self._haveEntranceElevator.destroy()
        self._stashEntranceElevator.destroy()
        self._entranceElevCallbacks = None
        del self.waitMusic
        del self.elevatorMusic
        del self.openSfx
        del self.closeSfx
        del self.fsm
        base.localAvatar.inventory.setBattleCreditMultiplier(1)
        DistributedObject.DistributedObject.delete(self)

    def isBossFloor(self, floorNum):
        return self.layout.hasBossBattle() and (self.layout.getBossBattleFloor() + 0) == floorNum

    def __cleanup(self):
        self.toons = []
        self.suits = []
        self.reserveSuits = []
        self.joiningReserves = []
        if self.elevatorModelIn != None:
            self.elevatorModelIn.removeNode()
        if self.elevatorModelOut != None:
            self.elevatorModelOut.removeNode()
        if self.floorModel != None:
            self.floorModel.removeNode()
        if self.cage != None:
            self.cage = None
        if self.barrelRoom != None:
            self.barrelRoom.destroy()
            self.barrelRoom = None
        self.leftDoorIn = None
        self.rightDoorIn = None
        self.leftDoorOut = None
        self.rightDoorOut = None

    def __addToon(self, toon):
        self.accept(toon.uniqueName('disable'), self.__handleUnexpectedExit, extraArgs=[toon])

    def __handleUnexpectedExit(self, toon):
        self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId)
        self.__removeToon(toon, unexpected=1)

    def __removeToon(self, toon, unexpected = 0):
        if self.toons.count(toon) == 1:
            self.toons.remove(toon)
        self.ignore(toon.uniqueName('disable'))

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

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

        self.activeIntervals = {}

    def __closeInElevator(self):
        self.leftDoorIn.setPos(3.5, 0, 0)
        self.rightDoorIn.setPos(-3.5, 0, 0)

    def getZoneId(self):
        return self.zoneId

    def setZoneId(self, zoneId):
        self.zoneId = zoneId

    def getExtZoneId(self):
        return self.extZoneId

    def setExtZoneId(self, extZoneId):
        self.extZoneId = extZoneId

    def getDistBldgDoId(self):
        return self.distBldgDoId

    def setDistBldgDoId(self, distBldgDoId):
        self.distBldgDoId = distBldgDoId

    def setNumFloors(self, numFloors):
        self.layout = CogdoLayout(numFloors)

    def getToonIds(self):
        toonIds = []
        for toon in self.toons:
            toonIds.append(toon.doId)

        return toonIds

    def setToons(self, toonIds, hack):
        self.toonIds = toonIds
        oldtoons = self.toons
        self.toons = []
        for toonId in toonIds:
            if toonId != 0:
                if toonId in self.cr.doId2do:
                    toon = self.cr.doId2do[toonId]
                    toon.stopSmooth()
                    self.toons.append(toon)
                    if oldtoons.count(toon) == 0:
                        self.__addToon(toon)
                else:
                    self.notify.warning('setToons() - no toon: %d' % toonId)

        for toon in oldtoons:
            if self.toons.count(toon) == 0:
                self.__removeToon(toon)

    def setSuits(self, suitIds, reserveIds, values):
        oldsuits = self.suits
        self.suits = []
        self.joiningReserves = []
        for suitId in suitIds:
            if suitId in self.cr.doId2do:
                suit = self.cr.doId2do[suitId]
                self.suits.append(suit)
                suit.fsm.request('Battle')
                suit.buildingSuit = 1
                suit.reparentTo(render)
                if oldsuits.count(suit) == 0:
                    self.joiningReserves.append(suit)

                if 'Elevator' in repr(self.fsm):
                    # Fix the position.
                    pos, h = BattleBase.BattleBase.suitPoints[len(suitIds) - 1][suitIds.index(suitId)]
                    suit.setPos(pos)
                    suit.setH(h)
            else:
                self.notify.warning('setSuits() - no suit: %d' % suitId)

        self.reserveSuits = []
        for index in xrange(len(reserveIds)):
            suitId = reserveIds[index]
            if suitId in self.cr.doId2do:
                suit = self.cr.doId2do[suitId]
                self.reserveSuits.append((suit, values[index]))
            else:
                self.notify.warning('setSuits() - no suit: %d' % suitId)

        if len(self.joiningReserves) > 0:
            self.fsm.request('ReservesJoining')

    def setState(self, state, timestamp):
        self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])

    def stashElevatorIn(self, stash = True):
        self._stashEntranceElevator.set(stash)

    def getEntranceElevator(self, callback):
        if self._haveEntranceElevator.get():
            callback(self.elevIn)
        else:
            self._entranceElevCallbacks.append(callback)

    def _doEntranceElevCallbacks(self, haveElev):
        if haveElev:
            while len(self._entranceElevCallbacks):
                cbs = self._entranceElevCallbacks[:]
                self._entranceElevCallbacks = []
                for callback in cbs:
                    callback(self.elevIn)

    def _doStashEntranceElevator(self, haveElev, doStash):
        if haveElev:
            if doStash:
                self.elevIn.stash()
            else:
                self.elevIn.unstash()

    def d_elevatorDone(self):
        self.sendUpdate('elevatorDone', [])

    def d_reserveJoinDone(self):
        self.sendUpdate('reserveJoinDone', [])

    def enterOff(self, ts = 0):
        messenger.send('sellbotFieldOfficeChanged', [False])
        return None

    def exitOff(self):
        return None

    def enterWaitForAllToonsInside(self, ts = 0):
        base.transitions.fadeOut(0)

    def exitWaitForAllToonsInside(self):
        return None

    def enterGame(self, ts = 0):
        base.cr.forbidCheesyEffects(1)

    def exitGame(self):
        base.cr.forbidCheesyEffects(0)

    def __playElevator(self, ts, name, callback):
        SuitHs = []
        SuitPositions = []

        if self.floorModel:
            self.floorModel.removeNode()
            self.floorModel = None

        if self.cage:
            self.cage = None

        if self.currentFloor == 0:
            SuitHs = self.BottomFloor_SuitHs
            SuitPositions = self.BottomFloor_SuitPositions

        if self.isBossFloor(self.currentFloor):
            self.notify.info('__playElevator: currentFloor %s is boss' % self.currentFloor)
            self.barrelRoom.unload()
            if self.FOType:
                penthouseName = SUITE_DICT.get(self.FOType)
                for i in xrange(4):
                    self.floorModel = loader.loadModel('phase_5/models/cogdominium/%s' % penthouseName)

            self.cage = self.floorModel.find('**/cage')
            pos = self.cage.getPos()
            self.cagePos = []
            for height in self.cageHeights:
                self.cagePos.append(Point3(pos[0], pos[1], height))

            self.cageDoor = self.floorModel.find('**/cage_door')
            self.cageDoor.wrtReparentTo(self.cage)
            if self.FOType:
                paintingModelName = PAINTING_DICT.get(self.FOType)
                for i in xrange(4):
                    paintingModel = loader.loadModel('phase_5/models/cogdominium/%s' % paintingModelName)
                    loc = self.floorModel.find('**/loc_painting%d' % (i + 1))
                    paintingModel.reparentTo(loc)

            if not self.floorModel.find('**/trophyCase').isEmpty():
                for i in xrange(4):
                    goldEmblem = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy.bam')
                    loc = self.floorModel.find('**/gold_0%d' % (i + 1))
                    goldEmblem.reparentTo(loc)
                for i in xrange(20):
                    silverEmblem = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam')
                    loc = self.floorModel.find('**/silver_0%d' % (i + 1))
                    silverEmblem.reparentTo(loc)

            SuitHs = self.BossOffice_SuitHs
            SuitPositions = self.BossOffice_SuitPositions
            self.__makeShopOwnerNpc()
        else:
            if self._wantBarrelRoom:
                self.barrelRoom.load()
                self.barrelRoom.hide()
            SuitHs = self.Cubicle_SuitHs
            SuitPositions = self.Cubicle_SuitPositions

        if self.floorModel:
            self.floorModel.reparentTo(render)
            if self.isBossFloor(self.currentFloor):
                self.notify.info('Load boss_suit_office')
                elevIn = self.floorModel.find(CogdoGameConsts.PenthouseElevatorInPath).copyTo(render)
                elevOut = self.floorModel.find(CogdoGameConsts.PenthouseElevatorOutPath)
                frame = self.elevatorModelOut.find('**/frame')

                if not frame.isEmpty():
                    frame.hide()

                frame = self.elevatorModelIn.find('**/frame')

                if not frame.isEmpty():
                    frame.hide()

                self.elevatorModelOut.reparentTo(elevOut)
                self.elevatorModelOut.setY(0)
            else:
                elevIn = self.floorModel.find('**/elevator-in')
                elevOut = self.floorModel.find('**/elevator-out')
        elif self._wantBarrelRoom and self.barrelRoom.isLoaded() and self.currentFloor == 2 and self.FOType == 'l': #i know this is really ugly
            elevIn = self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorInPath)
            elevOut = self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath)
            y = elevOut.getY(render)
            elevOut = elevOut.copyTo(render)
            elevOut.setY(render, y - 0.75)
        else:
            floorModel = loader.loadModel('phase_7/models/modules/boss_suit_office')
            elevIn = floorModel.find('**/elevator-in').copyTo(render)
            elevOut = floorModel.find('**/elevator-out').copyTo(render)
            floorModel.removeNode()

        self.elevIn = elevIn
        self.elevOut = elevOut
        self._haveEntranceElevator.set(True)
        for index in xrange(len(self.suits)):
            if not self.suits[index].isEmpty():
                self.suits[index].setPos(SuitPositions[index])
                if len(self.suits) > 2:
                    self.suits[index].setH(SuitHs[index])
                else:
                    self.suits[index].setH(170)
                self.suits[index].loop('neutral')

        for toon in self.toons:
            toon.reparentTo(self.elevatorModelIn)
            index = self.toonIds.index(toon.doId)
            toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2])
            toon.setHpr(180, 0, 0)
            toon.loop('neutral')

        self.elevatorModelIn.reparentTo(elevIn)
        self.leftDoorIn.setPos(3.5, 0, 0)
        self.rightDoorIn.setPos(-3.5, 0, 0)
        camera.reparentTo(self.elevatorModelIn)
        camera.setH(180)
        camera.setP(0)
        camera.setPos(0, 14, 4)
        base.playMusic(self.elevatorMusic, looping=1, volume=0.8)
        track = Sequence(Func(base.transitions.noTransitions), ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL), ElevatorUtils.getOpenInterval(self, self.leftDoorIn, self.rightDoorIn, self.openSfx, None, type=ELEVATOR_NORMAL), Func(camera.wrtReparentTo, render))
        for toon in self.toons:
            track.append(Func(toon.wrtReparentTo, render))

        track.append(Func(callback))
        track.start(ts)
        self.activeIntervals[name] = track

    def enterElevator(self, ts = 0):
        if not self._CogdoGameRepeat:
            self.currentFloor += 1
        self.cr.playGame.getPlace().currentFloor = self.currentFloor
        self.setElevatorLights(self.elevatorModelIn)
        self.setElevatorLights(self.elevatorModelOut)
        if not self.isBossFloor(self.currentFloor):
            self.elevatorModelOut.detachNode()
            messenger.send('sellbotFieldOfficeChanged', [True])
        else:
            if self.FOType == 's':
                self._movie = CogdoElevatorMovie()
                self._movie.load()
                self._movie.play()
        self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone)
        mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor)
        base.localAvatar.inventory.setBattleCreditMultiplier(mult)

    def __handleElevatorDone(self):
        self.d_elevatorDone()

    def exitElevator(self):
        self.elevatorMusic.stop()
        if self._movie:
            self._movie.end()
            self.__cleanupPenthouseIntro()
        self.__finishInterval(self.elevatorName)

    def __setupBarrelRoom(self):
        self.currentFloor += 1
        base.transitions.irisOut(0.0)
        self.elevatorModelOut.setY(-12)
        self.elevatorModelIn.reparentTo(self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorInPath))
        self.leftDoorIn.setPos(3.5, 0, 0)
        self.rightDoorIn.setPos(-3.5, 0, 0)
        self._showExitElevator()
        self.barrelRoom.show()
        self.barrelRoom.placeToonsAtEntrance(self.toons)
        self.setElevatorLights(self.elevatorModelOut)

    def barrelRoomIntroDone(self):
        self.sendUpdate('toonBarrelRoomIntroDone', [])

    def enterBarrelRoomIntro(self, ts = 0):
        if not self.isBossFloor(self.currentFloor):
            if self._wantBarrelRoom:
                self.__setupBarrelRoom()
                self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval()
                self.barrelRoomIntroDoneEvent = trackName
                self.accept(self.barrelRoomIntroDoneEvent, self.barrelRoomIntroDone)
                self.activeIntervals[trackName] = self.barrelRoomIntroTrack
                self.barrelRoomIntroTrack.start(ts)
                self._movie = CogdoBarrelRoomIntro()
                self._movie.load()
                self._movie.play()
            else:
                self._showExitElevator()

    def exitBarrelRoomIntro(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            self.ignore(self.barrelRoomIntroDoneEvent)
            if self.barrelRoomIntroTrack:
                self.barrelRoomIntroTrack.finish()
                DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack)
                self.barrelRoomIntroTrack = None

    def __handleLocalToonLeftBarrelRoom(self):
        self.notify.info('Local toon teleported out of barrel room.')
        self.sendUpdate('toonLeftBarrelRoom', [])
        self.barrelRoom.deactivate()

    def enterCollectBarrels(self, ts = 0):
        if not self.isBossFloor(self.currentFloor):
            if self._wantBarrelRoom:
                self.acceptOnce('localToonLeft', self.__handleLocalToonLeftBarrelRoom)
                self.barrelRoom.activate()
                base.playMusic(self.waitMusic, looping=1, volume=0.7)
                base.localAvatar.questMap.stop()

    def exitCollectBarrels(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            self.ignore('localToonLeft')
            self.barrelRoom.deactivate()
            self.waitMusic.stop()

    def __brRewardDone(self, task = None):
        self.notify.info('Toon finished watching the barrel room reward.')
        self.sendUpdate('toonBarrelRoomRewardDone', [])
        self.fsm.request('Battle')

    def enterBarrelRoomReward(self, ts = 0):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            base.cr.playGame.getPlace().fsm.request('stopped')
            self.startAlertElevatorLightIval(self.elevatorModelOut)
            track, trackName = self.barrelRoom.showRewardUi(callback=self.__brRewardDone)
            self.activeIntervals[trackName] = track
            track.start()
            self.barrelRoom.placeToonsNearBattle(self.toons)

    def exitBarrelRoomReward(self):
        if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor):
            base.cr.playGame.getPlace().fsm.request('walk')
            self.stopAlertElevatorLightIval(self.elevatorModelOut)
            self.barrelRoom.hideRewardUi()

    def enterBattleIntro(self, ts = 0):
        self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc)
        self._movie.load()
        self._movie.play()

    def exitBattleIntro(self):
        self._movie.end()
        self.__cleanupPenthouseIntro()

    def __playCloseElevatorOut(self, name, delay = 0):
        track = Sequence(Wait(delay + SUIT_LEAVE_ELEVATOR_TIME), Parallel(SoundInterval(self.closeSfx), LerpPosInterval(self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'), LerpPosInterval(self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut')))
        track.start()
        self.activeIntervals[name] = track

    def enterBattle(self, ts = 0):
        if self._wantBarrelRoom and self.elevatorOutOpen == 1:
            self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'), delay=2)
            camera.setPos(0, -15, 6)
            camera.headsUp(self.elevatorModelOut)

    def _showExitElevator(self):
        self.elevatorModelOut.reparentTo(self.elevOut)
        self.leftDoorOut.setPos(3.5, 0, 0)
        self.rightDoorOut.setPos(-3.5, 0, 0)
        if not self._wantBarrelRoom and self.elevatorOutOpen == 1:
            self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'))
            camera.setPos(0, -15, 6)
            camera.headsUp(self.elevatorModelOut)

    def exitBattle(self):
        if self.elevatorOutOpen == 1:
            self.__finishInterval(self.uniqueName('close-out-elevator'))
            self.elevatorOutOpen = 0

    def __playReservesJoining(self, ts, name, callback):
        index = 0
        for suit in self.joiningReserves:
            suit.reparentTo(render)
            suit.setPos(self.elevatorModelOut, Point3(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2]))
            index += 1
            suit.setH(180)
            suit.loop('neutral')

        track = Sequence(Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0)), Parallel(SoundInterval(self.openSfx), LerpPosInterval(self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), LerpPosInterval(self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), blendType='easeOut')), Wait(SUIT_HOLD_ELEVATOR_TIME), Func(camera.wrtReparentTo, render), Func(callback))
        track.start(ts)
        self.activeIntervals[name] = track

    def enterReservesJoining(self, ts = 0):
        self.__playReservesJoining(ts, self.uniqueName('reserves-joining'), self.__handleReserveJoinDone)

    def __handleReserveJoinDone(self):
        self.joiningReserves = []
        self.elevatorOutOpen = 1
        self.d_reserveJoinDone()

    def exitReservesJoining(self):
        self.__finishInterval(self.uniqueName('reserves-joining'))

    def enterResting(self, ts = 0):
        self._showExitElevator()
        self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit)
        if self._wantBarrelRoom:
            self.barrelRoom.showBattleAreaLight(True)
        base.playMusic(self.waitMusic, looping=1, volume=0.7)
        self.__closeInElevator()
        self._haveEntranceElevator.set(False)
        self._stashEntranceElevator.set(False)

    def _setAvPosToExit(self):
        base.localAvatar.setPos(self.elevOut, 0, -22, 0)
        base.localAvatar.setHpr(self.elevOut, 0, 0, 0)
        base.cr.playGame.getPlace().fsm.request('walk')

    def exitResting(self):
        self._setAvPosFDC.destroy()
        self.waitMusic.stop()

    def enterReward(self, ts = 0):
        if self.isBossFloor(self.currentFloor):
            self.penthouseOutroTrack = self.__outroPenthouse()
            self.penthouseOutroTrack.start(ts)
        else:
            self.exitCogdoBuilding()

    def exitReward(self):
        self.notify.debug('exitReward')
        if self.penthouseOutroTrack:
            self.penthouseOutroTrack.finish()
            DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack)
            self.penthouseOutroTrack = None
            if not self.penthouseOutroChatDoneTrack:
                self.notify.debug('exitReward: instanting outroPenthouseChatDone track')
                self.__outroPenthouseChatDone()
            self.penthouseOutroChatDoneTrack.finish()
            self.penthouseOutroChatDoneTrack = None

    def enterFailed(self, ts = 0):
        self.exitCogdoBuilding()

    def exitFailed(self):
        self.notify.debug('exitFailed()')
        self.exitCogdoBuilding()

    def exitCogdoBuilding(self):
        if base.localAvatar.hp < 0:
            return
        base.localAvatar.b_setParent(ToontownGlobals.SPHidden)
        request = {'loader': ZoneUtil.getBranchLoaderName(self.extZoneId),
         'where': ZoneUtil.getToonWhereName(self.extZoneId),
         'how': 'elevatorIn',
         'hoodId': ZoneUtil.getHoodId(self.extZoneId),
         'zoneId': self.extZoneId,
         'shardId': None,
         'avId': -1,
         'bldgDoId': self.distBldgDoId}
        messenger.send('DSIDoneEvent', [request])

    def displayBadges(self):
        numFloors = self.layout.getNumGameFloors()
        if numFloors > 5 or numFloors < 3:
            pass
        else:
            self.notify.warning('Invalid floor number for display badges.')
        for player in xrange(len(self.toons)):
            goldBadge = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy')
            goldBadge.setScale(1.2)
            goldNode = render.find('**/gold_0' + str(player + 1))
            goldBadge.reparentTo(goldNode)
            for floor in xrange(numFloors):
                silverBadge = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam')
                silverBadge.setScale(1.2)
                silverNode = render.find('**/silver_0' + str(floor * 4 + (player + 1)))
                silverBadge.reparentTo(silverNode)

    def __outroPenthouse(self):
        avatar = base.localAvatar
        trackName = '__outroPenthouse-%d' % avatar.doId
        track = Parallel(name=trackName)
        base.cr.playGame.getPlace().fsm.request('stopped')

        if self.FOType == 'l':
            speech = TTLocalizer.CogdoExecutiveSuiteToonThankYouLawbot
        else:
            speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName

        track.append(Sequence(Func(camera.wrtReparentTo, localAvatar),
                              Func(camera.setPos, 0, -9, 9),
                              Func(camera.lookAt, Point3(5, 15, 0)),
                              Parallel(self.cage.posInterval(0.75, self.cagePos[1], blendType='easeOut'),
                                       SoundInterval(self.cageLowerSfx, duration=0.5)),
                              Parallel(self.cageDoor.hprInterval(0.5, VBase3(0, 90, 0), blendType='easeOut'),
                                       Sequence(SoundInterval(self.cageDoorSfx), duration=0)),
                              Wait(0.25),
                              Func(self.shopOwnerNpc.wrtReparentTo, render),
                              Func(self.shopOwnerNpc.setScale, 1),
                              Func(self.shopOwnerNpc.loop, 'walk'),
                              Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)),
                              ParallelEndTogether(self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)), self.shopOwnerNpc.hprInterval(0.5, VBase3(180, 0, 0), blendType='easeInOut')),
                              Func(self.shopOwnerNpc.setChatAbsolute, TTLocalizer.CagedToonYippee, CFSpeech), ActorInterval(self.shopOwnerNpc, 'jump'),
                              Func(self.shopOwnerNpc.loop, 'neutral'), Func(self.shopOwnerNpc.headsUp, localAvatar),
                              Func(self.shopOwnerNpc.setLocalPageChat, speech, 0),
                              Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2))))
        self.activeIntervals[trackName] = track
        self.accept('doneChatPage', self.__outroPenthouseChatDone)
        return track

    def __outroPenthouseChatDone(self, elapsed = None):
        self.shopOwnerNpc.setChatAbsolute(TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech)
        self.ignore('doneChatPage')
        track = Parallel(Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence(Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setFov, settings['fov'])))
        track.start()
        self.penthouseOutroChatDoneTrack = track
コード例 #11
0
class FrameProfiler:
    notify = directNotify.newCategory('FrameProfiler')

    # because of precision requirements, all times related to the profile/log
    # schedule are stored as integers
    Minute = 60
    Hour = 60 * Minute
    Day = 24 * Hour

    def __init__(self):
        Hour = FrameProfiler.Hour
        # how long to wait between frame profiles
        self._period = 2 * FrameProfiler.Minute
        if config.GetBool('frequent-frame-profiles', 0):
            self._period = 1 * FrameProfiler.Minute
        # used to prevent profile from being taken exactly every 'period' seconds
        self._jitterMagnitude = self._period * .75
        # when to log output
        # each entry must be an integer multiple of all previous entries
        # as well as an integer multiple of the period
        self._logSchedule = [ 1 * FrameProfiler.Hour,
                              4 * FrameProfiler.Hour,
                             12 * FrameProfiler.Hour,
                              1 * FrameProfiler.Day,
                              ] # day schedule proceeds as 1, 2, 4, 8 days, etc.
        if config.GetBool('frequent-frame-profiles', 0):
            self._logSchedule = [ 1  * FrameProfiler.Minute,
                                  4  * FrameProfiler.Minute,
                                  12 * FrameProfiler.Minute,
                                  24 * FrameProfiler.Minute,
                                  ]
        for t in self._logSchedule:
            assert isInteger(t)
            # make sure the period is evenly divisible into each element of the log schedule
            assert (t % self._period) == 0
        # make sure each element of the schedule is evenly divisible into each subsequent element
        for i in xrange(len(self._logSchedule)):
            e = self._logSchedule[i]
            for j in xrange(i, len(self._logSchedule)):
                assert (self._logSchedule[j] % e) == 0
        assert isInteger(self._period)
        self._enableFC = FunctionCall(self._setEnabled, taskMgr.getProfileFramesSV())
        self._enableFC.pushCurrentState()

    def destroy(self):
        self._enableFC.set(False)
        self._enableFC.destroy()
        
    def _setEnabled(self, enabled):
        if enabled:
            self.notify.info('frame profiler started')
            self._startTime = globalClock.getFrameTime()
            self._profileCounter = 0
            self._jitter = None
            self._period2aggregateProfile = {}
            self._id2session = {}
            self._id2task = {}
            # don't profile process startup
            self._task = taskMgr.doMethodLater(self._period, self._scheduleNextProfileDoLater,
                                               'FrameProfilerStart-%s' % serialNum())
        else:
            self._task.remove()
            del self._task
            for session in self._period2aggregateProfile.itervalues:
                session.release()
            del self._period2aggregateProfile
            for task in self._id2task.itervalues():
                task.remove()
            del self._id2task
            for session in self._id2session.itervalues():
                session.release()
            del self._id2session
            self.notify.info('frame profiler stopped')

    def _scheduleNextProfileDoLater(self, task):
        self._scheduleNextProfile()
        return task.done

    def _scheduleNextProfile(self):
        self._profileCounter += 1
        self._timeElapsed = self._profileCounter * self._period
        assert isInteger(self._timeElapsed)
        time = self._startTime + self._timeElapsed

        # vary the actual delay between profiles by a random amount to prevent interaction
        # with periodic events
        jitter = self._jitter
        if jitter is None:
            jitter = normalDistrib(-self._jitterMagnitude, self._jitterMagnitude)
            time += jitter
        else:
            time -= jitter
            jitter = None
        self._jitter = jitter
            
        sessionId = serialNum()
        session = taskMgr.getProfileSession('FrameProfile-%s' % sessionId)
        self._id2session[sessionId] = session
        taskMgr.profileFrames(num=1, session=session, callback=Functor(
            self._analyzeResults, sessionId))

        # schedule the next profile
        delay = max(time - globalClock.getFrameTime(), 0.)
        self._task = taskMgr.doMethodLater(delay, self._scheduleNextProfileDoLater,
                                           'FrameProfiler-%s' % serialNum())

    def _analyzeResults(self, sessionId):
        # do the analysis in a task 1) to separate the processing from the profiled frame,
        # and 2) to get the processing to show up in a named task instead of in the taskMgr
        self._id2task[sessionId] = taskMgr.add(
            Functor(self._doAnalysis, sessionId), 'FrameProfilerAnalysis-%s' % sessionId)

    def _doAnalysis(self, sessionId, task):
        if hasattr(task, '_generator'):
            gen = task._generator
        else:
            gen = self._doAnalysisGen(sessionId)
            task._generator = gen
        result = gen.next()
        if result == Task.done:
            del task._generator
        return result

    def _doAnalysisGen(self, sessionId):
        # generator to limit max number of profile loggings per frame
        p2ap = self._period2aggregateProfile

        self._id2task.pop(sessionId)
        session = self._id2session.pop(sessionId)

        if session.profileSucceeded():
            # always add this profile to the first aggregated profile
            period = self._logSchedule[0]
            if period not in self._period2aggregateProfile:
                p2ap[period] = session.getReference()
            else:
                p2ap[period].aggregate(session)
        else:
            self.notify.warning('frame profile did not succeed')

        session.release()
        session = None

        counter = 0

        # log profiles when it's time, and aggregate them upwards into the
        # next-longer profile
        for pi in xrange(len(self._logSchedule)):
            period = self._logSchedule[pi]
            if (self._timeElapsed % period) == 0:
                if period in p2ap:
                    # delay until the next frame if we've already processed N profiles this frame
                    if counter >= 3:
                        counter = 0
                        yield Task.cont
                    self.notify.info('aggregate profile of sampled frames over last %s\n%s' %
                                     (formatTimeExact(period), p2ap[period].getResults()))
                    counter += 1
                    # aggregate this profile into the next larger profile
                    nextIndex = pi + 1
                    if nextIndex >= len(self._logSchedule):
                        # if we're adding a new period to the end of the log period table,
                        # set it to double the duration of the current longest period
                        nextPeriod = period * 2
                        self._logSchedule.append(nextPeriod)
                    else:
                        nextPeriod = self._logSchedule[nextIndex]
                    if nextPeriod not in p2ap:
                        p2ap[nextPeriod] = p2ap[period].getReference()
                    else:
                        p2ap[nextPeriod].aggregate(p2ap[period])
                    # this profile is now represented in the next larger profile
                    # throw it out
                    p2ap[period].release()
                    del p2ap[period]
            else:
                # current time is not divisible evenly into selected period, and all higher
                # periods are multiples of this one
                break

        yield Task.done
コード例 #12
0
class TaskProfiler:
    # this does intermittent profiling of tasks running on the system
    # if a task has a spike in execution time, the profile of the spike is logged
    notify = directNotify.newCategory("TaskProfiler")

    def __init__(self):
        self._enableFC = FunctionCall(self._setEnabled, taskMgr.getProfileTasksSV())
        self._enableFC.pushCurrentState()
        # table of task name pattern to TaskTracker
        self._namePrefix2tracker = {}
        self._task = None

    def destroy(self):
        if taskMgr.getProfileTasks():
            self._setEnabled(False)
        self._enableFC.destroy()
        for tracker in self._namePrefix2tracker.itervalues():
            tracker.destroy()
        del self._namePrefix2tracker
        del self._task
        
    @staticmethod
    def GetDefaultSpikeThreshold():
        return config.GetFloat('profile-task-spike-threshold', 5.)

    @staticmethod
    def SetSpikeThreshold(spikeThreshold):
        TaskTracker.SpikeThreshold = spikeThreshold
    @staticmethod
    def GetSpikeThreshold():
        return TaskTracker.SpikeThreshold

    def logProfiles(self, name=None):
        if name:
            name = name.lower()
        for namePrefix, tracker in self._namePrefix2tracker.iteritems():
            if (name and (name not in namePrefix.lower())):
                continue
            tracker.log()

    def flush(self, name):
        if name:
            name = name.lower()
        # flush stored task profiles
        for namePrefix, tracker in self._namePrefix2tracker.iteritems():
            if (name and (name not in namePrefix.lower())):
                continue
            tracker.flush()

    def _setEnabled(self, enabled):
        if enabled:
            self.notify.info('task profiler started')
            self._taskName = 'profile-tasks-%s' % id(self)
            taskMgr.add(self._doProfileTasks, self._taskName, priority=-200)
        else:
            taskMgr.remove(self._taskName)
            del self._taskName
            self.notify.info('task profiler stopped')
        
    def _doProfileTasks(self, task=None):
        # gather data from the previous frame
        # set up for the next frame
        if (self._task is not None) and taskMgr._hasProfiledDesignatedTask():
            session = taskMgr._getLastTaskProfileSession()
            # if we couldn't profile, throw this result out
            if session.profileSucceeded():
                namePrefix = self._task.getNamePrefix()
                if namePrefix not in self._namePrefix2tracker:
                    self._namePrefix2tracker[namePrefix] = TaskTracker(namePrefix)
                tracker = self._namePrefix2tracker[namePrefix]
                tracker.addProfileSession(session)

        # set up the next task
        self._task = taskMgr._getRandomTask()
        taskMgr._setProfileTask(self._task)

        return task.cont
コード例 #13
0
class TaskProfiler:
    notify = directNotify.newCategory('TaskProfiler')

    def __init__(self):
        self._enableFC = FunctionCall(self._setEnabled,
                                      taskMgr.getProfileTasksSV())
        self._enableFC.pushCurrentState()
        self._namePrefix2tracker = {}
        self._task = None
        return

    def destroy(self):
        if taskMgr.getProfileTasks():
            self._setEnabled(False)
        self._enableFC.destroy()
        for tracker in self._namePrefix2tracker.itervalues():
            tracker.destroy()

        del self._namePrefix2tracker
        del self._task

    @staticmethod
    def GetDefaultSpikeThreshold():
        return config.GetFloat('profile-task-spike-threshold', 5.0)

    @staticmethod
    def SetSpikeThreshold(spikeThreshold):
        TaskTracker.SpikeThreshold = spikeThreshold

    @staticmethod
    def GetSpikeThreshold():
        return TaskTracker.SpikeThreshold

    def logProfiles(self, name=None):
        if name:
            name = name.lower()
        for namePrefix, tracker in self._namePrefix2tracker.iteritems():
            if name and name not in namePrefix.lower():
                continue
            tracker.log()

    def flush(self, name):
        if name:
            name = name.lower()
        for namePrefix, tracker in self._namePrefix2tracker.iteritems():
            if name and name not in namePrefix.lower():
                continue
            tracker.flush()

    def _setEnabled(self, enabled):
        if enabled:
            self.notify.info('task profiler started')
            self._taskName = 'profile-tasks-%s' % id(self)
            taskMgr.add(self._doProfileTasks, self._taskName, priority=-200)
        else:
            taskMgr.remove(self._taskName)
            del self._taskName
            self.notify.info('task profiler stopped')

    def _doProfileTasks(self, task=None):
        if self._task is not None and taskMgr._hasProfiledDesignatedTask():
            session = taskMgr._getLastTaskProfileSession()
            if session.profileSucceeded():
                namePrefix = self._task.getNamePrefix()
                if namePrefix not in self._namePrefix2tracker:
                    self._namePrefix2tracker[namePrefix] = TaskTracker(
                        namePrefix)
                tracker = self._namePrefix2tracker[namePrefix]
                tracker.addProfileSession(session)
        self._task = taskMgr._getRandomTask()
        taskMgr._setProfileTask(self._task)
        return task.cont
コード例 #14
0
ファイル: FrameProfiler.pyc.py プロジェクト: z010155/c0d3
class FrameProfiler():
    __module__ = __name__
    notify = directNotify.newCategory('FrameProfiler')
    Minute = 60
    Hour = 60 * Minute
    Day = 24 * Hour

    def __init__(self):
        Hour = FrameProfiler.Hour
        self._period = 2 * FrameProfiler.Minute
        if config.GetBool('frequent-frame-profiles', 0):
            self._period = 1 * FrameProfiler.Minute
        self._jitterMagnitude = self._period * 0.75
        self._logSchedule = [1 * FrameProfiler.Hour,
         4 * FrameProfiler.Hour,
         12 * FrameProfiler.Hour,
         1 * FrameProfiler.Day]
        if config.GetBool('frequent-frame-profiles', 0):
            self._logSchedule = [1 * FrameProfiler.Minute,
             4 * FrameProfiler.Minute,
             12 * FrameProfiler.Minute,
             24 * FrameProfiler.Minute]
        for t in self._logSchedule:
            pass

        for i in xrange(len(self._logSchedule)):
            e = self._logSchedule[i]
            for j in xrange(i, len(self._logSchedule)):
                pass

        self._enableFC = FunctionCall(self._setEnabled, taskMgr.getProfileFramesSV())
        self._enableFC.pushCurrentState()

    def destroy(self):
        self._enableFC.set(False)
        self._enableFC.destroy()

    def _setEnabled(self, enabled):
        if enabled:
            self.notify.info('frame profiler started')
            self._startTime = globalClock.getFrameTime()
            self._profileCounter = 0
            self._jitter = None
            self._period2aggregateProfile = {}
            self._id2session = {}
            self._id2task = {}
            self._task = taskMgr.doMethodLater(self._period, self._scheduleNextProfileDoLater, 'FrameProfilerStart-%s' % serialNum())
        else:
            self._task.remove()
            del self._task
            for session in self._period2aggregateProfile.itervalues:
                session.release()

            del self._period2aggregateProfile
            for task in self._id2task.itervalues():
                task.remove()

            del self._id2task
            for session in self._id2session.itervalues():
                session.release()

            del self._id2session
            self.notify.info('frame profiler stopped')
        return

    def _scheduleNextProfileDoLater(self, task):
        self._scheduleNextProfile()
        return task.done

    def _scheduleNextProfile(self):
        self._profileCounter += 1
        self._timeElapsed = self._profileCounter * self._period
        time = self._startTime + self._timeElapsed
        jitter = self._jitter
        if jitter is None:
            jitter = normalDistrib(-self._jitterMagnitude, self._jitterMagnitude)
            time += jitter
        else:
            time -= jitter
            jitter = None
        self._jitter = jitter
        sessionId = serialNum()
        session = taskMgr.getProfileSession('FrameProfile-%s' % sessionId)
        self._id2session[sessionId] = session
        taskMgr.profileFrames(num=1, session=session, callback=Functor(self._analyzeResults, sessionId))
        delay = max(time - globalClock.getFrameTime(), 0.0)
        self._task = taskMgr.doMethodLater(delay, self._scheduleNextProfileDoLater, 'FrameProfiler-%s' % serialNum())
        return

    def _analyzeResults(self, sessionId):
        self._id2task[sessionId] = taskMgr.add(Functor(self._doAnalysis, sessionId), 'FrameProfilerAnalysis-%s' % sessionId)

    def _doAnalysis(self, sessionId, task):
        if hasattr(task, '_generator'):
            gen = task._generator
        else:
            gen = self._doAnalysisGen(sessionId)
            task._generator = gen
        result = gen.next()
        if result == Task.done:
            del task._generator
        return result

    def _doAnalysisGen--- This code section failed: ---
コード例 #15
0
class DistCogdoGame(DistCogdoGameBase, DistributedObject):
    notify = directNotify.newCategory('DistCogdoGame')

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        base.cogdoGame = self
        cr.cogdoGame = self
        self._waitingStartLabel = DirectLabel(text=TTL.MinigameWaitingForOtherPlayers, text_fg=VBase4(1, 1, 1, 1), relief=None, pos=(-0.6, 0, -0.75), scale=0.075)
        self._waitingStartLabel.hide()
        self.loadFSM = ClassicFSM.ClassicFSM('DistCogdoGame.loaded', [State.State('NotLoaded', self.enterNotLoaded, self.exitNotLoaded, ['Loaded']), State.State('Loaded', self.enterLoaded, self.exitLoaded, ['NotLoaded'])], 'NotLoaded', 'NotLoaded')
        self.loadFSM.enterInitialState()
        self.fsm = ClassicFSM.ClassicFSM('DistCogdoGame', [State.State('Visible', self.enterVisible, self.exitVisible, ['Intro']),
         State.State('Intro', self.enterIntro, self.exitIntro, ['WaitServerStart']),
         State.State('WaitServerStart', self.enterWaitServerStart, self.exitWaitServerStart, ['Game']),
         State.State('Game', self.enterGame, self.exitGame, ['Finish']),
         State.State('Finish', self.enterFinish, self.exitFinish, ['Off']),
         State.State('Off', self.enterOff, self.exitOff, ['Visible'])], 'Off', 'Off')
        self.fsm.enterInitialState()
        self.difficultyOverride = None
        self.exteriorZoneOverride = None
        self._gotInterior = StateVar(False)
        self._toonsInEntranceElev = StateVar(False)
        self._wantStashElevator = StateVar(False)
        self._stashElevatorFC = FunctionCall(self._doStashElevator, self._toonsInEntranceElev, self._gotInterior, self._wantStashElevator)

    def getTitle(self):
        pass

    def getInstructions(self):
        pass

    def setInteriorId(self, interiorId):
        self._interiorId = interiorId

    def setExteriorZone(self, exteriorZone):
        self.exteriorZone = exteriorZone

    def setDifficultyOverrides(self, difficultyOverride, exteriorZoneOverride):
        if difficultyOverride != CogdoGameConsts.NoDifficultyOverride:
            self.difficultyOverride = difficultyOverride / float(CogdoGameConsts.DifficultyOverrideMult)
        if exteriorZoneOverride != CogdoGameConsts.NoExteriorZoneOverride:
            self.exteriorZoneOverride = exteriorZoneOverride

    def getInterior(self):
        return self.cr.getDo(self._interiorId)

    def getEntranceElevator(self, callback):
        return self.getInterior().getEntranceElevator(callback)

    def getToonIds(self):
        interior = self.getInterior()
        if interior is not None:
            return interior.getToonIds()
        else:
            return []

    def getToon(self, toonId):
        if self.cr.doId2do.has_key(toonId):
            return self.cr.doId2do[toonId]
        else:
            return None

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

    def isSinglePlayer(self):
        if self.getNumPlayers() == 1:
            return 1
        else:
            return 0

    def announceGenerate(self):
        DistributedObject.announceGenerate(self)
        self.loadFSM.request('Loaded')
        self._requestInterior()
        self.notify.info('difficulty: %s, safezoneId: %s' % (self.getDifficulty(), self.getSafezoneId()))

    def _requestInterior(self):
        self.cr.relatedObjectMgr.requestObjects([self._interiorId], allCallback=self._handleGotInterior)

    def _handleGotInterior(self, objs):
        self._gotInterior.set(True)
        self.getEntranceElevator(self.placeEntranceElev)

    def stashEntranceElevator(self):
        self._wantStashElevator.set(True)

    def placeEntranceElev(self, elev):
        pass

    def _doStashElevator(self, toonsInEntranceElev, gotInterior, wantStashElevator):
        if gotInterior:
            interior = self.getInterior()
            if interior:
                if not toonsInEntranceElev and wantStashElevator:
                    interior.stashElevatorIn()
                else:
                    interior.stashElevatorIn(False)

    def disable(self):
        base.cogdoGame = None
        self.cr.cogdoGame = None
        self.fsm.requestFinalState()
        self.loadFSM.requestFinalState()
        self.fsm = None
        self.loadFSM = None
        DistributedObject.disable(self)

    def delete(self):
        self._stashElevatorFC.destroy()
        self._wantStashElevator.destroy()
        self._toonsInEntranceElev.destroy()
        self._gotInterior.destroy()
        self._waitingStartLabel.destroy()
        self._waitingStartLabel = None
        DistributedObject.delete(self)

    def getDifficulty(self):
        if self.difficultyOverride is not None:
            return self.difficultyOverride
        if hasattr(base, 'cogdoGameDifficulty'):
            return float(base.cogdoGameDifficulty)
        return CogdoGameConsts.getDifficulty(self.getSafezoneId())

    def getSafezoneId(self):
        if self.exteriorZoneOverride is not None:
            return self.exteriorZoneOverride
        if hasattr(base, 'cogdoGameSafezoneId'):
            return CogdoGameConsts.getSafezoneId(base.cogdoGameSafezoneId)
        return CogdoGameConsts.getSafezoneId(self.exteriorZone)

    def enterNotLoaded(self):
        pass

    def exitNotLoaded(self):
        pass

    def enterLoaded(self):
        pass

    def exitLoaded(self):
        pass

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def setVisible(self):
        self.fsm.request('Visible')

    def setIntroStart(self):
        self.fsm.request('Intro')

    def enterVisible(self):
        self._toonsInEntranceElev.set(True)

    def exitVisible(self):
        pass

    def enterIntro(self, duration = MinigameGlobals.rulesDuration):
        base.cr.playGame.getPlace().fsm.request('Game')
        self._rulesDoneEvent = self.uniqueName('cogdoGameRulesDone')
        self.accept(self._rulesDoneEvent, self._handleRulesDone)
        self._rulesPanel = CogdoGameRulesPanel('CogdoGameRulesPanel', self.getTitle(), '', self._rulesDoneEvent, timeout=duration)
        self._rulesPanel.load()
        self._rulesPanel.enter()

    def exitIntro(self):
        self._toonsInEntranceElev.set(False)
        self.ignore(self._rulesDoneEvent)
        if self._rulesPanel:
            self._rulesPanel.exit()
            self._rulesPanel.unload()
            self._rulesPanel = None

    def _handleRulesDone(self):
        self.ignore(self._rulesDoneEvent)
        self._rulesPanel.exit()
        self._rulesPanel.unload()
        self._rulesPanel = None
        self.fsm.request('WaitServerStart')
        self.d_setAvatarReady()

    def d_setAvatarReady(self):
        self.sendUpdate('setAvatarReady', [])

    def enterWaitServerStart(self):
        numToons = 1
        interior = self.getInterior()
        if interior:
            numToons = len(interior.getToonIds())
        if numToons > 1:
            msg = TTL.MinigameWaitingForOtherPlayers
        else:
            msg = TTL.MinigamePleaseWait
        self._waitingStartLabel['text'] = msg
        self._waitingStartLabel.show()

    def exitWaitServerStart(self):
        self._waitingStartLabel.hide()

    def setGameStart(self, timestamp):
        self._startTime = globalClockDelta.networkToLocalTime(timestamp)
        self.fsm.request('Game')

    def getStartTime(self):
        return self._startTime

    def enterGame(self):
        if SCHELLGAMES_DEV:
            self.acceptOnce('escape', messenger.send, ['magicWord', ['~endMaze']])

    def exitGame(self):
        if SCHELLGAMES_DEV:
            self.ignore('escape')

    def setGameFinish(self, timestamp):
        self._finishTime = globalClockDelta.networkToLocalTime(timestamp)
        self.fsm.request('Finish')

    def getFinishTime(self):
        return self._finishTime

    def enterFinish(self):
        pass

    def exitFinish(self):
        pass

    def setToonSad(self, toonId):
        pass

    def setToonDisconnect(self, toonId):
        pass
コード例 #16
0
ファイル: SiegeManager.py プロジェクト: TTGhost/POTCOR-src
class SiegeManager(DistributedObject, SiegeManagerBase):
    TeamJoinableChangedEvent = 'PVPTeamJoinableChanged'
    
    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        SiegeManagerBase.__init__(self)

    
    def generate(self):
        self._announcerInterest = None
        self._siegeTeam = 0
        self._siegeTeamUpdater = FunctionCall(self._setSiegeTeam, localAvatar._siegeTeamSV)
        self._siegeTeamUpdater.pushCurrentState()
        DistributedObject.generate(self)
        self._pvpTeamJoinable = { }
        base.cr.distributedDistrict.siegeManager = self

    
    def delete(self):
        self._siegeTeamUpdater.destroy()
        del self._siegeTeamUpdater
        self._removeAnnouncerInterest()
        del self._pvpTeamJoinable
        del base.cr.distributedDistrict.siegeManager
        DistributedObject.delete(self)

    
    def setPvpEnabled(self, enabled):
        self._pvpEnabled = enabled

    
    def getPvpEnabled(self):
        return self._pvpEnabled

    
    def setTeamsJoinable(self, teamJoinableItems):
        for (teamId, joinable) in teamJoinableItems:
            self._pvpTeamJoinable[teamId] = joinable
        
        messenger.send(SiegeManager.TeamJoinableChangedEvent)

    
    def teamIsJoinable(self, teamId):
        if not config.GetBool('want-pvp-team-balance', 1):
            return True
        
        return self._pvpTeamJoinable.get(teamId, True)

    
    def sendTalk(self, message):
        print 'Seige Manager Sending Message %s' % message
        self.sendUpdate('setTalkGroup', [
            0,
            0,
            '',
            message,
            [],
            0])

    
    def sendWLChat(self, message):
        self.sendUpdate('sendWLChat', [
            message,
            0,
            0])

    
    def sendSC(self, msgIndex):
        self.sendUpdate('sendSC', [
            msgIndex])

    
    def setTalkGroup(self, fromAv, fromAC, avatarName, chat, mods, flags):
        print 'Seige Manager- SetTalkGroup %s' % chat
        teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
        (message, scrubbed) = localAvatar.scrubTalk(chat, mods)
        base.talkAssistant.receiveShipPVPMessage(fromAv, fromAC, avatarName, teamName, message, scrubbed)

    
    def recvChat(self, avatarId, message, chatFlags, DISLid, name):
        teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
        if not self.cr.avatarFriendsManager.checkIgnored(avatarId):
            displayMess = '%s %s %s' % (name, self.getPVPChatTeamName(localAvatar.getSiegeTeam()), message)
            base.talkAssistant.receiveShipPVPMessage(avatarId, DISLid, name, teamName, message)
        

    
    def recvWLChat(self, avatarId, message, chatFlags, DISLid, name):
        teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
        if not self.cr.avatarFriendsManager.checkIgnored(avatarId):
            displayMess = '%s %s %s' % (name, self.getPVPChatTeamName(localAvatar.getSiegeTeam()), message)
            base.talkAssistant.receiveShipPVPMessage(avatarId, DISLid, name, teamName, message)
        

    
    def recvSpeedChat(self, avatarId, msgIndex, name):
        print 'siege manager recvSpeedChat'
        if not self.cr.avatarFriendsManager.checkIgnored(avatarId):
            displayMess = '%s %s %s' % (name, self.getPVPChatTeamName(localAvatar.getSiegeTeam()), SCDecoders.decodeSCStaticTextMsg(msgIndex))
            message = SCDecoders.decodeSCStaticTextMsg(msgIndex)
            teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
            base.talkAssistant.receiveShipPVPMessage(avatarId, 0, name, teamName, message)
        

    
    def sendSCQuest(self, questInt, msgType, taskNum):
        self.sendUpdate('sendSCQuest', [
            questInt,
            msgType,
            taskNum])

    
    def recvSCQuest(self, avName, senderId, questInt, msgType, taskNum):
        senderName = avName
        message = base.talkAssistant.SCDecoder.decodeSCQuestMsgInt(questInt, msgType, taskNum)
        if not self.cr.avatarFriendsManager.checkIgnored(senderId):
            teamName = self.getPVPChatTeamName(localAvatar.getSiegeTeam())
            displayMess = '%s %s %s' % (avName, teamName, message)
            base.talkAssistant.receiveShipPVPMessage(senderId, 0, avName, teamName, message)
        

    
    def getPVPChatTeamName(self, teamId):
        if teamId == 2:
            return PLocalizer.PVPSpanish
        elif teamId == 1:
            return PLocalizer.PVPFrench
        else:
            return PLocalizer.PVPPrefix

    
    def _addAnnouncerInterest(self):
        if not self._announcerInterest:
            self._announcerInterest = self.cr.addTaggedInterest(self.doId, self.ANNOUNCER_ZONE, self.cr.ITAG_GAME, 'siegeAnnouncer')
        

    
    def _removeAnnouncerInterest(self):
        if self._announcerInterest:
            self.cr.removeTaggedInterest(self._announcerInterest)
            self._announcerInterest = None
        

    
    def _setSiegeTeam(self, siegeTeam):
        if siegeTeam and not (self._siegeTeam):
            self._addAnnouncerInterest()
        elif not siegeTeam and self._siegeTeam:
            self._removeAnnouncerInterest()
        
        self._siegeTeam = siegeTeam
コード例 #17
0
class TaskProfiler:
    # this does intermittent profiling of tasks running on the system
    # if a task has a spike in execution time, the profile of the spike is logged
    notify = directNotify.newCategory("TaskProfiler")

    def __init__(self):
        self._enableFC = FunctionCall(self._setEnabled, taskMgr.getProfileTasksSV())
        self._enableFC.pushCurrentState()
        # table of task name pattern to TaskTracker
        self._namePrefix2tracker = {}
        self._task = None

    def destroy(self):
        if taskMgr.getProfileTasks():
            self._setEnabled(False)
        self._enableFC.destroy()
        for tracker in self._namePrefix2tracker.itervalues():
            tracker.destroy()
        del self._namePrefix2tracker
        del self._task

    @staticmethod
    def GetDefaultSpikeThreshold():
        return config.GetFloat('profile-task-spike-threshold', 5.)

    @staticmethod
    def SetSpikeThreshold(spikeThreshold):
        TaskTracker.SpikeThreshold = spikeThreshold
    @staticmethod
    def GetSpikeThreshold():
        return TaskTracker.SpikeThreshold

    def logProfiles(self, name=None):
        if name:
            name = name.lower()
        for namePrefix, tracker in self._namePrefix2tracker.iteritems():
            if (name and (name not in namePrefix.lower())):
                continue
            tracker.log()

    def flush(self, name):
        if name:
            name = name.lower()
        # flush stored task profiles
        for namePrefix, tracker in self._namePrefix2tracker.iteritems():
            if (name and (name not in namePrefix.lower())):
                continue
            tracker.flush()

    def _setEnabled(self, enabled):
        if enabled:
            self.notify.info('task profiler started')
            self._taskName = 'profile-tasks-%s' % id(self)
            taskMgr.add(self._doProfileTasks, self._taskName, priority=-200)
        else:
            taskMgr.remove(self._taskName)
            del self._taskName
            self.notify.info('task profiler stopped')

    def _doProfileTasks(self, task=None):
        # gather data from the previous frame
        # set up for the next frame
        if (self._task is not None) and taskMgr._hasProfiledDesignatedTask():
            session = taskMgr._getLastTaskProfileSession()
            # if we couldn't profile, throw this result out
            if session.profileSucceeded():
                namePrefix = self._task.getNamePrefix()
                if namePrefix not in self._namePrefix2tracker:
                    self._namePrefix2tracker[namePrefix] = TaskTracker(namePrefix)
                tracker = self._namePrefix2tracker[namePrefix]
                tracker.addProfileSession(session)

        # set up the next task
        self._task = taskMgr._getRandomTask()
        taskMgr._setProfileTask(self._task)

        return task.cont
コード例 #18
0
class TaskProfiler():
    __module__ = __name__
    notify = directNotify.newCategory('TaskProfiler')

    def __init__(self):
        self._enableFC = FunctionCall(self._setEnabled, taskMgr.getProfileTasksSV())
        self._enableFC.pushCurrentState()
        self._namePrefix2tracker = {}
        self._task = None
        return

    def destroy(self):
        if taskMgr.getProfileTasks():
            self._setEnabled(False)
        self._enableFC.destroy()
        for tracker in self._namePrefix2tracker.itervalues():
            tracker.destroy()

        del self._namePrefix2tracker
        del self._task

    @staticmethod
    def GetDefaultSpikeThreshold():
        return config.GetFloat('profile-task-spike-threshold', 5.0)

    @staticmethod
    def SetSpikeThreshold(spikeThreshold):
        TaskTracker.SpikeThreshold = spikeThreshold

    @staticmethod
    def GetSpikeThreshold():
        return TaskTracker.SpikeThreshold

    def logProfiles(self, name = None):
        if name:
            name = name.lower()
        for namePrefix, tracker in self._namePrefix2tracker.iteritems():
            if name and name not in namePrefix.lower():
                continue
            tracker.log()

    def flush(self, name):
        if name:
            name = name.lower()
        for namePrefix, tracker in self._namePrefix2tracker.iteritems():
            if name and name not in namePrefix.lower():
                continue
            tracker.flush()

    def _setEnabled(self, enabled):
        if enabled:
            self.notify.info('task profiler started')
            self._taskName = 'profile-tasks-%s' % id(self)
            taskMgr.add(self._doProfileTasks, self._taskName, priority=-200)
        else:
            taskMgr.remove(self._taskName)
            del self._taskName
            self.notify.info('task profiler stopped')

    def _doProfileTasks(self, task = None):
        if self._task is not None and taskMgr._hasProfiledDesignatedTask():
            session = taskMgr._getLastTaskProfileSession()
            if session.profileSucceeded():
                namePrefix = self._task.getNamePrefix()
                if namePrefix not in self._namePrefix2tracker:
                    self._namePrefix2tracker[namePrefix] = TaskTracker(namePrefix)
                tracker = self._namePrefix2tracker[namePrefix]
                tracker.addProfileSession(session)
        self._task = taskMgr._getRandomTask()
        taskMgr._setProfileTask(self._task)
        return task.cont