class DistributedPartyJukeboxActivityBase(DistributedPartyActivity): notify = directNotify.newCategory("DistributedPartyJukeboxActivityBase") def __init__(self, cr, actId, phaseToMusicData): DistributedPartyActivity.__init__(self, cr, actId, ActivityTypes.Continuous) self.phaseToMusicData = phaseToMusicData self.jukebox = None self.gui = None self.tunes = [] self.music = None self.currentSongData = None self.localQueuedSongInfo = None self.localQueuedSongListItem = None return def generateInit(self): self.gui = JukeboxGui(self.phaseToMusicData) def load(self): DistributedPartyActivity.load(self) self.jukebox = Actor( "phase_13/models/parties/jukebox_model", {"dance": "phase_13/models/parties/jukebox_dance"} ) self.jukebox.reparentTo(self.root) self.jukebox.loop("dance", fromFrame=0, toFrame=48) self.collNode = CollisionNode(self.getCollisionName()) self.collNode.setCollideMask(ToontownGlobals.CameraBitmask | ToontownGlobals.WallBitmask) collTube = CollisionTube(0, 0, 0, 0.0, 0.0, 4.25, 2.25) collTube.setTangible(1) self.collNode.addSolid(collTube) self.collNodePath = self.jukebox.attachNewNode(self.collNode) self.sign.setPos(-5.0, 0, 0) self.activate() def unload(self): DistributedPartyActivity.unload(self) self.gui.unload() if self.music is not None: self.music.stop() self.jukebox.stop() self.jukebox.delete() self.jukebox = None self.ignoreAll() return def getCollisionName(self): return self.uniqueName("jukeboxCollision") def activate(self): self.accept("enter" + self.getCollisionName(), self.__handleEnterCollision) def __handleEnterCollision(self, collisionEntry): if base.cr.playGame.getPlace().fsm.getCurrentState().getName() == "walk": base.cr.playGame.getPlace().fsm.request("activity") self.d_toonJoinRequest() def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyJukeboxOccupied) def handleToonJoined(self, toonId): toon = base.cr.doId2do.get(toonId) if toon: self.jukebox.lookAt(base.cr.doId2do[toonId]) self.jukebox.setHpr(self.jukebox.getH() + 180.0, 0, 0) if toonId == base.localAvatar.doId: self.__localUseJukebox() def handleToonExited(self, toonId): if toonId == base.localAvatar.doId and self.gui.isLoaded(): self.__deactivateGui() def handleToonDisabled(self, toonId): self.notify.warning("handleToonDisabled no implementation yet") def __localUseJukebox(self): base.localAvatar.disableAvatarControls() base.localAvatar.stopPosHprBroadcast() self.__activateGui() self.accept(JukeboxGui.CLOSE_EVENT, self.__handleGuiClose) taskMgr.doMethodLater( 0.5, self.__localToonWillExitTask, self.uniqueName("toonWillExitJukeboxOnTimeout"), extraArgs=None ) self.accept(JukeboxGui.ADD_SONG_CLICK_EVENT, self.__handleQueueSong) if self.isUserHost(): self.accept(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT, self.__handleMoveSongToTop) return def __localToonWillExitTask(self, task): self.localToonExiting() return Task.done def __activateGui(self): self.gui.enable(timer=JUKEBOX_TIMEOUT) self.gui.disableAddSongButton() if self.currentSongData is not None: self.gui.setSongCurrentlyPlaying(self.currentSongData[0], self.currentSongData[1]) self.d_queuedSongsRequest() return def __deactivateGui(self): self.ignore(JukeboxGui.CLOSE_EVENT) self.ignore(JukeboxGui.SONG_SELECT_EVENT) self.ignore(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT) base.cr.playGame.getPlace().setState("walk") base.localAvatar.startPosHprBroadcast() base.localAvatar.enableAvatarControls() self.gui.unload() self.__localClearQueuedSong() def isUserHost(self): return self.party.partyInfo.hostId == base.localAvatar.doId def d_queuedSongsRequest(self): self.sendUpdate("queuedSongsRequest") def queuedSongsResponse(self, songInfoList, index): if self.gui.isLoaded(): for i in range(len(songInfoList)): songInfo = songInfoList[i] self.__addSongToQueue(songInfo, isLocalQueue=index >= 0 and i == index) self.gui.enableAddSongButton() def __handleGuiClose(self): self.__deactivateGui() self.d_toonExitDemand() def __handleQueueSong(self, name, values): self.d_setNextSong(values[0], values[1]) def d_setNextSong(self, phase, filename): self.sendUpdate("setNextSong", [(phase, filename)]) def setSongInQueue(self, songInfo): if self.gui.isLoaded(): phase = sanitizePhase(songInfo[0]) filename = songInfo[1] data = self.getMusicData(phase, filename) if data: if self.localQueuedSongListItem is not None: self.localQueuedSongListItem["text"] = data[0] else: self.__addSongToQueue(songInfo, isLocalQueue=True) return def __addSongToQueue(self, songInfo, isLocalQueue=False): isHost = isLocalQueue and self.isUserHost() data = self.getMusicData(sanitizePhase(songInfo[0]), songInfo[1]) if data: listItem = self.gui.addSongToQueue(data[0], highlight=isLocalQueue, moveToTopButton=isHost) if isLocalQueue: self.localQueuedSongInfo = songInfo self.localQueuedSongListItem = listItem def __localClearQueuedSong(self): self.localQueuedSongInfo = None self.localQueuedSongListItem = None return def __play(self, phase, filename, length): self.music = base.loadMusic((MUSIC_PATH + "%s") % (phase, filename)) if self.music: if ( self.__checkPartyValidity() and hasattr(base.cr.playGame.getPlace().loader, "music") and base.cr.playGame.getPlace().loader.music ): base.cr.playGame.getPlace().loader.music.stop() self.music.setTime(0.0) self.music.setLoopCount(getMusicRepeatTimes(length)) self.music.play() self.currentSongData = (phase, filename) def __stop(self): self.currentSongData = None if self.music: self.music.stop() if self.gui.isLoaded(): self.gui.clearSongCurrentlyPlaying() return def setSongPlaying(self, songInfo, toonId): phase = sanitizePhase(songInfo[0]) filename = songInfo[1] if not filename: self.__stop() return data = self.getMusicData(phase, filename) if data: self.__play(phase, filename, data[1]) self.setSignNote(data[0]) if self.gui.isLoaded(): item = self.gui.popSongFromQueue() self.gui.setSongCurrentlyPlaying(phase, filename) if item == self.localQueuedSongListItem: self.__localClearQueuedSong() if toonId == localAvatar.doId: localAvatar.setSystemMessage(0, TTLocalizer.PartyJukeboxNowPlaying) def __handleMoveSongToTop(self): if self.isUserHost() and self.localQueuedSongListItem is not None: self.d_moveHostSongToTopRequest() return def d_moveHostSongToTopRequest(self): self.notify.debug("d_moveHostSongToTopRequest") self.sendUpdate("moveHostSongToTopRequest") def moveHostSongToTop(self): self.notify.debug("moveHostSongToTop") if self.gui.isLoaded(): self.gui.pushQueuedItemToTop(self.localQueuedSongListItem) def getMusicData(self, phase, filename): data = [] phase = sanitizePhase(phase) phase = self.phaseToMusicData.get(phase) if phase: data = phase.get(filename, []) return data def __checkPartyValidity(self): if ( hasattr(base.cr.playGame, "getPlace") and base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(), "loader") and base.cr.playGame.getPlace().loader ): return True else: return False
class DistributedPartyJukeboxActivityBase(DistributedPartyActivity): notify = directNotify.newCategory("DistributedPartyJukeboxActivityBase") def __init__(self, cr, actId, phaseToMusicData): DistributedPartyActivity.__init__(self, cr, actId, ActivityTypes.Continuous) self.phaseToMusicData = phaseToMusicData self.jukebox = None self.gui = None self.tunes = [] self.music = None # Data is tuple (phase, filename) self.currentSongData = None self.localQueuedSongInfo = None self.localQueuedSongListItem = None def generateInit(self): self.gui = JukeboxGui(self.phaseToMusicData) def load(self): DistributedPartyActivity.load(self) # Load Jukebox actor self.jukebox = Actor( "phase_13/models/parties/jukebox_model", {"dance": "phase_13/models/parties/jukebox_dance"}) self.jukebox.reparentTo(self.root) # Create collision area for jukebox self.collNode = CollisionNode(self.getCollisionName()) self.collNode.setCollideMask(ToontownGlobals.CameraBitmask | ToontownGlobals.WallBitmask) collTube = CollisionTube(0, 0, 0, 0.0, 0.0, 4.25, 2.25) collTube.setTangible(1) self.collNode.addSolid(collTube) self.collNodePath = self.jukebox.attachNewNode(self.collNode) self.sign.setPos(-5.0, 0, 0) self.activate() def unload(self): DistributedPartyActivity.unload(self) self.gui.unload() if self.music is not None: self.music.stop() self.jukebox.stop() self.jukebox.delete() self.jukebox = None self.ignoreAll() def getCollisionName(self): return self.uniqueName("jukeboxCollision") def activate(self): self.accept("enter" + self.getCollisionName(), self.__handleEnterCollision) #=============================================================================== # Enter/Exit Jukebox #=============================================================================== def __handleEnterCollision(self, collisionEntry): if base.cr.playGame.getPlace().fsm.getCurrentState().getName( ) == "walk": base.cr.playGame.getPlace().fsm.request("activity") self.d_toonJoinRequest() def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyJukeboxOccupied) # Distributed (broadcast ram) def handleToonJoined(self, toonId): """ Toon requested to use the jukebox and the request has been granted. """ toon = base.cr.doId2do.get(toonId) if toon: self.jukebox.lookAt(base.cr.doId2do[toonId]) self.jukebox.setHpr(self.jukebox.getH() + 180.0, 0, 0) if toonId == base.localAvatar.doId: self.__localUseJukebox() def handleToonExited(self, toonId): """ Typically called when toon times out. """ if toonId == base.localAvatar.doId and self.gui.isLoaded(): self.__deactivateGui() def handleToonDisabled(self, toonId): """ A toon dropped unexpectedly from the game. Handle it! """ self.notify.warning("handleToonDisabled no implementation yet") def __localUseJukebox(self): """ Sets the local toon to use the jukebox, including activating the GUI and changing the client into the appropriate state. """ base.localAvatar.disableAvatarControls() base.localAvatar.stopPosHprBroadcast() self.__activateGui() self.accept(JukeboxGui.CLOSE_EVENT, self.__handleGuiClose) # We are locking exiting now in case the AI times the toon out of the Jukebox. taskMgr.doMethodLater(0.5, self.__localToonWillExitTask, self.uniqueName("toonWillExitJukeboxOnTimeout"), extraArgs=None) self.accept(JukeboxGui.ADD_SONG_CLICK_EVENT, self.__handleQueueSong) if self.isUserHost(): self.accept(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT, self.__handleMoveSongToTop) def __localToonWillExitTask(self, task): self.localToonExiting() return Task.done def __activateGui(self): self.gui.enable(timer=JUKEBOX_TIMEOUT) self.gui.disableAddSongButton() if self.currentSongData is not None: self.gui.setSongCurrentlyPlaying(self.currentSongData[0], self.currentSongData[1]) self.d_queuedSongsRequest() def __deactivateGui(self): self.ignore(JukeboxGui.CLOSE_EVENT) self.ignore(JukeboxGui.SONG_SELECT_EVENT) self.ignore(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT) base.cr.playGame.getPlace().setState("walk") base.localAvatar.startPosHprBroadcast() base.localAvatar.enableAvatarControls() self.gui.unload() self.__localClearQueuedSong() def isUserHost(self): """ Checks if the localAvatar is the host of the party Returns true if localAvatar is the host of the party """ return (self.party.partyInfo.hostId == base.localAvatar.doId) # Distributed (clsend airecv) def d_queuedSongsRequest(self): self.sendUpdate("queuedSongsRequest") # Distributed (only sender receives this response) def queuedSongsResponse(self, songInfoList, index): """ Gets a list of songs and adds them to the queue. Called when the toon first interacts with the jukebox. Parameters: songInfoList is the list of songs index is the item # on the list for a song previously queued by the player. """ if self.gui.isLoaded(): for i in range(len(songInfoList)): songInfo = songInfoList[i] self.__addSongToQueue(songInfo, isLocalQueue=(index >= 0 and i == index)) self.gui.enableAddSongButton() def __handleGuiClose(self): """ Closes Jukebox GUI, cleans up event handlers, and sets client state to normal. Typically triggered when the player clicks the close button in the jukebox, which fires CLOSE_EVENT. """ self.__deactivateGui() self.d_toonExitDemand() #=============================================================================== # Queueing songs #=============================================================================== def __handleQueueSong(self, name, values): """ Requests to queue a song. Triggered when the localAvatar clicks the "Add/Replace Song button". """ self.d_setNextSong(values[0], values[1]) # Distributed (clsend airecv) def d_setNextSong(self, phase, filename): self.sendUpdate("setNextSong", [(phase, filename)]) # Distributed (sender only gets it back) def setSongInQueue(self, songInfo): if self.gui.isLoaded(): phase = sanitizePhase(songInfo[0]) filename = songInfo[1] data = self.getMusicData(phase, filename) if data: if self.localQueuedSongListItem is not None: self.localQueuedSongListItem["text"] = data[0] else: self.__addSongToQueue(songInfo, isLocalQueue=True) def __addSongToQueue(self, songInfo, isLocalQueue=False): """ Adds a song to the queue. If it's the localAvatar's queued song, then it marks it. Parameters: songInfo is a list of phase and data isLocalQueue is flag marking whether this is the localAvatar's queued song """ isHost = (isLocalQueue and self.isUserHost()) data = self.getMusicData(sanitizePhase(songInfo[0]), songInfo[1]) if data: listItem = self.gui.addSongToQueue(data[0], highlight=isLocalQueue, moveToTopButton=isHost) if isLocalQueue: self.localQueuedSongInfo = songInfo self.localQueuedSongListItem = listItem def __localClearQueuedSong(self): """ Clears the queued song records. """ self.localQueuedSongInfo = None self.localQueuedSongListItem = None #=============================================================================== # Music Playback #=============================================================================== def __play(self, phase, filename, length): """ Plays some music! """ assert self.notify.debugStateCall(self) self.music = base.loadMusic((MUSIC_PATH + "%s") % (phase, filename)) if self.music: if self.__checkPartyValidity() and hasattr( base.cr.playGame.getPlace().loader, "music") and base.cr.playGame.getPlace().loader.music: base.cr.playGame.getPlace().loader.music.stop() base.resetMusic.play() self.music.setTime(0.0) self.music.setLoopCount(getMusicRepeatTimes(length)) self.music.play() jukeboxAnimControl = self.jukebox.getAnimControl("dance") if not jukeboxAnimControl.isPlaying(): self.jukebox.loop("dance") self.currentSongData = (phase, filename) def __stop(self): """ Stops animations and and clears GUI. """ self.jukebox.stop() self.currentSongData = None if self.music: self.music.stop() if self.gui.isLoaded(): self.gui.clearSongCurrentlyPlaying() # Distributed (broadcast ram) def setSongPlaying(self, songInfo, toonId): """ Sets the song from the AI to play in the client. Parameters: songInfo is a list with two items: phase and filename """ phase = sanitizePhase(songInfo[0]) filename = songInfo[1] assert (self.notify.debug("setSongPlaying phase_%d/%s" % (phase, filename))) # setSongPlaying sends empty filename if songs have stop playing # in order for the client to clean up. if not filename: self.__stop() return data = self.getMusicData(phase, filename) if data: self.__play(phase, filename, data[1]) self.setSignNote(data[0]) # Update the gui if it's active: if self.gui.isLoaded(): item = self.gui.popSongFromQueue() self.gui.setSongCurrentlyPlaying(phase, filename) if item == self.localQueuedSongListItem: self.__localClearQueuedSong() if toonId == localAvatar.doId: localAvatar.setSystemMessage(0, TTLocalizer.PartyJukeboxNowPlaying) #=============================================================================== # Host only: Push his/her queued song to the top of the playlist. #=============================================================================== def __handleMoveSongToTop(self): """ Requests to move the localAvatar's queued song to top. It is triggered when the user clicks on the "moveToTopButton" on the GUI. This is only enabled for the host of the party. """ if self.isUserHost() and self.localQueuedSongListItem is not None: self.d_moveHostSongToTopRequest() # Distributed (clsend airecv) def d_moveHostSongToTopRequest(self): self.notify.debug("d_moveHostSongToTopRequest") self.sendUpdate("moveHostSongToTopRequest") # Distributed (only host gets it) def moveHostSongToTop(self): self.notify.debug("moveHostSongToTop") if self.gui.isLoaded(): self.gui.pushQueuedItemToTop(self.localQueuedSongListItem) def getMusicData(self, phase, filename): data = [] phase = sanitizePhase(phase) phase = self.phaseToMusicData.get(phase) if phase: data = phase.get(filename, []) return data def __checkPartyValidity(self): """ Function that checks the validity of a street, it's loader and the geometry""" if hasattr(base.cr.playGame, "getPlace") and base.cr.playGame.getPlace() and \ hasattr(base.cr.playGame.getPlace(), "loader") and base.cr.playGame.getPlace().loader: return True else: return False
class DistributedPartyJukeboxActivityBase(DistributedPartyActivity): __module__ = __name__ notify = directNotify.newCategory('DistributedPartyJukeboxActivityBase') def __init__(self, cr, actId, phaseToMusicData): DistributedPartyActivity.__init__(self, cr, actId, ActivityTypes.Continuous) self.phaseToMusicData = phaseToMusicData self.jukebox = None self.gui = None self.tunes = [] self.music = None self.currentSongData = None self.localQueuedSongInfo = None self.localQueuedSongListItem = None return def generateInit(self): self.gui = JukeboxGui(self.phaseToMusicData) def load(self): DistributedPartyActivity.load(self) self.jukebox = Actor( 'phase_13/models/parties/jukebox_model', {'dance': 'phase_13/models/parties/jukebox_dance'}) self.jukebox.reparentTo(self.root) self.collNode = CollisionNode(self.getCollisionName()) self.collNode.setCollideMask(ToontownGlobals.CameraBitmask | ToontownGlobals.WallBitmask) collTube = CollisionTube(0, 0, 0, 0.0, 0.0, 4.25, 2.25) collTube.setTangible(1) self.collNode.addSolid(collTube) self.collNodePath = self.jukebox.attachNewNode(self.collNode) self.sign.setPos(-5.0, 0, 0) self.activate() def unload(self): DistributedPartyActivity.unload(self) self.gui.unload() if self.music is not None: self.music.stop() self.jukebox.stop() self.jukebox.delete() self.jukebox = None self.ignoreAll() return def getCollisionName(self): return self.uniqueName('jukeboxCollision') def activate(self): self.accept('enter' + self.getCollisionName(), self.__handleEnterCollision) def __handleEnterCollision(self, collisionEntry): if base.cr.playGame.getPlace().fsm.getCurrentState().getName( ) == 'walk': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyJukeboxOccupied) def handleToonJoined(self, toonId): toon = base.cr.doId2do.get(toonId) if toon: self.jukebox.lookAt(base.cr.doId2do[toonId]) self.jukebox.setHpr(self.jukebox.getH() + 180.0, 0, 0) if toonId == base.localAvatar.doId: self.__localUseJukebox() def handleToonExited(self, toonId): if toonId == base.localAvatar.doId and self.gui.isLoaded(): self.__deactivateGui() def handleToonDisabled(self, toonId): self.notify.warning('handleToonDisabled no implementation yet') def __localUseJukebox(self): base.localAvatar.disableAvatarControls() base.localAvatar.stopPosHprBroadcast() self.__activateGui() self.accept(JukeboxGui.CLOSE_EVENT, self.__handleGuiClose) taskMgr.doMethodLater(0.5, self.__localToonWillExitTask, self.uniqueName('toonWillExitJukeboxOnTimeout'), extraArgs=None) self.accept(JukeboxGui.ADD_SONG_CLICK_EVENT, self.__handleQueueSong) if self.isUserHost(): self.accept(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT, self.__handleMoveSongToTop) return def __localToonWillExitTask(self, task): self.localToonExiting() return Task.done def __activateGui(self): self.gui.enable(timer=JUKEBOX_TIMEOUT) self.gui.disableAddSongButton() if self.currentSongData is not None: self.gui.setSongCurrentlyPlaying(self.currentSongData[0], self.currentSongData[1]) self.d_queuedSongsRequest() return def __deactivateGui(self): self.ignore(JukeboxGui.CLOSE_EVENT) self.ignore(JukeboxGui.SONG_SELECT_EVENT) self.ignore(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT) base.cr.playGame.getPlace().setState('walk') base.localAvatar.startPosHprBroadcast() base.localAvatar.enableAvatarControls() self.gui.unload() self.__localClearQueuedSong() def isUserHost(self): return self.party.partyInfo.hostId == base.localAvatar.doId def d_queuedSongsRequest(self): self.sendUpdate('queuedSongsRequest') def queuedSongsResponse(self, songInfoList, index): if self.gui.isLoaded(): for i in range(len(songInfoList)): songInfo = songInfoList[i] self.__addSongToQueue(songInfo, isLocalQueue=index >= 0 and i == index) self.gui.enableAddSongButton() def __handleGuiClose(self): self.__deactivateGui() self.d_toonExitDemand() def __handleQueueSong(self, name, values): self.d_setNextSong(values[0], values[1]) def d_setNextSong(self, phase, filename): self.sendUpdate('setNextSong', [(phase, filename)]) def setSongInQueue(self, songInfo): if self.gui.isLoaded(): phase = sanitizePhase(songInfo[0]) filename = songInfo[1] data = self.getMusicData(phase, filename) if data: if self.localQueuedSongListItem is not None: self.localQueuedSongListItem['text'] = data[0] else: self.__addSongToQueue(songInfo, isLocalQueue=True) return def __addSongToQueue(self, songInfo, isLocalQueue=False): if isLocalQueue: isHost = self.isUserHost() data = self.getMusicData(sanitizePhase(songInfo[0]), songInfo[1]) if data: listItem = self.gui.addSongToQueue(data[0], highlight=isLocalQueue, moveToTopButton=isHost) self.localQueuedSongInfo = isLocalQueue and songInfo self.localQueuedSongListItem = listItem def __localClearQueuedSong(self): self.localQueuedSongInfo = None self.localQueuedSongListItem = None return def __play(self, phase, filename, length): self.music = base.loadMusic((MUSIC_PATH + '%s') % (phase, filename)) if self.music: if self.__checkPartyValidity() and hasattr( base.cr.playGame.getPlace().loader, 'music') and base.cr.playGame.getPlace().loader.music: base.cr.playGame.getPlace().loader.music.stop() base.resetMusic.play() self.music.setTime(0.0) self.music.setLoopCount(getMusicRepeatTimes(length)) self.music.play() jukeboxAnimControl = self.jukebox.getAnimControl('dance') if not jukeboxAnimControl.isPlaying(): self.jukebox.loop('dance') self.currentSongData = (phase, filename) def __stop(self): self.jukebox.stop() self.currentSongData = None if self.music: self.music.stop() if self.gui.isLoaded(): self.gui.clearSongCurrentlyPlaying() return def setSongPlaying(self, songInfo, toonId): phase = sanitizePhase(songInfo[0]) filename = songInfo[1] if not filename: self.__stop() return data = self.getMusicData(phase, filename) if data: self.__play(phase, filename, data[1]) self.setSignNote(data[0]) if self.gui.isLoaded(): item = self.gui.popSongFromQueue() self.gui.setSongCurrentlyPlaying(phase, filename) if item == self.localQueuedSongListItem: self.__localClearQueuedSong() if toonId == localAvatar.doId: localAvatar.setSystemMessage(0, TTLocalizer.PartyJukeboxNowPlaying) def __handleMoveSongToTop(self): if self.isUserHost() and self.localQueuedSongListItem is not None: self.d_moveHostSongToTopRequest() return def d_moveHostSongToTopRequest(self): self.notify.debug('d_moveHostSongToTopRequest') self.sendUpdate('moveHostSongToTopRequest') def moveHostSongToTop(self): self.notify.debug('moveHostSongToTop') if self.gui.isLoaded(): self.gui.pushQueuedItemToTop(self.localQueuedSongListItem) def getMusicData(self, phase, filename): data = [] phase = sanitizePhase(phase) phase = self.phaseToMusicData.get(phase) if phase: data = phase.get(filename, []) return data def __checkPartyValidity(self): if hasattr(base.cr.playGame, 'getPlace') and base.cr.playGame.getPlace() and hasattr( base.cr.playGame.getPlace(), 'loader') and base.cr.playGame.getPlace().loader: return True else: return False
class DistributedSafezoneJukebox(DistributedObject): notify = directNotify.newCategory('DistributedSafezoneJukebox') def __init__(self, cr): DistributedObject.__init__(self, cr) self.activityName = TTLocalizer.SafezoneJukeboxTitle self.phaseToMusicData = PhaseToMusicData60 self.jukebox = None self.gui = None self.tunes = [] self.music = None self.messageGui = None self.currentSongData = None self.localQueuedSongInfo = None self.localQueuedSongListItem = None self._localToonRequestStatus = None self.toonIds = [] self._toonId2ror = {} self.root = NodePath('root') return def announceGenerate(self): DistributedObject.announceGenerate(self) self.load() def disable(self): self.notify.debug('BASE: disable') DistributedObject.disable(self) rorToonIds = self._toonId2ror.keys() for toonId in rorToonIds: self.cr.relatedObjectMgr.abortRequest(self._toonId2ror[toonId]) del self._toonId2ror[toonId] self.ignore(self.messageDoneEvent) if self.messageGui is not None and not self.messageGui.isEmpty(): self.messageGui.cleanup() self.messageGui = None return def delete(self): self.notify.debug('BASE: delete') self.unload() self.ignoreAll() DistributedObject.delete(self) def generateInit(self): self.gui = JukeboxGui(self.phaseToMusicData) def load(self): self.jukebox = Actor( 'phase_13/models/parties/jukebox_model', {'dance': 'phase_13/models/parties/jukebox_dance'}) self.jukebox.reparentTo(self.root) self.collNode = CollisionNode(self.getCollisionName()) self.collNode.setCollideMask(ToontownGlobals.CameraBitmask | ToontownGlobals.WallBitmask) collTube = CollisionTube(0, 0, 0, 0.0, 0.0, 4.25, 2.25) collTube.setTangible(1) self.collNode.addSolid(collTube) self.collNodePath = self.jukebox.attachNewNode(self.collNode) self.loadSign() self.sign.setPos(-5.0, 0, 0) self.messageDoneEvent = self.uniqueName('messageDoneEvent') self.root.reparentTo(render) self.activate() def loadSign(self): self.sign = self.root.attachNewNode('%sSign' % self.activityName) self.defaultSignModel = loader.loadModel( 'phase_13/models/parties/eventSign') self.signModel = self.defaultSignModel.copyTo(self.sign) self.signFlat = self.signModel.find('**/sign_flat') self.signFlatWithNote = self.signModel.find('**/sign_withNote') self.signTextLocator = self.signModel.find('**/signText_locator') self.activityIconsModel = loader.loadModel( 'phase_4/models/parties/eventSignIcons') textureNodePath = self.activityIconsModel.find('**/PartyJukebox40Icon') textureNodePath.setPos(0.0, -0.02, 2.2) textureNodePath.setScale(2.35) textureNodePath.copyTo(self.signFlat) textureNodePath.copyTo(self.signFlatWithNote) text = TextNode('noteText') text.setTextColor(0.2, 0.1, 0.7, 1.0) text.setAlign(TextNode.ACenter) text.setFont(OTPGlobals.getInterfaceFont()) text.setWordwrap(10.0) text.setText('') self.noteText = self.signFlatWithNote.attachNewNode(text) self.noteText.setPosHpr(self.signTextLocator, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0) self.noteText.setScale(0.2) self.signFlatWithNote.stash() self.signTextLocator.stash() def unload(self): self.gui.unload() if self.music is not None: self.music.stop() self.jukebox.stop() self.jukebox.delete() self.jukebox = None self.signModel.removeNode() del self.signModel self.sign.removeNode() del self.sign self.ignoreAll() self.root.removeNode() del self.root del self.activityName del self.messageGui if hasattr(self, 'toonIds'): del self.toonIds self.ignoreAll() return def getCollisionName(self): return self.uniqueName('jukeboxCollision') def activate(self): self.accept('enter' + self.getCollisionName(), self.__handleEnterCollision) def __handleEnterCollision(self, collisionEntry): if base.cr.playGame.getPlace().fsm.getCurrentState().getName( ) == 'walk': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() def localToonExiting(self): self._localToonRequestStatus = ActivityRequestStatus.Exiting def localToonJoining(self): self._localToonRequestStatus = ActivityRequestStatus.Joining def d_toonJoinRequest(self): if self._localToonRequestStatus is None: self.localToonJoining() self.sendUpdate('toonJoinRequest') return def d_toonExitRequest(self): if self._localToonRequestStatus is None: self.localToonExiting() self.sendUpdate('toonExitRequest') return def d_toonExitDemand(self): self.localToonExiting() self.sendUpdate('toonExitDemand') def joinRequestDenied(self, reason): self._localToonRequestStatus = None self.showMessage(TTLocalizer.PartyJukeboxOccupied) return def handleToonJoined(self, toonId): toon = base.cr.doId2do.get(toonId) if toon: self.jukebox.lookAt(base.cr.doId2do[toonId]) self.jukebox.setHpr(self.jukebox.getH() + 180.0, 0, 0) if toonId == base.localAvatar.doId: self.__localUseJukebox() def handleToonExited(self, toonId): if toonId == base.localAvatar.doId and self.gui.isLoaded(): self.__deactivateGui() def handleToonDisabled(self, toonId): self.notify.warning('handleToonDisabled no implementation yet') def setToonsPlaying(self, toonIds): exitedToons, joinedToons = self.getToonsPlayingChanges( self.toonIds, toonIds) self.setToonIds(toonIds) self._processExitedToons(exitedToons) self._processJoinedToons(joinedToons) def _processExitedToons(self, exitedToons): for toonId in exitedToons: if toonId != base.localAvatar.doId or toonId == base.localAvatar.doId and self.isLocalToonRequestStatus( ActivityRequestStatus.Exiting): toon = self.getAvatar(toonId) if toon is not None: self.ignore(toon.uniqueName('disable')) self.handleToonExited(toonId) if toonId == base.localAvatar.doId: self._localToonRequestStatus = None if toonId in self._toonId2ror: self.cr.relatedObjectMgr.abortRequest( self._toonId2ror[toonId]) del self._toonId2ror[toonId] return def _processJoinedToons(self, joinedToons): for toonId in joinedToons: if toonId != base.localAvatar.doId or toonId == base.localAvatar.doId and self.isLocalToonRequestStatus( ActivityRequestStatus.Joining): if toonId not in self._toonId2ror: request = self.cr.relatedObjectMgr.requestObjects( [toonId], allCallback=self._handlePlayerPresent) if toonId in self._toonId2ror: del self._toonId2ror[toonId] else: self._toonId2ror[toonId] = request def _handlePlayerPresent(self, toons): toon = toons[0] toonId = toon.doId if toonId in self._toonId2ror: del self._toonId2ror[toonId] else: self._toonId2ror[toonId] = None self._enableHandleToonDisabled(toonId) self.handleToonJoined(toonId) if toonId == base.localAvatar.doId: self._localToonRequestStatus = None return def _enableHandleToonDisabled(self, toonId): toon = self.getAvatar(toonId) if toon is not None: self.acceptOnce(toon.uniqueName('disable'), self.handleToonDisabled, [toonId]) else: self.notify.warning( 'BASE: unable to get handle to toon with toonId:%d. Hook for handleToonDisabled not set.' % toonId) return def isLocalToonRequestStatus(self, requestStatus): return self._localToonRequestStatus == requestStatus def setToonIds(self, toonIds): self.toonIds = toonIds def getToonsPlayingChanges(self, oldToonIds, newToonIds): oldToons = set(oldToonIds) newToons = set(newToonIds) exitedToons = oldToons.difference(newToons) joinedToons = newToons.difference(oldToons) return (list(exitedToons), list(joinedToons)) def getAvatar(self, toonId): if toonId in self.cr.doId2do: return self.cr.doId2do[toonId] else: self.notify.warning( 'BASE: getAvatar: No avatar in doId2do with id: ' + str(toonId)) return return def __localUseJukebox(self): base.localAvatar.disableAvatarControls() base.localAvatar.stopPosHprBroadcast() self.__activateGui() self.accept(JukeboxGui.CLOSE_EVENT, self.__handleGuiClose) taskMgr.doMethodLater(0.5, self.__localToonWillExitTask, self.uniqueName('toonWillExitJukeboxOnTimeout'), extraArgs=None) self.accept(JukeboxGui.ADD_SONG_CLICK_EVENT, self.__handleQueueSong) if self.isUserHost(): self.accept(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT, self.__handleMoveSongToTop) return def __localToonWillExitTask(self, task): self.localToonExiting() return Task.done def __activateGui(self): self.gui.enable(timer=JUKEBOX_TIMEOUT) self.gui.disableAddSongButton() if self.currentSongData is not None: self.gui.setSongCurrentlyPlaying(self.currentSongData[0], self.currentSongData[1]) self.d_queuedSongsRequest() return def __deactivateGui(self): self.ignore(JukeboxGui.CLOSE_EVENT) self.ignore(JukeboxGui.SONG_SELECT_EVENT) self.ignore(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT) base.cr.playGame.getPlace().setState('walk') base.localAvatar.startPosHprBroadcast() base.localAvatar.enableAvatarControls() self.gui.unload() self.__localClearQueuedSong() def isUserHost(self): return base.localAvatar.getAccessLevel() >= 200 def d_queuedSongsRequest(self): self.sendUpdate('queuedSongsRequest') def queuedSongsResponse(self, songInfoList, index): if self.gui.isLoaded(): for i in xrange(len(songInfoList)): songInfo = songInfoList[i] self.__addSongToQueue(songInfo, isLocalQueue=index >= 0 and i == index) self.gui.enableAddSongButton() def __handleGuiClose(self): self.__deactivateGui() self.d_toonExitDemand() def __handleQueueSong(self, name, values): self.d_setNextSong(values[0], values[1]) def d_setNextSong(self, phase, filename): self.sendUpdate('setNextSong', [(phase, filename)]) def setSongInQueue(self, songInfo): if self.gui.isLoaded(): phase = sanitizePhase(songInfo[0]) filename = songInfo[1] data = self.getMusicData(phase, filename) if data: if self.localQueuedSongListItem is not None: self.localQueuedSongListItem['text'] = data[0] else: self.__addSongToQueue(songInfo, isLocalQueue=True) return def __addSongToQueue(self, songInfo, isLocalQueue=False): isHost = isLocalQueue and self.isUserHost() data = self.getMusicData(sanitizePhase(songInfo[0]), songInfo[1]) if data: listItem = self.gui.addSongToQueue(data[0], highlight=isLocalQueue, moveToTopButton=isHost) if isLocalQueue: self.localQueuedSongInfo = songInfo self.localQueuedSongListItem = listItem def __localClearQueuedSong(self): self.localQueuedSongInfo = None self.localQueuedSongListItem = None return def __play(self, phase, filename, length): self.music = base.loader.loadMusic( (MUSIC_PATH + '%s') % (phase, filename)) if self.music: if self.__checkPartyValidity() and hasattr( base.cr.playGame.getPlace().loader, 'music') and base.cr.playGame.getPlace().loader.music: base.cr.playGame.getPlace().loader.music.stop() self.music.setTime(0.0) self.music.setLoopCount(int(getMusicRepeatTimes(length))) self.music.play() jukeboxAnimControl = self.jukebox.getAnimControl('dance') if not jukeboxAnimControl.isPlaying(): self.jukebox.loop('dance', fromFrame=0, toFrame=48) self.currentSongData = (phase, filename) def __stop(self): self.jukebox.stop() self.currentSongData = None if self.music: self.music.stop() if self.gui.isLoaded(): self.gui.clearSongCurrentlyPlaying() return def setSongPlaying(self, songInfo, toonId): phase = sanitizePhase(songInfo[0]) filename = songInfo[1] if not filename: self.__stop() return data = self.getMusicData(phase, filename) if data: self.__play(phase, filename, data[1]) self.setSignNote(data[0]) if self.gui.isLoaded(): item = self.gui.popSongFromQueue() self.gui.setSongCurrentlyPlaying(phase, filename) if item == self.localQueuedSongListItem: self.__localClearQueuedSong() if toonId == localAvatar.doId: localAvatar.setSystemMessage(0, TTLocalizer.PartyJukeboxNowPlaying) def setSignNote(self, note): self.noteText.node().setText(note) if len(note.strip()) > 0: self.signFlat.stash() self.signFlatWithNote.unstash() self.signTextLocator.unstash() else: self.signFlat.unstash() self.signFlatWithNote.stash() self.signTextLocator.stash() def __handleMoveSongToTop(self): if self.isUserHost() and self.localQueuedSongListItem is not None: self.d_moveHostSongToTopRequest() return def d_moveHostSongToTopRequest(self): self.notify.debug('d_moveHostSongToTopRequest') self.sendUpdate('moveHostSongToTopRequest') def moveHostSongToTop(self): self.notify.debug('moveHostSongToTop') if self.gui.isLoaded(): self.gui.pushQueuedItemToTop(self.localQueuedSongListItem) def getMusicData(self, phase, filename): data = [] phase = sanitizePhase(phase) phase = self.phaseToMusicData.get(phase) if phase: data = phase.get(filename, []) return data def __checkPartyValidity(self): if hasattr(base.cr.playGame, 'getPlace') and base.cr.playGame.getPlace() and hasattr( base.cr.playGame.getPlace(), 'loader') and base.cr.playGame.getPlace().loader: return True else: return False def showMessage(self, message, endState='walk'): base.cr.playGame.getPlace().fsm.request('activity') self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone) self.messageGui = TTDialog.TTGlobalDialog( doneEvent=self.messageDoneEvent, message=message, style=TTDialog.Acknowledge) self.messageGui.endState = endState def __handleMessageDone(self): self.ignore(self.messageDoneEvent) if hasattr(base.cr.playGame.getPlace(), 'fsm'): if self.messageGui and hasattr(self.messageGui, 'endState'): self.notify.info('__handleMessageDone (endState=%s)' % self.messageGui.endState) base.cr.playGame.getPlace().fsm.request( self.messageGui.endState) else: self.notify.warning( "messageGui has no endState, defaulting to 'walk'") base.cr.playGame.getPlace().fsm.request('walk') if self.messageGui is not None and not self.messageGui.isEmpty(): self.messageGui.cleanup() self.messageGui = None return