diff --git a/.gitignore b/.gitignore index 913fa7fd..e7a97233 100755 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,8 @@ # Local config dependencies/config/local.prc + +# PyMongo +bson +gridfs +pymongo \ No newline at end of file diff --git a/dependencies/astron/dclass/stride.dc b/dependencies/astron/dclass/stride.dc index 2735eafa..bd04e328 100644 --- a/dependencies/astron/dclass/stride.dc +++ b/dependencies/astron/dclass/stride.dc @@ -175,6 +175,9 @@ dclass FriendManager : DistributedObject { friendResponse(int8, int32); inviteeFriendQuery(int32, string, blob, int32); inviteeCancelFriendQuery(int32); + requestTFCode() airecv clsend; + redeemTFCode(string) airecv clsend; + tfResponse(uint8, string); }; from toontown.building import DistributedAnimatedProp/AI @@ -742,8 +745,9 @@ dclass DistributedToon : DistributedPlayer { setBuffs(uint32[] = []) required ownrecv db; setRedeemedCodes(string [] = []) required ownrecv db; setEmblems(uint32[] = [0, 0]) required ownrecv db; - setTrueFriends(uint32[] = []) required clsend ownrecv db; + setTrueFriends(uint32[] = []) required ownrecv db; setNextKnockHeal(uint32) ram airecv; + setTFRequest(uint32[] = [0, 0]) ram airecv; setEPP(uint8[] = []) required ownrecv db; setStats(uint32[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) required ownrecv db; requestNametagStyle(uint8) airecv ownsend; diff --git a/otp/friends/FriendManager.py b/otp/friends/FriendManager.py index 4daf48b5..0315a272 100755 --- a/otp/friends/FriendManager.py +++ b/otp/friends/FriendManager.py @@ -91,3 +91,14 @@ class FriendManager(DistributedObject.DistributedObject): self.notify.debug('Client: inviteeCancelFriendQuery(%d)' % context) messenger.send('cancelFriendInvitation', [context]) self.up_inviteeAcknowledgeCancel(context) + + def requestTFCode(self, callback): + self.tfCallback = callback + self.sendUpdate('requestTFCode') + + def redeemTFCode(self, code, callback): + self.tfCallback = callback + self.sendUpdate('redeemTFCode', [code]) + + def tfResponse(self, response, code): + self.tfCallback(response, code) \ No newline at end of file diff --git a/otp/friends/FriendManagerAI.py b/otp/friends/FriendManagerAI.py index 16352791..279a28ca 100755 --- a/otp/friends/FriendManagerAI.py +++ b/otp/friends/FriendManagerAI.py @@ -1,5 +1,56 @@ from direct.directnotify import DirectNotifyGlobal from direct.distributed.DistributedObjectAI import DistributedObjectAI +from otp.otpbase import OTPGlobals +from toontown.toonbase import ToontownGlobals +import datetime, uuid, time + +class AddTrueFriend: + + def __init__(self, manager, av, targetId, code): + self.air = manager.air + self.manager = manager + self.av = av + self.targetId = targetId + self.code = code + + def start(self): + self.air.dbInterface.queryObject(self.air.dbId, self.targetId, self.__gotAvatar) + + def __gotAvatar(self, dclass, fields): + dclasses = self.air.dclassesByName['DistributedToonAI'] + + if dclass != dclasses: + return + + friendsList = fields['setFriendsList'][0] + trueFriendsList = fields['setTrueFriends'][0] + name = fields['setName'][0] + avId = self.av.doId + + if avId in trueFriendsList: + self.manager.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_ALREADY_FRIENDS_NAME, name]) + return + elif avId not in friendsList: + if len(friendsList) >= OTPGlobals.MaxFriends: + self.manager.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_FRIENDS_LIST_FULL_HIM, name]) + return + + friendsList.append(avId) + + if self.targetId not in self.av.getFriendsList(): + self.av.extendFriendsList(self.targetId) + + if hasattr(self.manager, 'data'): + del self.manager.data[self.code] + else: + self.air.dbGlobalCursor.tfCodes.remove({'_id': self.code}) + + self.av.addTrueFriend(self.targetId) + trueFriendsList.append(avId) + self.air.send(dclasses.aiFormatUpdate('setFriendsList', self.targetId, self.targetId, self.air.ourChannel, [friendsList])) + self.air.send(dclasses.aiFormatUpdate('setTrueFriends', self.targetId, self.targetId, self.air.ourChannel, [trueFriendsList])) + self.manager.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_SUCCESS, name]) + del self.manager.tfFsms[avId] class FriendManagerAI(DistributedObjectAI): notify = DirectNotifyGlobal.directNotify.newCategory("FriendManagerAI") @@ -9,6 +60,15 @@ class FriendManagerAI(DistributedObjectAI): self.air = air self.currentContext = 0 self.requests = {} + self.tfFsms = {} + self.connectToDatabase() + + def connectToDatabase(self): + if not self.air.dbConn: + self.notify.warning('Not using mongodb, true friends will be non-persistent') + self.data = {} + else: + self.air.dbGlobalCursor.tfCodes.ensure_index('date', expireAfterSeconds=ToontownGlobals.TF_EXPIRE_SECS) def friendQuery(self, requested): avId = self.air.getAvatarIdFromSender() @@ -118,3 +178,67 @@ class FriendManagerAI(DistributedObjectAI): return del self.requests[context] + + def requestTFCode(self): + avId = self.air.getAvatarIdFromSender() + av = self.air.doId2do.get(avId) + + if not av: + return + + tfRequest = av.getTFRequest() + + if tfRequest[1] >= ToontownGlobals.MAX_TF_TRIES and tfRequest[0] >= time.time(): + self.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_COOLDOWN, '']) + return + + code = str(uuid.uuid4()) + + if hasattr(self, 'data'): + self.data[code] = avId + else: + self.air.dbGlobalCursor.tfCodes.insert({'_id': code, 'date': datetime.datetime.utcnow(), 'avId': avId}) + + av.b_setTFRequest((time.time() + ToontownGlobals.TF_COOLDOWN_SECS, tfRequest[1] + 1)) + self.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_SUCCESS, code]) + + def redeemTFCode(self, code): + avId = self.air.getAvatarIdFromSender() + + if avId in self.tfFsms: + self.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_TOO_FAST, '']) + return + + av = self.air.doId2do.get(avId) + + if not av: + return + + if hasattr(self, 'data'): + if code not in self.data: + self.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_UNKNOWN_SECRET, '']) + return + + targetId = self.data[code] + else: + fields = self.air.dbGlobalCursor.tfCodes.find_one({'_id': code}) + + if not fields: + self.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_UNKNOWN_SECRET, '']) + return + + targetId = fields['avId'] + + if avId == targetId: + self.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_SELF_SECRET, '']) + return + elif av.isTrueFriends(targetId): + self.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_ALREADY_FRIENDS, '']) + return + elif targetId not in av.getFriendsList() and len(av.getFriendsList()) >= OTPGlobals.MaxFriends: + self.sendUpdateToAvatarId(avId, 'tfResponse', [ToontownGlobals.TF_FRIENDS_LIST_FULL_YOU, '']) + return + + tfOperation = AddTrueFriend(self, av, targetId, code) + tfOperation.start() + self.tfFsms[avId] = tfOperation \ No newline at end of file diff --git a/otp/otpbase/OTPLocalizerEnglish.py b/otp/otpbase/OTPLocalizerEnglish.py index 26bdaaa2..d37d265f 100755 --- a/otp/otpbase/OTPLocalizerEnglish.py +++ b/otp/otpbase/OTPLocalizerEnglish.py @@ -234,6 +234,7 @@ FriendInviterConfirmRemove = 'Remove' FriendInviterYes = lYes FriendInviterNo = lNo FriendInviterClickToon = 'Click on the toon you would like to make friends with.' +FriendInviterTooMany = 'You have too many friends on your list to add another one now. You will have to remove some friends if you want to make friends with %s.' FriendInviterToonTooMany = 'You have too many toon friends on your list to add another one now. You will have to remove some toon friends if you want to make friends with %s.' FriendInviterNotYet = 'Would you like to make friends with %s?' FriendInviterCheckAvailability = 'Seeing if %s is available.' @@ -2345,4 +2346,4 @@ AccessToString = { 500: '\x01androidGreen\x01Developer\x02', 600: '\x01cobalt\x01Admin\x02', 700: '\x01azure\x01System Admin\x02' -} +} \ No newline at end of file diff --git a/toontown/distributed/ToontownClientRepository.py b/toontown/distributed/ToontownClientRepository.py index c14480d9..2a5cdbd8 100755 --- a/toontown/distributed/ToontownClientRepository.py +++ b/toontown/distributed/ToontownClientRepository.py @@ -30,6 +30,7 @@ from toontown.toonbase.ToontownGlobals import * from toontown.distributed import DelayDelete from toontown.friends import FriendHandle from toontown.friends import FriendsListPanel +from toontown.friends import ToontownFriendSecret from toontown.login import AvatarChooser from toontown.makeatoon import MakeAToon from toontown.pets import DistributedPet, PetDetail, PetHandle @@ -408,6 +409,7 @@ class ToontownClientRepository(OTPClientRepository.OTPClientRepository): if self.objectManager != None: self.objectManager.destroy() self.objectManager = None + ToontownFriendSecret.unloadFriendSecret() FriendsListPanel.unloadFriendsList() messenger.send('cancelFriendInvitation') base.removeGlitchMessage() @@ -663,7 +665,6 @@ class ToontownClientRepository(OTPClientRepository.OTPClientRepository): def removeFriend(self, avatarId): self.ttsFriendsManager.d_removeFriend(avatarId) - base.localAvatar.removeTrueFriends(avatarId) def clearFriendState(self): self.friendsMap = {} diff --git a/toontown/friends/FriendsListManager.py b/toontown/friends/FriendsListManager.py index 5d7e2a1b..257d7eb3 100755 --- a/toontown/friends/FriendsListManager.py +++ b/toontown/friends/FriendsListManager.py @@ -5,6 +5,7 @@ import FriendInvitee import FriendNotifier from direct.directnotify import DirectNotifyGlobal from toontown.toon import ToonTeleportPanel +from toontown.friends import ToontownFriendSecret from toontown.pets import PetAvatarPanel from toontown.toon import ToonAvatarPanel from toontown.suit import SuitAvatarPanel @@ -73,6 +74,7 @@ class FriendsListManager: self.ignore('friendAvatar') self.ignore('avatarDetails') FriendsListPanel.hideFriendsList() + ToontownFriendSecret.hideFriendSecret() if base.cr.friendManager: base.cr.friendManager.setAvailable(0) self.ignore('friendInvitation') diff --git a/toontown/friends/FriendsListPanel.py b/toontown/friends/FriendsListPanel.py index 1abaf5fe..27d5da25 100755 --- a/toontown/friends/FriendsListPanel.py +++ b/toontown/friends/FriendsListPanel.py @@ -2,6 +2,7 @@ from panda3d.core import * from direct.gui.DirectGui import * from direct.fsm import StateData from toontown.toon import ToonAvatarPanel +from toontown.friends import ToontownFriendSecret from toontown.toonbase import ToontownGlobals from toontown.toonbase import TTLocalizer from otp.nametag.NametagGroup import * @@ -94,7 +95,6 @@ class FriendsListPanel(DirectFrame, StateData.StateData): self.textDownColor = Vec4(0.5, 0.9, 1, 1) self.textDisabledColor = Vec4(0.4, 0.8, 0.4, 1) self.panelType = FLPOnline - return def load(self): if self.isLoaded == 1: @@ -128,9 +128,12 @@ class FriendsListPanel(DirectFrame, StateData.StateData): gui.find('**/Horiz_Arrow_Rllvr'), gui.find('**/Horiz_Arrow_UP')), image3_color=Vec4(0.6, 0.6, 0.6, 0.6), pos=(0.17, 0, -0.38), command=self.__right) self.newFriend = DirectButton(parent=self, relief=None, pos=(-0.14, 0.0, 0.14), image=(auxGui.find('**/Frnds_Btn_UP'), auxGui.find('**/Frnds_Btn_DN'), auxGui.find('**/Frnds_Btn_RLVR')), text=('', TTLocalizer.FriendsListPanelNewFriend, TTLocalizer.FriendsListPanelNewFriend), text_scale=TTLocalizer.FLPnewFriend, text_fg=(0, 0, 0, 1), text_bg=(1, 1, 1, 1), text_pos=(0.1, -0.085), textMayChange=0, command=self.__newFriend) + self.trueFriends = DirectButton(parent=self, relief=None, pos=TTLocalizer.FLPtruefriendsPos, image=(auxGui.find('**/ChtBx_ChtBtn_UP'), auxGui.find('**/ChtBx_ChtBtn_DN'), auxGui.find('**/ChtBx_ChtBtn_RLVR')), text=('', + TTLocalizer.FriendsListPanelTrueFriends, + TTLocalizer.FriendsListPanelTrueFriends, + ''), text_scale=TTLocalizer.FLPtruefriends, text_fg=(0, 0, 0, 1), text_bg=(1, 1, 1, 1), text_pos=(-0.04, -0.085), textMayChange=0, command=self.__trueFriends) gui.removeNode() auxGui.removeNode() - return def unload(self): if self.isLoaded == 0: @@ -144,7 +147,6 @@ class FriendsListPanel(DirectFrame, StateData.StateData): del self.right del self.friends DirectFrame.destroy(self) - return None def makeFriendButton(self, avId, color): handle = base.cr.identifyFriend(avId) @@ -212,10 +214,13 @@ class FriendsListPanel(DirectFrame, StateData.StateData): self.__updateTitle() self.__updateArrows() + def __trueFriends(self): + messenger.send('wakeup') + ToontownFriendSecret.showFriendSecret() + def __newFriend(self): messenger.send('wakeup') messenger.send('friendAvatar', [None, None, None]) - return def __choseFriend(self, friendId): messenger.send('wakeup') diff --git a/toontown/friends/TTSFriendsManagerUD.py b/toontown/friends/TTSFriendsManagerUD.py index 5a118b5b..36e1bffc 100755 --- a/toontown/friends/TTSFriendsManagerUD.py +++ b/toontown/friends/TTSFriendsManagerUD.py @@ -95,10 +95,11 @@ class RemoveFriendOperation(OperationFSM): self.demand('Error', 'Distributed Class was not a Toon.') return - self.demand('Retrieved', fields['setFriendsList'][0]) + self.demand('Retrieved', fields['setFriendsList'][0], fields['setTrueFriends'][0]) - def enterRetrieved(self, friendsList): + def enterRetrieved(self, friendsList, trueFriendsList): friendsList.remove(self.target) + trueFriendsList.remove(self.target) if self.sender in self.mgr.onlineToons: dg = self.air.dclassesByName['DistributedToonUD'].aiFormatUpdate( 'setFriendsList', self.sender, self.sender, @@ -114,7 +115,7 @@ class RemoveFriendOperation(OperationFSM): self.air.dbInterface.updateObject(self.air.dbId, self.sender, self.air.dclassesByName['DistributedToonUD'], - {'setFriendsList' : [friendsList]}) + {'setFriendsList' : [friendsList], 'setTrueFriends' : [trueFriendsList]}) self.demand('Off') # -- Clear List -- diff --git a/toontown/friends/ToontownFriendSecret.py b/toontown/friends/ToontownFriendSecret.py new file mode 100644 index 00000000..f4e041f7 --- /dev/null +++ b/toontown/friends/ToontownFriendSecret.py @@ -0,0 +1,197 @@ +from pandac.PandaModules import * +from direct.gui.DirectGui import * +from direct.directnotify import DirectNotifyGlobal +from toontown.toonbase import TTLocalizer, ToontownGlobals +from otp.otpbase import OTPGlobals + +globalFriendSecret = None + +def showFriendSecret(): + global globalFriendSecret + if not settings['trueFriends']: + chatMgr = base.localAvatar.chatMgr + chatMgr.fsm.request('noTrueFriends') + else: + if globalFriendSecret != None: + globalFriendSecret.unload() + globalFriendSecret = ToontownFriendSecret() + globalFriendSecret.enter() + +def hideFriendSecret(): + if globalFriendSecret != None: + globalFriendSecret.exit() + +def unloadFriendSecret(): + global globalFriendSecret + if globalFriendSecret != None: + globalFriendSecret.unload() + globalFriendSecret = None + return + +class ToontownFriendSecret(DirectFrame): + notify = DirectNotifyGlobal.directNotify.newCategory('ToontownFriendSecret') + + def __init__(self): + DirectFrame.__init__(self, parent=aspect2dp, pos=(0, 0, 0.3), relief=None, image=DGG.getDefaultDialogGeom(), image_scale=(1.6, 1, 1.4), image_pos=(0, 0, -0.05), image_color=OTPGlobals.GlobalDialogColor, borderWidth=(0.01, 0.01)) + self.initialiseoptions(ToontownFriendSecret) + self.isLoaded = 0 + self.isEntered = 0 + + def unload(self): + if self.isLoaded == 0: + return None + self.isLoaded = 0 + self.exit() + del self.introText + del self.getSecret + del self.enterSecretText + del self.enterSecret + del self.ok1 + del self.ok2 + del self.cancel + del self.secretText + DirectFrame.destroy(self) + + def load(self): + if self.isLoaded == 1: + return None + self.isLoaded = 1 + self.introText = DirectLabel(parent=self, relief=None, pos=(0, 0, 0.4), scale=0.05, text=TTLocalizer.FriendSecretIntro, text_fg=(0, 0, 0, 1), text_wordwrap=30) + self.introText.hide() + guiButton = loader.loadModel('phase_3/models/gui/quit_button') + self.getSecret = DirectButton(parent=self, relief=None, pos=(0, 0, -0.11), image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=TTLocalizer.FSgetSecret, text=TTLocalizer.FriendSecretGetSecret, text_scale=TTLocalizer.FSgetSecretButton, text_pos=(0, -0.02), command=self.__getSecret) + self.getSecret.hide() + self.enterSecretText = DirectLabel(parent=self, relief=None, pos=TTLocalizer.FSenterSecretTextPos, scale=0.05, text=TTLocalizer.FriendSecretEnterSecret, text_fg=(0, 0, 0, 1), text_wordwrap=30) + self.enterSecretText.hide() + self.enterSecret = DirectEntry(parent=self, relief=DGG.SUNKEN, scale=0.06, pos=(-0.6, 0, -0.38), frameColor=(0.8, 0.8, 0.5, 1), borderWidth=(0.1, 0.1), numLines=1, width=20, frameSize=(-0.4, + 20.4, + -0.4, + 1.1), command=self.__enterSecret) + self.enterSecret.resetFrameSize() + self.enterSecret.hide() + self.ok1 = DirectButton(parent=self, relief=None, image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=TTLocalizer.FSok1, text=TTLocalizer.FriendSecretEnter, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.5), command=self.__ok1) + self.ok1.hide() + self.ok2 = DirectButton(parent=self, relief=None, image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=TTLocalizer.FSok2, text=TTLocalizer.FriendSecretOK, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.57), command=self.__ok2) + self.ok2.hide() + self.cancel = DirectButton(parent=self, relief=None, text=TTLocalizer.FriendSecretCancel, image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=TTLocalizer.FScancel, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.57), command=self.__cancel) + self.cancel.hide() + self.nextText = DirectLabel(parent=self, relief=None, pos=(0, 0, 0.3), scale=0.06, text='', text_scale=TTLocalizer.FSnextText, text_fg=(0, 0, 0, 1), text_wordwrap=25.5) + self.nextText.hide() + self.secretText = DirectLabel(parent=self, relief=None, pos=(0, 0, -0.42), scale=0.08, text='', text_fg=(0, 0, 0, 1), text_wordwrap=30) + self.secretText.hide() + guiButton.removeNode() + + def enter(self): + if self.isEntered == 1: + return + self.isEntered = 1 + if self.isLoaded == 0: + self.load() + self.show() + self.introText.show() + self.getSecret.show() + self.enterSecretText.show() + self.enterSecret.show() + self.ok1.show() + self.ok2.hide() + self.cancel.hide() + self.nextText.hide() + self.secretText.hide() + base.localAvatar.chatMgr.fsm.request('otherDialog') + self.enterSecret['focus'] = 1 + + def exit(self): + if self.isEntered == 0: + return + self.isEntered = 0 + self.__cleanupFirstPage() + self.hide() + + def __getSecret(self): + self.__cleanupFirstPage() + self.nextText['text'] = TTLocalizer.FriendSecretGettingSecret + self.nextText.setPos(0, 0, 0.3) + self.nextText.show() + self.ok1.hide() + self.cancel.show() + base.cr.friendManager.requestTFCode(self.gotSecret) + + def gotSecret(self, response, code): + if response == ToontownGlobals.TF_COOLDOWN: + self.rejectGetSecret(TTLocalizer.FriendSecretTooMany) + elif response == ToontownGlobals.TF_SUCCESS: + self.successGetSecret(code) + + def rejectGetSecret(self, reason): + self.nextText['text'] = reason + self.nextText.show() + self.secretText.show() + self.cancel.hide() + self.ok1.hide() + self.ok2.show() + + def successGetSecret(self, code): + self.nextText['text'] = TTLocalizer.FriendSecretGotSecret % code + self.nextText.setPos(*TTLocalizer.FSgotSecretPos) + self.secretText['text'] = secret + self.nextText.show() + self.secretText.show() + self.cancel.hide() + self.ok1.hide() + self.ok2.show() + + def __enterSecret(self, secret): + self.enterSecret.set('') + secret = secret.strip() + + if not secret: + self.exit() + return + + self.__cleanupFirstPage() + self.nextText['text'] = TTLocalizer.FriendSecretTryingSecret + base.cr.friendManager.redeemTFCode(secret, self.gotResponse) + self.nextText.setPos(0, 0, 0.3) + self.nextText.show() + self.cancel.hide() + self.ok1.hide() + self.ok2.show() + + def gotResponse(self, response, name): + if response == ToontownGlobals.TF_UNKNOWN_SECRET: + self.nextText['text'] = TTLocalizer.FriendSecretEnteredSecretUnknown + elif response == ToontownGlobals.TF_SELF_SECRET: + self.nextText['text'] = TTLocalizer.FriendSecretEnteredSecretSelf + elif response == ToontownGlobals.TF_TOO_FAST: + self.nextText['text'] = TTLocalizer.FriendSecretTooFast + elif response == ToontownGlobals.TF_FRIENDS_LIST_FULL_YOU: + self.nextText['text'] = TTLocalizer.FriendSecretEnteredSecretFullYou + elif response == ToontownGlobals.TF_FRIENDS_LIST_FULL_HIM: + self.nextText['text'] = TTLocalizer.FriendSecretEnteredSecretFullHim % name + elif response == ToontownGlobals.TF_ALREADY_FRIENDS: + self.nextText['text'] = TTLocalizer.FriendSecretAlreadyFriends + elif response == ToontownGlobals.TF_ALREADY_FRIENDS_NAME: + self.nextText['text'] = TTLocalizer.FriendSecretAlreadyFriendsName % name + elif response == ToontownGlobals.TF_SUCCESS: + self.nextText['text'] = TTLocalizer.FriendSecretNowFriends % name + self.nextText.show() + self.cancel.hide() + self.ok1.hide() + self.ok2.show() + + def __ok1(self): + secret = self.enterSecret.get() + self.__enterSecret(secret) + + def __ok2(self): + self.exit() + + def __cancel(self): + self.exit() + + def __cleanupFirstPage(self): + self.introText.hide() + self.getSecret.hide() + self.enterSecretText.hide() + self.enterSecret.hide() + base.localAvatar.chatMgr.fsm.request('mainMenu') diff --git a/toontown/toon/DistributedToon.py b/toontown/toon/DistributedToon.py index dac18f42..a787138b 100755 --- a/toontown/toon/DistributedToon.py +++ b/toontown/toon/DistributedToon.py @@ -2384,30 +2384,13 @@ class DistributedToon(DistributedPlayer.DistributedPlayer, Toon.Toon, Distribute if not self.isReported(doId): self.reported.append(doId) - def b_setTrueFriends(self, trueFriends): - self.setTrueFriends(trueFriends) - self.d_setTrueFriends(trueFriends) - def setTrueFriends(self, trueFriends): Toon.reconsiderAllToonsUnderstandable() self.trueFriends = trueFriends - def d_setTrueFriends(self, trueFriends): - self.sendUpdate('setTrueFriends', [trueFriends]) - def isTrueFriends(self, doId): return doId in self.trueFriends - def addTrueFriends(self, doId): - if not self.isTrueFriends(doId): - self.trueFriends.append(doId) - self.b_setTrueFriends(self.trueFriends) - - def removeTrueFriends(self, doId): - if self.isTrueFriends(doId): - self.trueFriends.remove(doId) - self.b_setTrueFriends(self.trueFriends) - def applyBuffs(self): for id, timestamp in enumerate(self.buffs): if id == ToontownGlobals.BMovementSpeed: diff --git a/toontown/toon/DistributedToonAI.py b/toontown/toon/DistributedToonAI.py index d7077fd5..fd5a0f2b 100755 --- a/toontown/toon/DistributedToonAI.py +++ b/toontown/toon/DistributedToonAI.py @@ -161,6 +161,7 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo self.trueFriends = [] self.fishBingoTutorialDone = False self.nextKnockHeal = 0 + self.tfRequest = (0, 0) self.epp = [] def generate(self): @@ -4091,7 +4092,7 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo self.b_setRedeemedCodes(self.redeemedCodes) def setTrueFriends(self, trueFriends): - self.trueFriends = trueFriends[:OTPGlobals.MaxFriends] + self.trueFriends = trueFriends def d_setTrueFriends(self, trueFriends): self.sendUpdate('setTrueFriends', [trueFriends]) @@ -4099,6 +4100,16 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo def b_setTrueFriends(self, trueFriends): self.setTrueFriends(trueFriends) self.d_setTrueFriends(trueFriends) + + def isTrueFriends(self, avId): + return avId in self.trueFriends + + def addTrueFriend(self, avId): + if avId in self.trueFriends: + return + + self.trueFriends.append(avId) + self.b_setTrueFriends(self.trueFriends) def getTrueFriends(self, trueFriends): return self.trueFriends @@ -4115,6 +4126,19 @@ class DistributedToonAI(DistributedPlayerAI.DistributedPlayerAI, DistributedSmoo def getNextKnockHeal(self): return self.nextKnockHeal + + def setTFRequest(self, tfRequest): + self.tfRequest = tfRequest + + def d_setTFRequest(self, tfRequest): + self.sendUpdate('setTFRequest', [tfRequest]) + + def b_setTFRequest(self, tfRequest): + self.setTFRequest(tfRequest) + self.d_setTFRequest(tfRequest) + + def getTFRequest(self): + return self.tfRequest def setEPP(self, epp): self.epp = epp diff --git a/toontown/toon/ToonAvatarPanel.py b/toontown/toon/ToonAvatarPanel.py index b93a5429..50def5d4 100755 --- a/toontown/toon/ToonAvatarPanel.py +++ b/toontown/toon/ToonAvatarPanel.py @@ -8,6 +8,7 @@ from direct.distributed import DistributedObject from direct.directnotify import DirectNotifyGlobal from toontown.toonbase import ToontownGlobals from toontown.toonbase import TTLocalizer +from toontown.friends import ToontownFriendSecret import ToonAvatarDetailPanel import AvatarPanelBase from toontown.toontowngui import TTDialog @@ -353,6 +354,10 @@ class ToonAvatarPanel(AvatarPanelBase.AvatarPanelBase): def __handleWhisper(self): base.localAvatar.chatMgr.whisperTo(self.avName, self.avId) + def __handleTrueFriends(self): + base.localAvatar.chatMgr.noWhisper() + ToontownFriendSecret.showFriendSecret() + def __handleFriend(self): base.localAvatar.chatMgr.noWhisper() messenger.send('friendAvatar', [self.avId, self.avName, self.avDisableName]) @@ -549,47 +554,4 @@ class ToonAvatarPanel(AvatarPanelBase.AvatarPanelBase): self.boardingInfoText = None groupInviteGui.removeNode() groupAvatarBgGui.removeNode() - helpGui.removeNode() - return - - def __handleTrueFriends(self): - if not settings['trueFriends']: - base.localAvatar.chatMgr.fsm.request('noTrueFriends') - return - - self.cleanupDialog() - base.cr.playGame.getPlace().fsm.request('stopped') - - if base.localAvatar.isTrueFriends(self.avatar.doId): - self.dialog = TTDialog.TTDialog(style=TTDialog.YesNo, text=TTLocalizer.TrueFriendsRemoveNotice % self.avatar.getName(), text_wordwrap=20, command=self.confirmTrueFriendsRemove) - self.dialog.show() - elif not base.cr.isFriend(self.avatar.doId): - self.dialog = TTDialog.TTDialog(style=TTDialog.Acknowledge, text=TTLocalizer.TrueFriendsNotFriends % self.avatar.getName(), text_wordwrap=20, command=self.cleanupDialogAndWalk) - self.dialog.show() - else: - self.dialog = TTDialog.TTDialog(style=TTDialog.YesNo, text=TTLocalizer.TrueFriendsAddNotice % self.avatar.getName(), text_wordwrap=20, command=self.confirmTrueFriendsAdd) - self.dialog.show() - - def confirmTrueFriendsAdd(self, state): - self.cleanupDialog() - - if state > 0: - base.localAvatar.addTrueFriends(self.avatar.doId) - self.dialog = TTDialog.TTDialog(style=TTDialog.Acknowledge, text=TTLocalizer.TrueFriendsAdded.replace('%s', self.avatar.getName()), text_wordwrap=20, command=self.cleanupDialogAndWalk) - self.dialog.show() - else: - base.cr.playGame.getPlace().fsm.request('walk') - - def confirmTrueFriendsRemove(self, state): - self.cleanupDialog() - - if state > 0: - base.localAvatar.removeTrueFriends(self.avatar.doId) - self.dialog = TTDialog.TTDialog(style=TTDialog.Acknowledge, text=TTLocalizer.TrueFriendsRemoved % self.avatar.getName(), text_wordwrap=20, command=self.cleanupDialogAndWalk) - self.dialog.show() - else: - base.cr.playGame.getPlace().fsm.request('walk') - - def cleanupDialogAndWalk(self, state=None): - self.cleanupDialog() - base.cr.playGame.getPlace().fsm.request('walk') + helpGui.removeNode() \ No newline at end of file diff --git a/toontown/toonbase/TTLocalizerEnglish.py b/toontown/toonbase/TTLocalizerEnglish.py index e7489cbc..ff424dfc 100755 --- a/toontown/toonbase/TTLocalizerEnglish.py +++ b/toontown/toonbase/TTLocalizerEnglish.py @@ -3247,6 +3247,7 @@ FriendsListPanelNewFriend = 'New Friend' FriendsListPanelOnlineFriends = 'ONLINE TOON\nFRIENDS' FriendsListPanelAllFriends = 'ALL TOON\nFRIENDS' FriendsListPanelPets = 'NEARBY\nPETS' +FriendsListPanelTrueFriends = 'True Friends' FriendInviterClickToon = 'Click on the toon you would like to make friends with.\n\n(You have %s friends)' FriendInviterThatToon = 'That toon' FriendInviterToonTooMany = 'You have too many toon friends to add another one now. You will have to remove some toon friends if you want to make friends with %s.' @@ -8491,11 +8492,6 @@ CogPanelSkeleton = 'Skeleton' CogPanelVirtual = 'Virtual' CogPanelRevives = 'v%s.0' CogPanelWaiter = 'Waiter' -TrueFriendsRemoveNotice = 'Are you sure you want to remove %s as your True Friend?\n\nYou will no longer be able to chat without limits.' -TrueFriendsNotFriends = 'You cannot be True Friends with %s until you are regular friends first.' -TrueFriendsAddNotice = 'If you are playing Toontown with someone you trust, you can become True Friends.\n\nYou can chat using the keyboard with your True Friends.\n\nOther Toons won\'t understand what you\'re saying.\n\n\x01WLRed\x01However, this chat is completely unfiltered.\x02\n\nAre you sure you want to be True Friends with %s?' -TrueFriendsAdded = 'You are now True Friends with %s!\n\nYou can now understand everything %s says.\n\nHowever, chances are %s hasn\'t added you as a True Friend yet.\n\nIf this is the case, he cannot understand you yet. Please ask %s to add you as a True Friend aswell!' -TrueFriendsRemoved = 'You are no longer True Friends with %s.' def convertSecondsToDate(seconds): m, s = divmod(seconds, 60) @@ -8654,6 +8650,25 @@ StatResetDone = 'Your stats have been reset.' ChairAskToUse = 'Would you like to sit on this chair?' +FriendSecretIntro = "If you are playing Toontown Stride with someone you know in the real world, you can become True Friends. You can chat using the keyboard with your True Friends. Other Toons won't understand what you're saying.\n\nYou do this by getting a True Friend Code. Tell the True Friend Code to your friend, but not to anyone else. When your friend types in your True Friend Code on his or her screen, you'll be True Friends in Toontown!" +FriendSecretGetSecret = 'Get a True Friend Code' +FriendSecretEnterSecret = 'If you have a True Friend Code from someone you know, type it here.' +FriendSecretOK = lOK +FriendSecretEnter = 'Enter True Friend Code' +FriendSecretCancel = lCancel +FriendSecretGettingSecret = 'Getting True Friend Code. . .' +FriendSecretGotSecret = "Here is your new True Friend Code. Be sure to write it down!\n\nYou may give this True Friend Code to one person only. Once someone types in your True Friend Code, it will not work for anyone else. If you want to give a True Friend Code to more than one person, get another True Friend Code.\n\nThe True Friend Code will only work for the next three days. Your friend will have to type it in before it goes away, or it won't work.\n\nYour True Friend Code is: %s" +FriendSecretTooMany = "Sorry, you can't have any more True Friend Codes today. You've already had more than your fair share!\n\nTry again tomorrow." +FriendSecretTryingSecret = 'Trying True Friend Code. . .' +FriendSecretEnteredSecretUnknown = "That's not anyone's True Friend Code. Are you sure you spelled it correctly?\n\nIf you did type it correctly, it may have expired. Ask your friend to get a new True Friend Code for you (or get a new one yourself and give it to your friend)." +FriendSecretEnteredSecretFullYou = "You can't be True Friends because you have too many friends on your friends list." +FriendSecretEnteredSecretFullHim = "You can't be True Friends because %s has too many friends on his friends list." +FriendSecretAlreadyFriends = 'You are already True Friends!' +FriendSecretAlreadyFriendsName = 'You are already True Friends with %s!' +FriendSecretEnteredSecretSelf = 'You just typed in your own True Friend Code!' +FriendSecretTooFast = 'You are redeeming codes too fast! Please wait a few seconds.' +FriendSecretNowFriends = 'You are now True Friends with %s!' + Blacklist = [ "$1ut", "$h1t", diff --git a/toontown/toonbase/TTLocalizerEnglishProperty.py b/toontown/toonbase/TTLocalizerEnglishProperty.py index 3073ad24..16038f24 100755 --- a/toontown/toonbase/TTLocalizerEnglishProperty.py +++ b/toontown/toonbase/TTLocalizerEnglishProperty.py @@ -56,6 +56,8 @@ FPnewEntry = 0.08 FPnewRecord = 0.08 GPgenus = 0.045 FLPnewFriend = 0.045 +FLPtruefriends = 0.045 +FLPtruefriendsPos = (0.152, 0.0, 0.14) FLPtitle = 0.04 FIbStop = 0.05 FIdirectFrame = 0.06 @@ -283,6 +285,14 @@ TPhaveFun = 0.1 TPjoinUs = 0.1 TBSOSPSPenter = 0.1 TexitButton = 0.8 +FSenterSecretTextPos = (0, 0, -0.25) +FSgotSecretPos = (0, 0, 0.47) +FSgetSecretButton = 0.06 +FSnextText = 1.0 +FSgetSecret = (1.55, 1, 1) +FSok1 = (1.55, 1, 1) +FSok2 = (0.6, 1, 1) +FScancel = (0.6, 1, 1) #Some languages need to change the word order SellbotFactoryPosPart1 = (0, -0.25) SellbotFactoryScalePart1 = 0.075 diff --git a/toontown/toonbase/ToontownGlobals.py b/toontown/toonbase/ToontownGlobals.py index 450bd290..e381c298 100755 --- a/toontown/toonbase/ToontownGlobals.py +++ b/toontown/toonbase/ToontownGlobals.py @@ -1671,4 +1671,17 @@ CHAIR_START = 0 CHAIR_STOP = 1 CHAIR_NONE = 0 CHAIR_EXIT = 1 -CHAIR_UNEXPECTED_EXIT = 2 \ No newline at end of file +CHAIR_UNEXPECTED_EXIT = 2 + +MAX_TF_TRIES = 5 +TF_COOLDOWN_SECS = 60 * 60 * 24 +TF_EXPIRE_SECS = 3 * 60 * 60 * 24 +TF_COOLDOWN = 0 +TF_UNKNOWN_SECRET = 1 +TF_SELF_SECRET = 2 +TF_TOO_FAST = 3 +TF_FRIENDS_LIST_FULL_YOU = 4 +TF_FRIENDS_LIST_FULL_HIM = 5 +TF_ALREADY_FRIENDS = 6 +TF_ALREADY_FRIENDS_NAME = 7 +TF_SUCCESS = 8 \ No newline at end of file