diff --git a/dependencies/astron/dclass/stride.dc b/dependencies/astron/dclass/stride.dc index 2c630a18..192f6d10 100644 --- a/dependencies/astron/dclass/stride.dc +++ b/dependencies/astron/dclass/stride.dc @@ -294,6 +294,7 @@ from toontown.estate import DistributedTrunk/AI from toontown.estate import DistributedPhone/AI from toontown.estate import DistributedRewardCrate/AI from toontown.estate import DistributedChair/AI +from toontown.estate import DistributedTV/AI from toontown.effects import DistributedFireworkShow/AI from toontown.estate import DistributedFireworksCannon/AI from toontown.coghq import LobbyManager/AI @@ -2091,6 +2092,12 @@ dclass DistributedChair : DistributedFurnitureItem { setStatus(uint8) broadcast ram; }; +dclass DistributedTV : DistributedFurnitureItem { + setVideo(string(0-255), uint32) required broadcast ram; + requestVideo(string(0-255)) airecv clsend; + requestVideoResponse(uint8); +}; + dclass DistributedFireworkShow : DistributedObject { startShow(uint8, uint8, uint8, int16) broadcast ram; requestFirework(int16/10, int16/10, int16/100, uint8, uint8, uint8) airecv clsend; diff --git a/toontown/catalog/CatalogFurnitureItem.py b/toontown/catalog/CatalogFurnitureItem.py index dfed3a40..089c403a 100755 --- a/toontown/catalog/CatalogFurnitureItem.py +++ b/toontown/catalog/CatalogFurnitureItem.py @@ -21,9 +21,10 @@ FLBillboard = 64 FLPhone = 128 FLCrate = 256 FLChair = 512 -FLTrunk = 1024 -FLBoysOnly = 2048 -FLGirlsOnly = 4096 +FLTV = 1024 +FLTrunk = 2048 +FLBoysOnly = 4096 +FLGirlsOnly = 8192 furnitureColors = [ (0.792, 0.353, 0.29, 1.0), (0.176, 0.592, 0.439, 1.0), @@ -752,15 +753,18 @@ FurnitureTypes = { 1530: ('phase_5.5/models/estate/bugRoomTV', None, None, - 675), + 675, + FLTV), 1531: ('phase_5.5/models/estate/bugRoomTV_50inch', None, None, - 1250), + 1250, + FLTV), 1532: ('phase_5.5/models/estate/bugRoomTV_100inch', None, None, - 5000), + 5000, + FLTV), 1600: ('phase_5.5/models/estate/vaseA_short', None, None, @@ -1107,38 +1111,7 @@ class CatalogFurnitureItem(CatalogAtticItem.CatalogAtticItem): model.setScale(scale) model.flattenLight() - if animate and self.furnitureType in TvToPosScale: - pos = TvToPosScale[self.furnitureType] - screen = NodePath(CardMaker('tv-screen').generate()) - - model.find('**/toonTownBugTV_screen').hide() - screen.reparentTo(model) - screen.setScale(*pos[1]) - screen.setPos(*pos[0]) - self.startVideo(screen) - return model - - def startVideo(self, model, file=None): - files = glob.glob('user/videos/*.mp4') - - if not files: - model.setTextureOff(TextureStage.getDefault()) - model.setColor(0.3, 0.3, 0.3, 1.0) - return - - if file is None: - file = random.randint(0, len(files) - 1) - elif file >= len(files): - file = 0 - - movie = loader.loadTexture(files[file]) - sound = loader.loadSfx(files[file]) - movie.synchronizeTo(sound) - model.setTexture(movie) - model.setTexScale(TextureStage.getDefault(), movie.getTexScale()) - self.videoSequence = Sequence(SoundInterval(sound, volume=1.0), Func(self.startVideo, model, file + 1)) - self.videoSequence.start() def decodeDatagram(self, di, versionNumber, store): CatalogAtticItem.CatalogAtticItem.decodeDatagram(self, di, versionNumber, store) diff --git a/toontown/estate/DistributedFurnitureItem.py b/toontown/estate/DistributedFurnitureItem.py index 75be8567..5b6e88a5 100755 --- a/toontown/estate/DistributedFurnitureItem.py +++ b/toontown/estate/DistributedFurnitureItem.py @@ -47,8 +47,6 @@ class DistributedFurnitureItem(DistributedHouseItem.DistributedHouseItem, Distri def delete(self): self.removeNode() - if hasattr(self.item, 'videoSequence') and self.item.videoSequence: - self.item.videoSequence.pause() del self.item DistributedHouseItem.DistributedHouseItem.delete(self) DistributedSmoothNode.DistributedSmoothNode.delete(self) diff --git a/toontown/estate/DistributedFurnitureManagerAI.py b/toontown/estate/DistributedFurnitureManagerAI.py index 33e241eb..5aab2dda 100755 --- a/toontown/estate/DistributedFurnitureManagerAI.py +++ b/toontown/estate/DistributedFurnitureManagerAI.py @@ -1,7 +1,7 @@ from direct.distributed.DistributedObjectAI import DistributedObjectAI from toontown.catalog.CatalogItemList import CatalogItemList from toontown.catalog import CatalogItem -from toontown.catalog.CatalogFurnitureItem import CatalogFurnitureItem, FLTrunk, FLCloset, FLBank, FLPhone, FLCrate, FLChair +from toontown.catalog.CatalogFurnitureItem import CatalogFurnitureItem, FLTrunk, FLCloset, FLBank, FLPhone, FLCrate, FLChair, FLTV from toontown.catalog.CatalogWallpaperItem import CatalogWallpaperItem from toontown.catalog.CatalogMouldingItem import CatalogMouldingItem from toontown.catalog.CatalogFlooringItem import CatalogFlooringItem @@ -14,6 +14,7 @@ from DistributedTrunkAI import DistributedTrunkAI from DistributedBankAI import DistributedBankAI from DistributedRewardCrateAI import DistributedRewardCrateAI from DistributedChairAI import DistributedChairAI +from DistributedTVAI import DistributedTVAI from otp.ai.MagicWordGlobal import * class FurnitureError(Exception): @@ -249,6 +250,8 @@ class DistributedFurnitureManagerAI(DistributedObjectAI): do = DistributedRewardCrateAI(self.air, self, item) elif item.getFlags() & FLChair: do = DistributedChairAI(self.air, self, item) + elif item.getFlags() & FLTV: + do = DistributedTVAI(self.air, self, item) else: do = DistributedFurnitureItemAI(self.air, self, item) diff --git a/toontown/estate/DistributedTV.py b/toontown/estate/DistributedTV.py new file mode 100644 index 00000000..576253ec --- /dev/null +++ b/toontown/estate/DistributedTV.py @@ -0,0 +1,141 @@ +from direct.gui.DirectGui import * +from otp.otpbase import OTPLocalizer +from toontown.catalog import CatalogFurnitureItem +from toontown.toonbase import ToontownGlobals, TTLocalizer +from toontown.toontowngui import TTDialog +from DistributedFurnitureItem import DistributedFurnitureItem +import glob, ntpath, os, time + +class DistributedTV(DistributedFurnitureItem): + + def __init__(self, cr): + DistributedFurnitureItem.__init__(self, cr) + self.dialog = None + self.screen = None + self.sound = None + + def announceGenerate(self): + self.accept('exitingStoppedState', self.destroyGui) + DistributedFurnitureItem.announceGenerate(self) + + def loadModel(self, animate=1): + model = DistributedFurnitureItem.loadModel(self) + + if animate: + pos = CatalogFurnitureItem.TvToPosScale[self.item.furnitureType] + self.screen = NodePath(CardMaker('tv-screen').generate()) + + model.find('**/toonTownBugTV_screen').hide() + self.screen.reparentTo(model) + self.screen.setScale(*pos[1]) + self.screen.setPos(*pos[0]) + self.resetScreen() + + cSphere = CollisionSphere(0.0, -1.5, 1.0, 1.575) + cSphere.setTangible(0) + colNode = CollisionNode('TV-%s' % self.doId) + colNode.addSolid(cSphere) + cSpherePath = model.attachNewNode(colNode) + cSpherePath.setCollideMask(ToontownGlobals.WallBitmask) + self.accept('enterTV-%s' % self.doId, self.__enterSphere) + return model + + def disable(self): + self.ignoreAll() + self.destroyGui() + self.destroySound() + DistributedFurnitureItem.disable(self) + + def setVideo(self, video, time): + if (not video) or (not time): + return + + self.destroySound() + self.startVideo(os.path.join('user', os.path.join('videos', video)), time) + + def getPack(self, name): + for pack in TTLocalizer.TVPacks: + if pack.lower() in name: + return pack + + return None + + def destroySound(self): + if self.sound: + self.sound.stop() + self.sound = None + + def destroyGui(self, arg=None): + if self.dialog: + self.dialog.destroy() + self.dialog = None + + def destroyGuiAndWalk(self, arg=None): + self.destroyGui() + base.cr.playGame.getPlace().setState('walk') + + def cutOff(self, string): + return string if len(string) < 24 else '%s...' % string[:24] + + def resetScreen(self): + self.screen.setTextureOff(TextureStage.getDefault()) + self.screen.setColor(0.3, 0.3, 0.3, 1.0) + + def startVideo(self, video, startTime): + if not os.path.exists(video): + pack = self.getPack(video) + base.localAvatar.setSystemMessage(0, TTLocalizer.TVUnknownVideoPack % pack if pack else TTLocalizer.TVUnknownVideo) + self.resetScreen() + return + + movie = loader.loadTexture(video) + self.sound = loader.loadSfx(video) + movie.synchronizeTo(self.sound) + self.screen.setColor(1, 1, 1, 1) + self.screen.setTexture(movie) + self.screen.setTexScale(TextureStage.getDefault(), movie.getTexScale()) + self.sound.setLoop(True) + self.sound.setTime(min(self.sound.length(), int(time.time() - startTime))) + self.sound.play() + + def __enterSphere(self, collisionEntry): + if base.localAvatar.doId != self.furnitureMgr.ownerId: + return + + videos = [] + gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui') + buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui') + buttonImage = (gui.find('**/FndsLst_ScrollUp'), gui.find('**/FndsLst_ScrollDN'), gui.find('**/FndsLst_ScrollUp_Rllvr'), gui.find('**/FndsLst_ScrollUp')) + base.cr.playGame.getPlace().setState('stopped') + self.dialog = DirectFrame(relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=ToontownGlobals.GlobalDialogColor, geom_scale=(1.33, 1, 1.4), + pos=(0, 0, 0), text=TTLocalizer.TVChooseVideo, text_scale=0.07, text_pos=(0, 0.575)) + + for file in sorted(glob.glob('user/videos/*.mp4')): + filename = ntpath.basename(file) + videos.append(DirectButton(relief=None, text=self.cutOff(filename[:-4]), text_pos=(0.0, -0.0225), text_scale=0.048, text_align=TextNode.ALeft, text_fg=(0, 0, 0, 1), text3_fg=(0.4, 0.8, 0.4, 1), text1_bg=(0.5, 0.9, 1, 1), text2_bg=(1, 1, 0, 1), command=self.chooseVideo, extraArgs=[filename])) + + scrollList = DirectScrolledList(parent=self.dialog, relief=None, pos=(-0.05, 0, 0), incButton_image=buttonImage, incButton_relief=None, incButton_scale=(1.3, 1.3, -1.3), + incButton_pos=(0.045, 0, -0.4), incButton_image3_color=(1, 1, 1, 0.2), decButton_image=buttonImage, decButton_relief=None, + decButton_scale=1.3, decButton_pos=(0.045, 0, 0.5), decButton_image3_color=(1, 1, 1, 0.2), itemFrame_pos=(-0.247, 0, 0.365), + itemFrame_scale=1.0, itemFrame_relief=DGG.SUNKEN, itemFrame_frameSize=(-0.02, 0.6, -0.7, 0.08), itemFrame_frameColor=(0.85, 0.95, 1, 1), + itemFrame_borderWidth=(0.01, 0.01), numItemsVisible=10, forceHeight=0.065, items=videos) + cancelButton = DirectButton(parent=self.dialog, relief=None, image=(buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr')), pos=(0, 0, -0.55), text=OTPLocalizer.lCancel, text_scale=0.06, text_pos=(0, -0.1), command=self.destroyGuiAndWalk) + + gui.removeNode() + buttons.removeNode() + + def chooseVideo(self, video): + self.destroyGuiAndWalk() + self.sendUpdate('requestVideo', [video]) + + def showDialog(self, text): + base.cr.playGame.getPlace().setState('stopped') + self.dialog = TTDialog.TTDialog(style=TTDialog.Acknowledge, text=text, text_wordwrap=15, fadeScreen=1, command=self.destroyGuiAndWalk) + + def requestVideoResponse(self, response): + if response == ToontownGlobals.TV_NOT_OWNER: + self.showDialog(TTLocalizer.TVNotOwner) + elif response == ToontownGlobals.TV_INVALID_VIDEO: + self.showDialog(TTLocalizer.TVInvalidVideo) + elif response == ToontownGlobals.TV_OK: + self.showDialog(TTLocalizer.TVOK) \ No newline at end of file diff --git a/toontown/estate/DistributedTVAI.py b/toontown/estate/DistributedTVAI.py new file mode 100644 index 00000000..0f287b64 --- /dev/null +++ b/toontown/estate/DistributedTVAI.py @@ -0,0 +1,32 @@ +from toontown.toonbase import ToontownGlobals +from DistributedFurnitureItemAI import DistributedFurnitureItemAI +import time + +class DistributedTVAI(DistributedFurnitureItemAI): + + def __init__(self, air, furnitureMgr, item): + DistributedFurnitureItemAI.__init__(self, air, furnitureMgr, item) + self.video = ['', 0] + + def d_setVideo(self, video): + self.sendUpdate('setVideo', video) + + def getVideo(self): + return self.video + + def requestVideo(self, video): + avId = self.air.getAvatarIdFromSender() + av = self.air.doId2do.get(avId) + + if not av: + return + elif self.furnitureMgr.ownerId != avId: + self.sendUpdateToAvatarId(avId, 'requestVideoResponse', [ToontownGlobals.TV_NOT_OWNER]) + return + elif not video.endswith('.mp4'): + self.sendUpdateToAvatarId(avId, 'requestVideoResponse', [ToontownGlobals.TV_INVALID_VIDEO]) + return + + self.video = [video, int(time.time())] + self.d_setVideo(self.video) + self.sendUpdateToAvatarId(avId, 'requestVideoResponse', [ToontownGlobals.TV_OK]) \ No newline at end of file diff --git a/toontown/toonbase/TTLocalizerEnglish.py b/toontown/toonbase/TTLocalizerEnglish.py index 812b5649..6cbbc605 100755 --- a/toontown/toonbase/TTLocalizerEnglish.py +++ b/toontown/toonbase/TTLocalizerEnglish.py @@ -8678,6 +8678,14 @@ GroupAskNoAccess = 'Sorry, but you have no teleport access %s %s.\n\nWould you s GroupAskNoAccessSame = 'Sorry, but you have no teleport access %s %s.' GroupAskAccess = 'Would you like to teleport %s %s in %s?' +TVNotOwner = 'Sorry, but this is not your TV.' +TVInvalidVideo = "Sorry, but we can't play that video. Make sure it is a MP4 video." +TVUnknownVideo = "Oops! Looks like the owner has picked a video to play which isn't currently on your computer!" +TVUnknownVideoPack = 'Oops! Looks like the owner has picked a video to play, but you need to download the %s TV Pack in the launcher.' +TVChooseVideo = 'Choose a video to play!' +TVOK = 'The video you selected is now playing!' +TVPacks = ['QuackityHQ'] + Blacklist = [ "$1ut", "$h1t", diff --git a/toontown/toonbase/ToontownGlobals.py b/toontown/toonbase/ToontownGlobals.py index 18704a29..9162dca8 100755 --- a/toontown/toonbase/ToontownGlobals.py +++ b/toontown/toonbase/ToontownGlobals.py @@ -1687,5 +1687,10 @@ TF_ALREADY_FRIENDS_NAME = 7 TF_SUCCESS = 8 GROUP_ZONES = [11000, 11100, 11200, 12000, 12100, 13000, 13100, 13200, 10000, 10100] + TOONUP_PULSE_ZONES = [ToontownCentral, DonaldsDock, DaisyGardens, MinniesMelodyland, TheBrrrgh, DonaldsDreamland] -TOONUP_FREQUENCY = 30 \ No newline at end of file +TOONUP_FREQUENCY = 30 + +TV_NOT_OWNER = 0 +TV_INVALID_VIDEO = 1 +TV_OK = 2 \ No newline at end of file