class DistributedPicnicTable(DistributedNode.DistributedNode): def __init__(self, cr): self.cr = cr NodePath.__init__(self, 'DistributedPicnicTable') DistributedNode.DistributedNode.__init__(self, cr) self.reparentTo(render) self.picnicTable = loader.loadModel('phase_6/models/golf/game_table') self.picnicTable.reparentTo(self) self.picnicTableSphereNodes = [] self.numSeats = 6 self.seats = [] self.jumpOffsets = [] self.inGame = False self.requestSeat = None self.gameState = None self.cameraBoardTrack = Func(self.doNothing) self.seatBumpForObserve = 0 self.winTrack = Sequence() self.outTrack = Sequence() self.joinButton = None self.observeButton = None self.tutorialButton = None self.exitButton = None self.isPlaying = False self.gameMenu = None self.game = None self.gameZone = None self.tutorial = None self.timerFunc = None self.gameDoId = None self.gameWantTimer = False self.tableState = [None, None, None, None, None, None] self.haveAnimated = [] self.winSound = base.loadSfx('phase_6/audio/sfx/KART_Applause_1.ogg') self.happyDance = base.loadSfx('phase_5/audio/sfx/AA_heal_happydance.ogg') self.accept('stoppedAsleep', self.handleSleep) base.localAvatar.startSleepWatch(self.handleSleep) self.__toonTracks = {} self.fsm = ClassicFSM.ClassicFSM('PicnicTable', [State.State('off', self.enterOff, self.exitOff, ['chooseMode', 'observing']), State.State('chooseMode', self.enterChooseMode, self.exitChooseMode, ['sitting', 'off', 'observing']), State.State('sitting', self.enterSitting, self.exitSitting, ['off']), State.State('observing', self.enterObserving, self.exitObserving, ['off'])], 'off', 'off') self.fsm.enterInitialState() for i in range(self.numSeats): self.seats.append(self.picnicTable.find('**/*seat%d' % (i + 1))) self.jumpOffsets.append(self.picnicTable.find('**/*jumpOut%d' % (i + 1))) self.tableCloth = self.picnicTable.find('**/basket_locator') self.tableclothSphereNode = self.tableCloth.attachNewNode(CollisionNode('tablecloth_sphere')) self.tableclothSphereNode.node().addSolid(CollisionSphere(0, 0, -2, 5.5)) self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) for i in range(self.numSeats): self.picnicTableSphereNodes.append(self.seats[i].attachNewNode(CollisionNode('picnicTable_sphere_%d_%d' % (self.getDoId(), i)))) self.picnicTableSphereNodes[i].node().addSolid(CollisionSphere(0, 0, 0, 2)) self.tableState = [None, None, None, None, None, None] self.requestTableState() self.buttonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui') self.upButton = self.buttonModels.find('**//InventoryButtonUp') self.downButton = self.buttonModels.find('**/InventoryButtonDown') self.rolloverButton = self.buttonModels.find('**/InventoryButtonRollover') angle = self.getH() angle -= 90 radAngle = deg2Rad(angle) unitVec = Vec3(math.cos(radAngle), math.sin(radAngle), 0) unitVec *= 30.0 self.endPos = self.getPos() + unitVec dist = Vec3(self.endPos - self.getPos()).length() wheelAngle = dist / (0.7 * math.pi) * 360 self.__enableCollisions() def handleSleep(self, task = None): if self.fsm.getCurrentState().getName() == 'chooseMode': self.cancelButtonPushed() elif self.fsm.getCurrentState().getName() == 'sitting': self.sendUpdate('requestExit', []) if self.gameMenu != None: self.gameMenu.removeButtons() self.gameMenu.picnicFunction = None self.gameMenu = None if task != None: task.done def disable(self): DistributedNode.DistributedNode.disable(self) self.ignore('stoppedAsleep') self.clearToonTracks() self.__disableCollisions() self.disableChoiceButtons() self.picnicTable.removeNode() self.cameraBoardTrack = None def delete(self): self.__disableCollisions() self.ignore('stoppedAsleep') DistributedNode.DistributedNode.delete(self) self.disableChoiceButtons() self.cameraBoardTrack = None del self.winTrack del self.outTrack self.fsm = None self.gameZone = None self.clearToonTracks() self.cameraBoardTrack = None def setName(self, name): self.name = name def setGameDoId(self, doId): self.gameDoId = doId self.game = self.cr.doId2do[doId] self.game.setHpr(self.getHpr()) self.gameWantTimer = self.game.wantTimer if self.gameState == 1: self.game.fsm.request('playing') def setTimerFunc(self, function): self.timerFunc = function def setTimer(self, timerEnd): self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) self.timeLeft = int(time - globalClock.getRealTime()) if self.gameWantTimer and self.game != None: self.showTimer() def showTimer(self): self.clockNode.stop() self.clockNode.countdown(self.timeLeft, self.timerFunc) self.clockNode.show() def requestTableState(self): self.sendUpdate('requestTableState', []) def setTableState(self, tableStateList, isplaying): y = 0 print 'SET TABLE STATE' if isplaying == 0: self.isPlaying = False else: self.isPlaying = True for x in tableStateList: if x != 0: if x not in self.tableState and self.cr.doId2do.has_key(x) and x not in self.haveAnimated: seatIndex = tableStateList.index(x) toon = self.cr.doId2do[x] toon.stopSmooth() toon.setAnimState('Sit', 1.0) dest = self.seats[seatIndex].getPos(self.tableCloth) hpr = self.seats[seatIndex].getHpr(render) toon.setHpr(hpr) if seatIndex > 2: toon.setH(self.getH() + 180) toon.wrtReparentTo(self) toon.setPos(dest) toon.setZ(toon.getZ() + 1.35) if seatIndex > 2: toon.setY(toon.getY() - 1.0) else: toon.setY(toon.getY() + 1.0) if x != 0: self.tableState[y] = x else: self.tableState[y] = None y += 1 numPlayers = 0 for x in self.tableState: if x != None: numPlayers += 1 print ' GETTING 2', self.gameMenu, numPlayers if self.gameMenu: if numPlayers > 2: print ' GETTING HERE!!' self.gameMenu.FindFour.setColor(0.7, 0.7, 0.7, 0.7) self.gameMenu.FindFour['command'] = self.doNothing self.gameMenu.findFourText['fg'] = (0.7, 0.7, 0.7, 0.7) self.gameMenu.Checkers.setColor(0.7, 0.7, 0.7, 0.7) self.gameMenu.Checkers['command'] = self.doNothing self.gameMenu.checkersText['fg'] = (0.7, 0.7, 0.7, 0.7) def setIsPlaying(self, isPlaying): if isPlaying == 0: self.isPlaying = False elif isPlaying == 1: self.isPlaying = True def announceWinner(self, winString, avId): if avId == base.localAvatar.getDoId(): sound = Sequence(Wait(2.0), Parallel(SoundInterval(self.winSound), SoundInterval(self.happyDance))) sound.start() base.cr.playGame.getPlace().setState('walk') if winString == 'Chinese Checkers': whisper = WhisperPopup(TTLocalizer.ChineseCheckersYouWon, OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif winString == 'Checkers': whisper = WhisperPopup(TTLocalizer.RegularCheckersYouWon, OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif winString == 'Find Four': whisper = WhisperPopup('You won a game of Find Four!', OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif self.cr.doId2do.has_key(avId): stateString = self.fsm.getCurrentState().getName() if stateString == 'sitting' or stateString == 'observing': base.cr.playGame.getPlace().setState('walk') av = self.cr.doId2do[avId] if winString == 'Chinese Checkers': whisper = WhisperPopup(av.getName() + TTLocalizer.ChineseCheckersGameOf + TTLocalizer.ChineseCheckers, OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif winString == 'Checkers': whisper = WhisperPopup(av.getName() + TTLocalizer.RegularCheckersGameOf + TTLocalizer.RegularCheckers, OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif winString == 'Find Four': whisper = WhisperPopup(av.getName() + ' has won a game of' + ' Find Four!', OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) if self.cr.doId2do.has_key(avId): toon = self.cr.doId2do[avId] self.winTrack = Sequence(autoFinish=1) if self.outTrack.isPlaying(): self.winTrack.append(Wait(2.0)) if avId == base.localAvatar.getDoId(): self.winTrack.append(Func(self.stopToWalk)) self.winTrack.append(ActorInterval(toon, 'happy-dance')) if avId == base.localAvatar.getDoId(): self.winTrack.append(Func(self.allowToWalk)) self.winTrack.start() whisper.manage(base.marginManager) def handleEnterPicnicTableSphere(self, i, collEntry): self.notify.debug('Entering Picnic Table Sphere.... %s' % self.getDoId()) self.requestSeat = i self.seatBumpForObserve = i self.fsm.request('chooseMode') def enableChoiceButtons(self): if self.tableState[self.seatBumpForObserve] == None and self.isPlaying == False: self.joinButton = DirectButton(relief=None, text=TTLocalizer.PicnicTableJoinButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0, 0, 0.8), scale=0.15, command=lambda self = self: self.joinButtonPushed()) if self.isPlaying: self.observeButton = DirectButton(relief=None, text=TTLocalizer.PicnicTableObserveButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0, 0, 0.6), scale=0.15, command=lambda self = self: self.observeButtonPushed()) self.exitButton = DirectButton(relief=None, text=TTLocalizer.PicnicTableCancelButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(1, 0, 0.6), scale=0.15, command=lambda self = self: self.cancelButtonPushed()) self.tutorialButton = DirectButton(relief=None, text=TTLocalizer.PicnicTableTutorial, text_fg=(1, 1, 0.65, 1), text_pos=(-0.05, -0.13), text_scale=0.55, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-1, 0, 0.6), scale=0.15, command=lambda self = self: self.tutorialButtonPushed()) base.cr.playGame.getPlace().setState('stopped') def tutorialButtonPushed(self): self.disableChoiceButtons() self.gameMenu = GameMenu(self.tutorialFunction, 1) self.tutorialButton.destroy() self.tutorialButton = None def tutorialFunction(self, tutVal): if tutVal == 1: self.tutorial = ChineseTutorial(self.tutorialDone) elif tutVal == 2: self.tutorial = CheckersTutorial(self.tutorialDone) self.gameMenu.picnicFunction = None self.gameMenu = None def tutorialDone(self): self.requestSeat = None self.fsm.request('off') self.tutorial = None def joinButtonPushed(self): toon = base.localAvatar self.sendUpdate('requestJoin', [self.requestSeat, toon.getX(), toon.getY(), toon.getZ(), toon.getH(), toon.getP(), toon.getR()]) self.requestSeat = None self.fsm.request('sitting') def rejectJoin(self): self.fsm.request('off') self.allowToWalk() def cancelButtonPushed(self): base.cr.playGame.getPlace().setState('walk') self.requestSeat = None self.fsm.request('off') def disableChoiceButtons(self): if self.joinButton: self.joinButton.destroy() if self.observeButton: self.observeButton.destroy() if self.exitButton: self.exitButton.destroy() if self.tutorialButton: self.tutorialButton.destroy() def pickFunction(self, gameNum): if gameNum == 1: self.sendUpdate('requestPickedGame', [gameNum]) elif gameNum == 2: self.sendUpdate('requestPickedGame', [gameNum]) elif gameNum == 3: self.sendUpdate('requestPickedGame', [gameNum]) def allowPick(self): self.gameMenu = GameMenu(self.pickFunction, 2) def setZone(self, zoneId): if self.fsm.getCurrentState().getName() == 'sitting' or self.fsm.getCurrentState().getName() == 'observing': if self.tutorial == None: self.gameZone = base.cr.addInterest(base.localAvatar.defaultShard, zoneId, 'gameBoard') if self.gameMenu != None: self.gameMenu.removeButtons() self.gameMenu.picnicFunction = None self.gameMenu = None def fillSlot(self, avId, index, x, y, z, h, p, r, timestamp, parentDoId): self.notify.debug('fill Slot: %d for %d' % (index, avId)) if avId not in self.haveAnimated: self.haveAnimated.append(avId) if avId == base.localAvatar.getDoId(): if self.inGame: return self.inGame = True self.seatPos = index if self.cr.doId2do.has_key(avId): toon = self.cr.doId2do[avId] toon.stopSmooth() toon.wrtReparentTo(self.tableCloth) sitStartDuration = toon.getDuration('sit-start') jumpTrack = self.generateToonJumpTrack(toon, index) track = Sequence(autoFinish=1) if avId == base.localAvatar.getDoId(): if not base.cr.playGame.getPlace() == None: self.moveCamera(index) track.append(Func(self.__disableCollisions)) track.append(jumpTrack) track.append(Func(toon.setAnimState, 'Sit', 1.0)) track.append(Func(self.clearToonTrack, avId)) self.storeToonTrack(avId, track) track.start() def emptySlot(self, avId, index, timestamp): self.notify.debug('### seat %s now empty' % index) if index == 255 and self.game != None: self.stopObserveButtonPushed() return if avId in self.haveAnimated: self.haveAnimated.remove(avId) if self.cr.doId2do.has_key(avId): if avId == base.localAvatar.getDoId(): if self.gameZone: base.cr.removeInterest(self.gameZone) if self.inGame: self.inGame = False else: return toon = self.cr.doId2do[avId] toon.stopSmooth() sitStartDuration = toon.getDuration('sit-start') jumpOutTrack = self.generateToonReverseJumpTrack(toon, index) self.outTrack = Sequence(jumpOutTrack) if base.localAvatar.getDoId() == avId: self.outTrack.append(Func(self.__enableCollisions)) self.outTrack.append(Func(self.allowToWalk)) self.fsm.request('off') val = self.jumpOffsets[index].getPos(render) self.outTrack.append(Func(toon.setPos, val)) self.outTrack.append(Func(toon.startSmooth)) self.outTrack.start() def stopToWalk(self): base.cr.playGame.getPlace().setState('stopped') def allowToWalk(self): base.cr.playGame.getPlace().setState('walk') def moveCamera(self, seatIndex): self.oldCameraPos = camera.getPos() self.oldCameraHpr = camera.getHpr() camera.wrtReparentTo(self.picnicTable) heading = PythonUtil.fitDestAngle2Src(camera.getH(), 90) if seatIndex < 3: self.cameraBoardTrack = LerpPosHprInterval(camera, 2.0, Point3(0, 0, 17), Point3(0, -90, 0)) elif camera.getH() < 0: self.cameraBoardTrack = LerpPosHprInterval(camera, 2.0, Point3(0, 0, 17), Point3(-180, -90, 0)) else: self.cameraBoardTrack = LerpPosHprInterval(camera, 2.0, Point3(0, 0, 17), Point3(180, -90, 0)) self.cameraBoardTrack.start() def moveCameraBack(self): self.cameraBoardTrack = LerpPosHprInterval(camera, 2.5, self.oldCameraPos, self.oldCameraHpr) self.cameraBoardTrack.start() def __enableCollisions(self): for i in range(self.numSeats): self.accept('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTableSphere, [i]) self.picnicTableSphereNodes[i].setCollideMask(ToontownGlobals.WallBitmask) self.tableclothSphereNode.setCollideMask(ToontownGlobals.WallBitmask) def __disableCollisions(self): for i in range(self.numSeats): self.ignore('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i)) self.ignore('enterPicnicTableOK_%d_%d' % (self.getDoId(), i)) for i in range(self.numSeats): self.picnicTableSphereNodes[i].setCollideMask(BitMask32(0)) self.tableclothSphereNode.setCollideMask(BitMask32(0)) def enterOff(self): base.setCellsAvailable(base.leftCells + base.bottomCells, 0) def exitOff(self): base.setCellsAvailable(base.bottomCells, 0) def enterChooseMode(self): self.winTrack = Sequence(autoFinish=1) self.enableChoiceButtons() def exitChooseMode(self): self.disableChoiceButtons() def enterObserving(self): self.enableStopObserveButton() self.moveCamera(self.seatBumpForObserve) self.sendUpdate('requestGameZone') def exitObserving(self): if self.cameraBoardTrack.isPlaying(): self.cameraBoardTrack.pause() self.allowToWalk() self.stopObserveButton.destroy() def enterSitting(self): pass def exitSitting(self): self.gameMenu = None def setGameZone(self, zoneId, gamestate): self.gameZone = base.cr.addInterest(base.localAvatar.defaultShard, zoneId, 'gameBoard') self.gameState = gamestate def observeButtonPushed(self): self.requestSeat = None self.fsm.request('observing') def enableStopObserveButton(self): self.stopObserveButton = DirectButton(relief=None, text='Stop Observing', text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.45, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0.92, 0, 0.4), scale=0.15, command=lambda self = self: self.stopObserveButtonPushed()) def stopObserveButtonPushed(self): self.sendUpdate('leaveObserve', []) self.gameState = None if self.game: self.game.fsm.request('gameOver') base.cr.removeInterest(self.gameZone) self.fsm.request('off') def generateToonReverseJumpTrack(self, av, seatIndex): self.notify.debug('av.getH() = %s' % av.getH()) def getToonJumpTrack(av, destNode): def getJumpDest(av = av, node = destNode): dest = node.getPos(self.tableCloth) dest += self.jumpOffsets[seatIndex].getPos(self.tableCloth) return dest def getJumpHpr(av = av, node = destNode): hpr = node.getHpr(av.getParent()) hpr.setX(hpr.getX() + 180) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel(ActorInterval(av, 'jump'), Sequence(Wait(0.1), Parallel(ProjectileInterval(av, endPos=getJumpDest, duration=0.9)))) return toonJumpTrack toonJumpTrack = getToonJumpTrack(av, self.tableCloth) jumpTrack = Sequence(toonJumpTrack, Func(av.loop, 'neutral'), Func(av.wrtReparentTo, render)) return jumpTrack def generateToonJumpTrack(self, av, seatIndex): av.pose('sit', 47) hipOffset = av.getHipsParts()[2].getPos(av) def getToonJumpTrack(av, seatIndex): def getJumpDest(av = av, node = self.tableCloth): dest = Vec3(self.tableCloth.getPos(av.getParent())) seatNode = self.picnicTable.find('**/seat' + str(seatIndex + 1)) dest += seatNode.getPos(self.tableCloth) dna = av.getStyle() dest -= hipOffset if seatIndex > 2: dest.setY(dest.getY() - 2.0) if seatIndex == 1: dest.setY(dest.getY() - 0.5) dest.setZ(dest.getZ() + 0.2) return dest def getJumpHpr(av = av, node = self.tableCloth): hpr = self.seats[seatIndex].getHpr(av.getParent()) if seatIndex < 3: hpr.setX(hpr.getX()) elif av.getH() < 0: hpr.setX(hpr.getX() - 180) else: hpr.setX(hpr.getX() + 180) return hpr toonJumpTrack = Parallel(ActorInterval(av, 'jump'), Sequence(Wait(0.43), Parallel(LerpHprInterval(av, hpr=getJumpHpr, duration=1), ProjectileInterval(av, endPos=getJumpDest, duration=1)))) return toonJumpTrack def getToonSitTrack(av): toonSitTrack = Sequence(ActorInterval(av, 'sit-start'), Func(av.loop, 'sit')) return toonSitTrack toonJumpTrack = getToonJumpTrack(av, seatIndex) toonSitTrack = getToonSitTrack(av) jumpTrack = Sequence(Parallel(toonJumpTrack, Sequence(Wait(1), toonSitTrack)), Func(av.wrtReparentTo, self.tableCloth)) return jumpTrack def storeToonTrack(self, avId, track): self.clearToonTrack(avId) self.__toonTracks[avId] = track def clearToonTrack(self, avId): oldTrack = self.__toonTracks.get(avId) if oldTrack: oldTrack.pause() DelayDelete.cleanupDelayDeletes(oldTrack) def clearToonTracks(self): keyList = [] for key in self.__toonTracks: keyList.append(key) for key in keyList: if self.__toonTracks.has_key(key): self.clearToonTrack(key) def doNothing(self): pass
class DistributedPicnicTable(DistributedNode.DistributedNode): def __init__(self, cr): self.cr = cr NodePath.__init__(self, "DistributedPicnicTable") DistributedNode.DistributedNode.__init__(self, cr) self.reparentTo(render) self.picnicTable = loader.loadModel( "phase_6/models/golf/game_table.bam") self.picnicTable.reparentTo(self) self.picnicTableSphereNodes = [] self.numSeats = 6 self.seats = [] self.jumpOffsets = [] self.inGame = False self.requestSeat = None self.gameState = None #self.mypos = self.getPos() self.cameraBoardTrack = Func(self.doNothing) self.seatBumpForObserve = 0 self.winTrack = Sequence() self.outTrack = Sequence() self.joinButton = None self.observeButton = None self.tutorialButton = None self.exitButton = None self.isPlaying = False self.gameMenu = None self.game = None self.gameZone = None self.tutorial = None self.timerFunc = None self.gameDoId = None #self.game = None self.gameWantTimer = False self.tableState = [None, None, None, None, None, None] self.haveAnimated = [] self.winSound = base.loadSfx("phase_6/audio/sfx/KART_Applause_1.mp3") self.happyDance = base.loadSfx( "phase_5/audio/sfx/AA_heal_happydance.mp3") #Seems like these functions BOTH are required #To intercept the sleep event. #Important to take action when GUI elements are up to turn #them off when the avatar goes to sleep otherwise the wakeup will allow #him to run around with the gui up. self.accept('stoppedAsleep', self.handleSleep) base.localAvatar.startSleepWatch(self.handleSleep) self.__toonTracks = {} self.fsm = ClassicFSM.ClassicFSM( 'PicnicTable', [ State.State('off', self.enterOff, self.exitOff, ['chooseMode', 'observing']), State.State('chooseMode', self.enterChooseMode, self.exitChooseMode, ['sitting', 'off', 'observing']), State.State('sitting', self.enterSitting, self.exitSitting, ['off']), State.State('observing', self.enterObserving, self.exitObserving, ['off']) ], #start state 'off', #final state` 'off', ) self.fsm.enterInitialState() #Go find all of the locators for seats and jumpout locators for i in range(self.numSeats): self.seats.append(self.picnicTable.find("**/*seat%d" % (i + 1))) self.jumpOffsets.append( self.picnicTable.find("**/*jumpOut%d" % (i + 1))) self.tableCloth = self.picnicTable.find("**/basket_locator") #Stops you from walking on the table self.tableclothSphereNode = self.tableCloth.attachNewNode( CollisionNode('tablecloth_sphere')) self.tableclothSphereNode.node().addSolid( CollisionSphere(0, 0, -2, 5.5)) self.clockNode = ToontownTimer() self.clockNode.setPos(1.16, 0, -0.83) self.clockNode.setScale(0.3) self.clockNode.hide() def announceGenerate(self): DistributedNode.DistributedNode.announceGenerate(self) #Set up the collision spheres for the seats for i in range(self.numSeats): self.picnicTableSphereNodes.append(self.seats[i].attachNewNode( CollisionNode('picnicTable_sphere_%d_%d' % (self.getDoId(), i)))) self.picnicTableSphereNodes[i].node().addSolid( CollisionSphere(0, 0, 0, 2)) #sit everyone down self.tableState = [None, None, None, None, None, None] self.requestTableState() self.buttonModels = loader.loadModel( "phase_3.5/models/gui/inventory_gui") self.upButton = self.buttonModels.find("**//InventoryButtonUp") self.downButton = self.buttonModels.find("**/InventoryButtonDown") self.rolloverButton = self.buttonModels.find( "**/InventoryButtonRollover") #self.picnicTable.setScale(.030) #Preprocessing for Jump into seat Arcs (bad to do at runtime) angle = self.getH() angle -= 90 radAngle = deg2Rad(angle) unitVec = Vec3(math.cos(radAngle), math.sin(radAngle), 0) unitVec *= 30.0 self.endPos = self.getPos() + unitVec dist = Vec3(self.endPos - self.getPos()).length() wheelAngle = dist / (0.5 * 1.4 * math.pi) * 360 self.__enableCollisions() def handleSleep(self, task=None): #print "GETTING TO SLEEP!!!" if self.fsm.getCurrentState().getName() == "chooseMode": self.cancelButtonPushed() elif self.fsm.getCurrentState().getName() == "sitting": self.sendUpdate("requestExit", []) if self.gameMenu != None: self.gameMenu.removeButtons() self.gameMenu.picnicFunction = None self.gameMenu = None if task != None: task.done #task.done def disable(self): DistributedNode.DistributedNode.disable(self) self.ignore('stoppedAsleep') self.clearToonTracks() self.__disableCollisions() self.disableChoiceButtons() #del self.picnicTableSphereNodes self.picnicTable.removeNode() self.cameraBoardTrack = None #self.fsm = None #self.winTrack.finish() #self.outTrack.finish() #self.outTrack = None def delete(self): self.__disableCollisions() self.ignore('stoppedAsleep') DistributedNode.DistributedNode.delete(self) self.disableChoiceButtons() self.cameraBoardTrack = None #self.winTrack.finish() #self.outTrack.finish() #self.winTrack = None #self.outTrack = None del self.winTrack del self.outTrack self.fsm = None self.gameZone = None self.clearToonTracks() self.cameraBoardTrack = None #self.clearToonTrack() #print " I AM DELETEING \n\n\n\n\n\n\n\n\n" #self.outTrack = None #del self def setName(self, name): self.name = name ################ ##SetGameDoID - # This function is called by the child game after it is generated, in order #to set up the cross references that are needed to handle certain events #IE (getting up, erroneous disconnects ect.) def setGameDoId(self, doId): self.gameDoId = doId self.game = self.cr.doId2do[doId] self.game.setHpr(self.getHpr()) self.gameWantTimer = self.game.wantTimer if self.gameState == 1: self.game.fsm.request('playing') ########## ##Timer Functions #setTimer (required broadcast ram) # #These are the timer functions that dictate movement and visual timer #feedback in the game table and chinese checkers. # ########## def setTimerFunc(self, function): self.timerFunc = function def setTimer(self, timerEnd): self.clockNode.stop() time = globalClockDelta.networkToLocalTime(timerEnd) self.timeLeft = int(time - globalClock.getRealTime()) if self.gameWantTimer and self.game != None: self.showTimer() def showTimer(self): #important to stop the timer before you reset it, otherwise it may still be running self.clockNode.stop() self.clockNode.countdown(self.timeLeft, self.timerFunc) self.clockNode.show() ########## #setTableState (required ram broadcast) # #This functions primary purpose is to handle asynchrinous joins of the zone #if an avatar teleports in, he needs to have a state of the table so he #can animate the toons to be sitting down in their corresponding seats ########## def requestTableState(self): self.sendUpdate("requestTableState", []) def setTableState(self, tableStateList, isplaying): y = 0 print "SET TABLE STATE" if isplaying == 0: self.isPlaying = False else: self.isPlaying = True for x in tableStateList: if x != 0: # If we are to sit him down, make sure that he has not already been animated by fillslot # (deltas are handled by that function) if not x in self.tableState and self.cr.doId2do.has_key( x) and x not in self.haveAnimated: seatIndex = tableStateList.index(x) toon = self.cr.doId2do[x] toon.stopSmooth() toon.setAnimState("Sit", 1.0) dest = self.seats[seatIndex].getPos(self.tableCloth) hpr = self.seats[seatIndex].getHpr(render) toon.setHpr(hpr) if (seatIndex > 2): toon.setH(self.getH() + 180) toon.wrtReparentTo(self) toon.setPos(dest) toon.setZ(toon.getZ() + 1.35) if (seatIndex > 2): toon.setY(toon.getY() - 1.0) else: toon.setY(toon.getY() + 1.0) if x != 0: self.tableState[y] = x else: self.tableState[y] = None y = y + 1 ###Handle the game menu stuffs numPlayers = 0 for x in self.tableState: if x != None: numPlayers += 1 #check for a game menu up print " GETTING 2", self.gameMenu, numPlayers if self.gameMenu: if numPlayers > 2: print " GETTING HERE!!" self.gameMenu.FindFour.setColor(.7, .7, .7, .7) self.gameMenu.FindFour['command'] = self.doNothing self.gameMenu.findFourText['fg'] = (.7, .7, .7, .7) self.gameMenu.Checkers.setColor(.7, .7, .7, .7) self.gameMenu.Checkers['command'] = self.doNothing self.gameMenu.checkersText['fg'] = (.7, .7, .7, .7) def setIsPlaying(self, isPlaying): if isPlaying == 0: self.isPlaying = False elif isPlaying == 1: self.isPlaying = True ########## ##announceWinner (broadcast) # #Obvious, simply just sets the whisper message ########## def announceWinner(self, winString, avId): if avId == base.localAvatar.getDoId(): sound = Sequence( Wait(2.0), Parallel(SoundInterval(self.winSound), SoundInterval(self.happyDance))) sound.start() base.cr.playGame.getPlace().setState( 'walk') #To stop Cohesion between EmptySlot and AnnounceWin if winString == "Chinese Checkers": whisper = WhisperPopup(TTLocalizer.ChineseCheckersYouWon, OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif winString == "Checkers": whisper = WhisperPopup(TTLocalizer.RegularCheckersYouWon, OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif winString == "Find Four": whisper = WhisperPopup("You won a game of Find Four!", OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) else: if self.cr.doId2do.has_key(avId): stateString = self.fsm.getCurrentState().getName() if stateString == "sitting" or stateString == "observing": base.cr.playGame.getPlace().setState( 'walk' ) #To stop Cohesion between EmptySlot and AnnounceWin av = self.cr.doId2do[avId] if winString == "Chinese Checkers": whisper = WhisperPopup( av.getName() + TTLocalizer.ChineseCheckersGameOf + TTLocalizer.ChineseCheckers, OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif winString == "Checkers": whisper = WhisperPopup( av.getName() + TTLocalizer.RegularCheckersGameOf + TTLocalizer.RegularCheckers, OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) elif winString == "Find Four": whisper = WhisperPopup( av.getName() + " has won a game of" + " Find Four!", OTPGlobals.getInterfaceFont(), WhisperPopup.WTNormal) if self.cr.doId2do.has_key(avId): # If the toon exists, look it up toon = self.cr.doId2do[avId] #self.winTrack.finish() self.winTrack = Sequence(autoFinish=1) if self.outTrack.isPlaying(): #If toon is jumping out Wait a self.winTrack.append( Wait(2.0)) # duration till his anim is over to begin if avId == base.localAvatar.getDoId(): #stop him from walking locally #otherwise he will animate around while moving on other clients self.winTrack.append(Func(self.stopToWalk)) self.winTrack.append(ActorInterval(toon, 'happy-dance')) if avId == base.localAvatar.getDoId(): self.winTrack.append(Func(self.allowToWalk)) self.winTrack.start() #Display the whisper message whisper.manage(base.marginManager) ########## #handleEnterPicnicTableSphere # #This is the function that via the messenger, handles the collision #with one of the six collision spheres on a picnic table ########## def handleEnterPicnicTableSphere(self, i, collEntry): assert self.notify.debugStateCall(self) #print "COLLISION!!!" self.notify.debug("Entering Picnic Table Sphere.... %s" % self.getDoId()) #if self.requestSeat == None: self.requestSeat = i self.seatBumpForObserve = i self.fsm.request('chooseMode') ########## #Button Logic (handled by handleEnterPicnicTableSphere, and self.fsm ### def enableChoiceButtons(self): if self.tableState[ self.seatBumpForObserve] == None and self.isPlaying == False: self.joinButton = DirectButton( relief=None, text=TTLocalizer.PicnicTableJoinButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0, 0, .8), scale=0.15, command=lambda self=self: self.joinButtonPushed(), ) if self.isPlaying == True: self.observeButton = DirectButton( relief=None, text=TTLocalizer.PicnicTableObserveButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(0, 0, 0.6), scale=0.15, command=lambda self=self: self.observeButtonPushed(), ) self.exitButton = DirectButton( relief=None, text=TTLocalizer.PicnicTableCancelButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.8, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(1, 0, 0.6), scale=0.15, command=lambda self=self: self.cancelButtonPushed(), ) self.tutorialButton = DirectButton( relief=None, text=TTLocalizer.PicnicTableTutorial, text_fg=(1, 1, 0.65, 1), text_pos=(-.05, -.13), text_scale=0.55, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-1, 0, 0.6), scale=0.15, command=lambda self=self: self.tutorialButtonPushed(), ) base.cr.playGame.getPlace().setState('stopped') def tutorialButtonPushed(self): #print "GETTING HERE!!!" self.disableChoiceButtons() #self.tutorial = ChineseTutorial(self.tutorialDone) self.gameMenu = GameMenu(self.tutorialFunction, 1) # 1 == Tutorial Num #self.tutorialFunction(1) self.tutorialButton.destroy() self.tutorialButton = None def tutorialFunction(self, tutVal): if tutVal == 1: self.tutorial = ChineseTutorial(self.tutorialDone) elif tutVal == 2: self.tutorial = CheckersTutorial(self.tutorialDone) self.gameMenu.picnicFunction = None self.gameMenu = None def tutorialDone(self): #del self.tutorial self.requestSeat = None self.fsm.request('off') self.tutorial = None #del self.tutorial def joinButtonPushed(self): toon = base.localAvatar self.sendUpdate("requestJoin", [ self.requestSeat, toon.getX(), toon.getY(), toon.getZ(), toon.getH(), toon.getP(), toon.getR() ]) self.requestSeat = None self.fsm.request('sitting') def rejectJoin(self): self.fsm.request('off') self.allowToWalk() def cancelButtonPushed(self): base.cr.playGame.getPlace().setState('walk') self.requestSeat = None self.fsm.request('off') def disableChoiceButtons(self): if self.joinButton: self.joinButton.destroy() if self.observeButton: self.observeButton.destroy() if self.exitButton: self.exitButton.destroy() if self.tutorialButton: self.tutorialButton.destroy() ########## #Distributed fillSlot Functions (broadcasT) # #These functions are the distributed functions that the ai sends to tell #the client if its ok for people to picnic table, and then animates them ########## def pickFunction(self, gameNum): #print "SENDING PICK!" if gameNum == 1: #Chinese Checkers self.sendUpdate('requestPickedGame', [gameNum]) elif gameNum == 2: self.sendUpdate('requestPickedGame', [gameNum]) elif gameNum == 3: self.sendUpdate('requestPickedGame', [gameNum]) def allowPick(self): self.gameMenu = GameMenu(self.pickFunction, 2) # 2 == pick Num for TTlocalizer #elf.pickFunction(1) def setZone(self, zoneId): #import pdb; pdb.set_trace() #print "ZONE iD == " , zoneId #print "CURRENT SATE?!?!? == ", self.fsm.getCurrentState().getName() #if self.fsm.getCurrentState().getName() == "chooseMode" or self.fsm.getCurrentState().getName() == "sitting": if self.fsm.getCurrentState().getName( ) == "sitting" or self.fsm.getCurrentState().getName() == "observing": if self.tutorial == None: self.gameZone = base.cr.addInterest( base.localAvatar.defaultShard, zoneId, 'gameBoard') if self.gameMenu != None: self.gameMenu.removeButtons() self.gameMenu.picnicFunction = None self.gameMenu = None def fillSlot(self, avId, index, x, y, z, h, p, r, timestamp, parentDoId): assert self.notify.debugStateCall(self) self.notify.debug("fill Slot: %d for %d" % (index, avId)) if not avId in self.haveAnimated: self.haveAnimated.append(avId) if avId == base.localAvatar.getDoId(): if self.inGame == True: return #in a game therefore we dont animate else: self.inGame = True self.seatPos = index pass #not in a game but need to animate into the game if self.cr.doId2do.has_key(avId): toon = self.cr.doId2do[avId] toon.stopSmooth() toon.wrtReparentTo(self.tableCloth) sitStartDuration = toon.getDuration("sit-start") jumpTrack = self.generateToonJumpTrack(toon, index) track = Sequence(autoFinish=1) if avId == base.localAvatar.getDoId(): if not base.cr.playGame.getPlace() == None: self.moveCamera(index) track.append(Func(self.__disableCollisions)) #self.gameZone = base.cr.addInterest(base.localAvatar.defaultShard, boardZoneId, 'chineseBoard') track.append(jumpTrack) track.append(Func(toon.setAnimState, "Sit", 1.0)) track.append(Func(self.clearToonTrack, avId)) self.storeToonTrack(avId, track) track.start() ########## #Empty Slot Distributed Functions (broadcast) # #Distributed functions that manage the toons getting off of the picnic #tables ########## def emptySlot(self, avId, index, timestamp): self.notify.debug("### seat %s now empty" % index) ##Player told to exit is an OBSERVER if index == 255 and self.game != None: self.stopObserveButtonPushed() return #self.fullSeat[index] = self.seatState.Empty if avId in self.haveAnimated: self.haveAnimated.remove(avId) # self.fullSeat[index] = self.seatState.Empty if self.cr.doId2do.has_key(avId): if avId == base.localAvatar.getDoId(): if self.gameZone: base.cr.removeInterest(self.gameZone) if self.inGame == True: #are in a game self.inGame = False else: return #dont animate because we are NOT in a game toon = self.cr.doId2do[avId] toon.stopSmooth() sitStartDuration = toon.getDuration("sit-start") jumpOutTrack = self.generateToonReverseJumpTrack(toon, index) #self.outTrack.finish() self.outTrack = Sequence(jumpOutTrack) if base.localAvatar.getDoId() == avId: self.outTrack.append(Func(self.__enableCollisions)) self.outTrack.append(Func( self.allowToWalk)) #temp until i can stop the #camera from jerking #self.outTrack.append(Func(self.fsm.request, 'off')) self.fsm.request('off') #self.outTrack.append(Func(self.tempCheckers.setHpr, 0, self.tempCheckers.getP(), self.tempCheckers.getR())) val = self.jumpOffsets[index].getPos(render) #self.storeToonTrack(avId, self.outTrack) self.outTrack.append(Func(toon.setPos, val)) self.outTrack.append(Func(toon.startSmooth)) self.outTrack.start() #self.outTrack = Sequence() def stopToWalk(self): base.cr.playGame.getPlace().setState("stopped") def allowToWalk(self): #if not self.winTrack.isPlaying(): base.cr.playGame.getPlace().setState("walk") #self.winTrack.finish() #self.winTrack = None ########## #Camera manipulations ########## def moveCamera(self, seatIndex): self.oldCameraPos = camera.getPos() self.oldCameraHpr = camera.getHpr() camera.wrtReparentTo(self.picnicTable) heading = PythonUtil.fitDestAngle2Src(camera.getH(), 90) #Need to check the seat index so the cameras *down #is towards the player so he is not facing his own character #rather he feels he is a bit above him if seatIndex < 3: self.cameraBoardTrack = LerpPosHprInterval(camera, 2.0, Point3(0, 0, 17), Point3(0, -90, 0)) else: #needed for camera orientation #If test is not here, the camera may often flip around #spinning ~340 degrees to the destination #instead of turning the 20 degrees towards the table if (camera.getH() < 0): #(turned left) self.cameraBoardTrack = LerpPosHprInterval( camera, 2.0, Point3(0, 0, 17), Point3(-180, -90, 0)) else: #(turned right) self.cameraBoardTrack = LerpPosHprInterval( camera, 2.0, Point3(0, 0, 17), Point3(180, -90, 0)) self.cameraBoardTrack.start() def moveCameraBack(self): self.cameraBoardTrack = LerpPosHprInterval(camera, 2.5, self.oldCameraPos, self.oldCameraHpr) self.cameraBoardTrack.start() ########## # Enable and Disable Collisions # #Turn on and off the collisions for the seat and table collision spheres for #boarding and unboarding, thus to actaully allow the toons to sit down, animate ect. ########## def __enableCollisions(self): # start listening for toons to enter. assert self.notify.debugStateCall(self) for i in range(self.numSeats): self.accept('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTableSphere, [i]) #self.accept('enterPicnicTableOK_%d_%d' % (self.getDoId(), i), self.handleEnterPicnicTable, [i]) self.picnicTableSphereNodes[i].setCollideMask( ToontownGlobals.WallBitmask) self.tableclothSphereNode.setCollideMask(ToontownGlobals.WallBitmask) def __disableCollisions(self): assert self.notify.debugStateCall(self) #self.ignore('tableClothSphereNode') for i in range(self.numSeats): self.ignore('enterpicnicTable_sphere_%d_%d' % (self.getDoId(), i)) self.ignore('enterPicnicTableOK_%d_%d' % (self.getDoId(), i)) for i in range(self.numSeats): self.picnicTableSphereNodes[i].setCollideMask(BitMask32(0)) self.tableclothSphereNode.setCollideMask(BitMask32(0)) ########## #FSM stuff ########## def enterOff(self): base.setCellsAvailable(base.leftCells + base.bottomCells, 0) def exitOff(self): base.setCellsAvailable(base.bottomCells, 0) def enterChooseMode(self): #self.requestTableState() self.winTrack = Sequence(autoFinish=1) self.enableChoiceButtons() def exitChooseMode(self): self.disableChoiceButtons() def enterObserving(self): self.enableStopObserveButton() self.moveCamera(self.seatBumpForObserve) #track.append(Func(self.__disableCollisions)) self.sendUpdate('requestGameZone') #self.gameZone = base.cr.addInterest(base.localAvatar.defaultShard, boardZoneId, 'chineseBoard') def exitObserving(self): #self.__enableCollisions if self.cameraBoardTrack.isPlaying(): self.cameraBoardTrack.pause() self.allowToWalk() #temp until i can stop the #camera from jerking self.stopObserveButton.destroy() def enterSitting(self): pass #self.tempCheckers.hide() def exitSitting(self): self.gameMenu = None #self.winTrack = None #self.tempCheckers.show() #self.suxButton.destroy() #self.sendUpdate('requestExit', []) ########## #Observer Functions setGameZone (broadcast) # #Need these because you are not "filling" a slot by observing # #For this case - When it sends a 1 or a zero with the setGameZone, This is to account for the fact #an observer can (and will) come into games halfway through, somehow that client needs to know #about the current state of the game. # # #1 == Playing #0 == Not Playing ########## def setGameZone(self, zoneId, gamestate): self.gameZone = base.cr.addInterest(base.localAvatar.defaultShard, zoneId, 'gameBoard') self.gameState = gamestate def observeButtonPushed(self): #base.cr.playGame.getPlace().setState('walk') self.requestSeat = None self.fsm.request('observing') def enableStopObserveButton(self): self.stopObserveButton = DirectButton( relief=None, text="Stop Observing", text_fg=(1, 1, 0.65, 1), text_pos=(0, -.23), text_scale=0.45, image=(self.upButton, self.downButton, self.rolloverButton), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(.92, 0, 0.4), scale=0.15, command=lambda self=self: self.stopObserveButtonPushed(), ) def stopObserveButtonPushed(self): self.sendUpdate("leaveObserve", []) self.gameState = None if self.game: self.game.fsm.request('gameOver') base.cr.removeInterest(self.gameZone) self.fsm.request('off') ########## #Generators for jumps # #And the storage/deletion functions for #handling them. ########## def generateToonReverseJumpTrack(self, av, seatIndex): """Return an interval of the toon jumping out of the golf kart.""" self.notify.debug("av.getH() = %s" % av.getH()) def getToonJumpTrack(av, destNode): # using a local func allows the ProjectileInterval to # calculate this pos at run-time def getJumpDest(av=av, node=destNode): dest = node.getPos(self.tableCloth) dest += self.jumpOffsets[seatIndex].getPos(self.tableCloth) return dest def getJumpHpr(av=av, node=destNode): hpr = node.getHpr(av.getParent()) hpr.setX(hpr.getX() + 180) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel( ActorInterval(av, 'jump'), Sequence( Wait(0.1), #43 ), Parallel( #LerpHprInterval( av, # hpr = getJumpHpr, # duration = .9 ), ProjectileInterval(av, endPos=getJumpDest, duration=.9)))) return toonJumpTrack toonJumpTrack = getToonJumpTrack(av, self.tableCloth) #self.seats[seatIndex]) jumpTrack = Sequence( toonJumpTrack, Func(av.loop, 'neutral'), Func(av.wrtReparentTo, render), #Func( self.av.setPosHpr, self.exitMovieNode, 0,0,0,0,0,0 ), ) return jumpTrack def generateToonJumpTrack(self, av, seatIndex): """Return an interval of the toon jumping into the golf kart.""" # Maintain a reference to Parent and Scale of avatar in case they # exit from the kart. #base.sb = self av.pose('sit', 47) hipOffset = av.getHipsParts()[2].getPos(av) def getToonJumpTrack(av, seatIndex): # using a local func allows the ProjectileInterval to # calculate this pos at run-time def getJumpDest(av=av, node=self.tableCloth): dest = Vec3(self.tableCloth.getPos(av.getParent())) seatNode = self.picnicTable.find("**/seat" + str(seatIndex + 1)) dest += seatNode.getPos(self.tableCloth) dna = av.getStyle() dest -= hipOffset if (seatIndex > 2): dest.setY(dest.getY() - 2.0) if (seatIndex == 1): dest.setY(dest.getY() - .5) #dest.setY( dest.getY() + 2 * hipOffset.getY()) #dest.setY(dest.getY()) dest.setZ(dest.getZ() + 0.2) return dest def getJumpHpr(av=av, node=self.tableCloth): hpr = self.seats[seatIndex].getHpr(av.getParent()) if (seatIndex < 3): hpr.setX(hpr.getX()) else: if (av.getH() < 0): hpr.setX(hpr.getX() - 180) else: hpr.setX(hpr.getX() + 180) return hpr toonJumpTrack = Parallel( ActorInterval(av, 'jump'), Sequence( Wait(0.43), Parallel( LerpHprInterval(av, hpr=getJumpHpr, duration=1), ProjectileInterval(av, endPos=getJumpDest, duration=1)), )) return toonJumpTrack def getToonSitTrack(av): toonSitTrack = Sequence(ActorInterval(av, 'sit-start'), Func(av.loop, 'sit')) return toonSitTrack toonJumpTrack = getToonJumpTrack(av, seatIndex) toonSitTrack = getToonSitTrack(av) jumpTrack = Sequence( Parallel( toonJumpTrack, Sequence( Wait(1), toonSitTrack, ), ), Func(av.wrtReparentTo, self.tableCloth), ) return jumpTrack def storeToonTrack(self, avId, track): # Clear out any currently playing tracks on this toon self.clearToonTrack(avId) # Store this new one self.__toonTracks[avId] = track def clearToonTrack(self, avId): # Clear out any currently playing tracks on this toon oldTrack = self.__toonTracks.get(avId) if oldTrack: oldTrack.pause() cleanupDelayDeletes(oldTrack) #del self.__toonTracks[avId] def clearToonTracks(self): #We can't use an iter because we are deleting keys keyList = [] for key in self.__toonTracks: keyList.append(key) for key in keyList: if self.__toonTracks.has_key(key): self.clearToonTrack(key) def doNothing(self): pass