Friends: True friend codes can now be generated
This commit is contained in:
parent
a9eb3c2ea0
commit
05d73cb4fb
|
|
@ -2874,6 +2874,7 @@ dclass ToontownFriendsManager : DistributedObject {
|
|||
makeFriendsResponse(uint32, uint32, uint8, uint32) airecv;
|
||||
removeFriend(uint32) clsend;
|
||||
requestSecret(uint32);
|
||||
requestSecretResponse(uint8, string, uint32) airecv;
|
||||
};
|
||||
|
||||
dclass TTSpeedchatRelay : SpeedchatRelay {
|
||||
|
|
|
|||
|
|
@ -50,9 +50,11 @@ class FriendManagerAI(DistributedObjectGlobalAI):
|
|||
# will be sent in response to secret requests to the database,
|
||||
# via the AIR.
|
||||
self.accept("makeFriendsReply", self.makeFriendsReply)
|
||||
self.accept("requestSecretReply", self.requestSecretReply)
|
||||
|
||||
def delete(self):
|
||||
self.ignore("makeFriendsReply")
|
||||
self.ignore("requestSecretReply")
|
||||
DistributedObjectGlobalAI.delete(self)
|
||||
|
||||
### Messages sent from inviter client to AI
|
||||
|
|
@ -409,3 +411,18 @@ class FriendManagerAI(DistributedObjectGlobalAI):
|
|||
avatar.d_friendsNotify(invite.inviterId, 2)
|
||||
|
||||
self.clearInvite(invite)
|
||||
|
||||
def requestSecretReply(self, result, secret, requesterId):
|
||||
self.down_requestSecretResponse(requesterId, result, secret)
|
||||
|
||||
def down_requestSecretResponse(self, recipient, result, secret):
|
||||
"""requestSecret(self, int8 result, string secret)
|
||||
|
||||
Sent by the AI to the client in response to requestSecret().
|
||||
result is one of:
|
||||
|
||||
0 - Too many secrets outstanding. Try again later.
|
||||
1 - Success. The new secret is supplied.
|
||||
|
||||
"""
|
||||
self.sendUpdateToAvatarId(recipient, 'requestSecretResponse', [result, secret])
|
||||
|
|
@ -1,59 +1,67 @@
|
|||
from panda3d.core import *
|
||||
from panda3d.otp import *
|
||||
from direct.gui.DirectGui import *
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
from direct.fsm import StateData
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from direct.gui.DirectGui import *
|
||||
from panda3d.core import *
|
||||
from panda3d.otp import NametagGlobals
|
||||
|
||||
from otp.otpbase import OTPGlobals
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from otp.uberdog import RejectCode
|
||||
|
||||
globalFriendSecret = None
|
||||
AccountSecret = 0
|
||||
AvatarSecret = 1
|
||||
BothSecrets = 2
|
||||
|
||||
def showFriendSecret(secretType = AvatarSecret):
|
||||
|
||||
def showFriendSecret(secretType=AvatarSecret):
|
||||
"""
|
||||
Added optional parameter to offer the choice between account and avatar friend tokens.
|
||||
"""
|
||||
# A module function to open the global secret panel.
|
||||
global globalFriendSecret
|
||||
if not base.cr.isPaid():
|
||||
# bring up teaser panel
|
||||
chatMgr = base.localAvatar.chatMgr
|
||||
chatMgr.fsm.request('trueFriendTeaserPanel')
|
||||
chatMgr.fsm.request("trueFriendTeaserPanel")
|
||||
elif not base.cr.isParentPasswordSet():
|
||||
# non-COPPA gamecard user: prompt to leave game and set parent password
|
||||
chatMgr = base.localAvatar.chatMgr
|
||||
if base.cr.productName in ['DisneyOnline-AP',
|
||||
'DisneyOnline-UK',
|
||||
'JP',
|
||||
'DE',
|
||||
'BR',
|
||||
'FR']:
|
||||
if base.cr.productName in ['DisneyOnline-AP', 'DisneyOnline-UK', 'JP', 'DE', 'BR', 'FR']:
|
||||
chatMgr = base.localAvatar.chatMgr
|
||||
if not base.cr.isPaid():
|
||||
chatMgr.fsm.request('unpaidChatWarning')
|
||||
chatMgr.fsm.request("unpaidChatWarning")
|
||||
else:
|
||||
chatMgr.paidNoParentPassword = 1
|
||||
chatMgr.fsm.request('unpaidChatWarning')
|
||||
chatMgr.fsm.request("unpaidChatWarning")
|
||||
else:
|
||||
chatMgr.paidNoParentPassword = 1
|
||||
chatMgr.fsm.request('noSecretChatAtAll')
|
||||
chatMgr.fsm.request("noSecretChatAtAll") # bring up dialog for true friends # open chat with true friends
|
||||
|
||||
elif not base.cr.allowSecretChat():
|
||||
# If we're paid but have not yet activated secrets, pop up the
|
||||
# dialog to do this.
|
||||
chatMgr = base.localAvatar.chatMgr
|
||||
if base.cr.productName in ['DisneyOnline-AP',
|
||||
'DisneyOnline-UK',
|
||||
'JP',
|
||||
'DE',
|
||||
'BR',
|
||||
'FR']:
|
||||
if base.cr.productName in ['DisneyOnline-AP', 'DisneyOnline-UK', 'JP', 'DE', 'BR', 'FR']:
|
||||
chatMgr = base.localAvatar.chatMgr
|
||||
if not base.cr.isPaid():
|
||||
chatMgr.fsm.request('unpaidChatWarning')
|
||||
chatMgr.fsm.request("unpaidChatWarning")
|
||||
else:
|
||||
chatMgr.paidNoParentPassword = 1
|
||||
chatMgr.fsm.request('unpaidChatWarning')
|
||||
chatMgr.fsm.request("unpaidChatWarning")
|
||||
else:
|
||||
chatMgr.fsm.request('noSecretChatAtAll')
|
||||
# we no longer offer the ability to enable chat in game
|
||||
# chatMgr.fsm.request("noSecretChatWarning")
|
||||
chatMgr.fsm.request("noSecretChatAtAll")
|
||||
elif base.cr.needParentPasswordForSecretChat():
|
||||
# If we're paid but have the flag set to require the Parent Password to be
|
||||
# entered to get or use a Secret Friends password, pop up the
|
||||
# dialog to get the Parent Password.
|
||||
unloadFriendSecret()
|
||||
globalFriendSecret = FriendSecretNeedsParentLogin(secretType)
|
||||
globalFriendSecret.enter()
|
||||
else:
|
||||
# Otherwise, actually open the secrets panel.
|
||||
openFriendSecret(secretType)
|
||||
|
||||
|
||||
|
|
@ -63,53 +71,60 @@ def openFriendSecret(secretType):
|
|||
globalFriendSecret.unload()
|
||||
globalFriendSecret = FriendSecret(secretType)
|
||||
globalFriendSecret.enter()
|
||||
return
|
||||
|
||||
|
||||
def hideFriendSecret():
|
||||
# A module function to close the global secret panel if it is open.
|
||||
if globalFriendSecret != None:
|
||||
globalFriendSecret.exit()
|
||||
return
|
||||
|
||||
|
||||
def unloadFriendSecret():
|
||||
# A module function to completely unload the global secret panel.
|
||||
global globalFriendSecret
|
||||
if globalFriendSecret != None:
|
||||
globalFriendSecret.unload()
|
||||
globalFriendSecret = None
|
||||
return
|
||||
|
||||
|
||||
class FriendSecretNeedsParentLogin(StateData.StateData):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('FriendSecretNeedsParentLogin')
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("FriendSecretNeedsParentLogin")
|
||||
|
||||
def __init__(self, secretType):
|
||||
StateData.StateData.__init__(self, 'friend-secret-needs-parent-login-done')
|
||||
StateData.StateData.__init__(self, "friend-secret-needs-parent-login-done")
|
||||
self.dialog = None
|
||||
self.secretType = secretType
|
||||
return
|
||||
|
||||
def enter(self):
|
||||
StateData.StateData.enter(self)
|
||||
base.localAvatar.chatMgr.fsm.request('otherDialog')
|
||||
base.localAvatar.chatMgr.fsm.request("otherDialog")
|
||||
# Pop up a dialog indicating the parent account needs to login
|
||||
# in order to get to the Secret Friends chat:
|
||||
if self.dialog == None:
|
||||
guiButton = loader.loadModel('phase_3/models/gui/quit_button')
|
||||
guiButton = loader.loadModel("phase_3/models/gui/quit_button")
|
||||
buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui')
|
||||
nameBalloon = loader.loadModel('phase_3/models/props/chatbox_input')
|
||||
optionsButtonImage = (guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR'))
|
||||
okButtonImage = (buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr'))
|
||||
cancelButtonImage = (buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr'))
|
||||
nameBalloon = loader.loadModel("phase_3/models/props/chatbox_input")
|
||||
optionsButtonImage = (
|
||||
guiButton.find("**/QuitBtn_UP"), guiButton.find("**/QuitBtn_DN"), guiButton.find("**/QuitBtn_RLVR"))
|
||||
okButtonImage = (
|
||||
buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr'))
|
||||
cancelButtonImage = (
|
||||
buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr'))
|
||||
|
||||
# The Castillian (and all foreign) version relies on a seperate parent
|
||||
# password system. Omit the the password entry field and cancel button.
|
||||
withParentAccount = False
|
||||
try:
|
||||
withParentAccount = base.cr.withParentAccount
|
||||
except:
|
||||
self.notify.warning('withParentAccount not found in base.cr')
|
||||
self.notify.warning("withParentAccount not found in base.cr")
|
||||
pass
|
||||
|
||||
if withParentAccount:
|
||||
okPos = (-0.22, 0.0, -0.5)
|
||||
textPos = (0, 0.25)
|
||||
okCommand = self.__handleOKWithParentAccount
|
||||
elif base.cr.productName != 'Terra-DMC':
|
||||
elif base.cr.productName != "Terra-DMC":
|
||||
okPos = (-0.22, 0.0, -0.5)
|
||||
textPos = (0, 0.25)
|
||||
okCommand = self.__oldHandleOK
|
||||
|
|
@ -118,24 +133,48 @@ class FriendSecretNeedsParentLogin(StateData.StateData):
|
|||
okPos = (0, 0, -0.35)
|
||||
textPos = (0, 0.125)
|
||||
okCommand = self.__handleCancel
|
||||
self.dialog = DirectFrame(parent=aspect2dp, pos=(0.0, 0.1, 0.2), relief=None, image=DGG.getDefaultDialogGeom(), image_color=OTPGlobals.GlobalDialogColor, image_scale=(1.4, 1.0, 1.25), image_pos=(0, 0, -0.1), text=OTPLocalizer.FriendSecretNeedsParentLoginWarning, text_wordwrap=21.5, text_scale=0.055, text_pos=textPos, textMayChange=1)
|
||||
DirectButton(self.dialog, image=okButtonImage, relief=None, text=OTPLocalizer.FriendSecretNeedsPasswordWarningOK, text_scale=0.05, text_pos=(0.0, -0.1), textMayChange=0, pos=okPos, command=okCommand)
|
||||
DirectLabel(parent=self.dialog, relief=None, pos=(0, 0, 0.35), text=OTPLocalizer.FriendSecretNeedsPasswordWarningTitle, textMayChange=0, text_scale=0.08)
|
||||
if base.cr.productName != 'Terra-DMC':
|
||||
self.usernameLabel = DirectLabel(parent=self.dialog, relief=None, pos=(-0.07, 0.0, -0.1), text=OTPLocalizer.ParentLogin, text_scale=0.06, text_align=TextNode.ARight, textMayChange=0)
|
||||
self.usernameEntry = DirectEntry(parent=self.dialog, relief=None, image=nameBalloon, image1_color=(0.8, 0.8, 0.8, 1.0), scale=0.064, pos=(0.0, 0.0, -0.1), width=OTPGlobals.maxLoginWidth, numLines=1, focus=1, cursorKeys=1, obscured=1, command=self.__handleUsername)
|
||||
self.passwordLabel = DirectLabel(parent=self.dialog, relief=None, pos=(-0.02, 0.0, -0.3), text=OTPLocalizer.ParentPassword, text_scale=0.06, text_align=TextNode.ARight, textMayChange=0)
|
||||
self.passwordEntry = DirectEntry(parent=self.dialog, relief=None, image=nameBalloon, image1_color=(0.8, 0.8, 0.8, 1.0), scale=0.064, pos=(0.04, 0.0, -0.3), width=OTPGlobals.maxLoginWidth, numLines=1, focus=1, cursorKeys=1, obscured=1, command=okCommand)
|
||||
DirectButton(self.dialog, image=cancelButtonImage, relief=None, text=OTPLocalizer.FriendSecretNeedsPasswordWarningCancel, text_scale=0.05, text_pos=(0.0, -0.1), textMayChange=1, pos=(0.2, 0.0, -0.5), command=self.__handleCancel)
|
||||
|
||||
# make the common gui elements
|
||||
self.dialog = DirectFrame(parent=aspect2dp, pos=(0.0, 0.1, 0.2), relief=None,
|
||||
image=DGG.getDefaultDialogGeom(), image_color=OTPGlobals.GlobalDialogColor,
|
||||
image_scale=(1.4, 1.0, 1.25), image_pos=(0, 0, -0.1),
|
||||
text=OTPLocalizer.FriendSecretNeedsParentLoginWarning, text_wordwrap=21.5, text_scale=0.055,
|
||||
text_pos=textPos, textMayChange=1)
|
||||
DirectButton(self.dialog, image=okButtonImage, relief=None,
|
||||
text=OTPLocalizer.FriendSecretNeedsPasswordWarningOK, text_scale=0.05, text_pos=(0.0, -0.1),
|
||||
textMayChange=0, pos=okPos, command=okCommand)
|
||||
DirectLabel(parent=self.dialog, relief=None, pos=(0, 0, 0.35),
|
||||
text=OTPLocalizer.FriendSecretNeedsPasswordWarningTitle, textMayChange=0, text_scale=0.08)
|
||||
|
||||
# if not foreign, make the domestic only password entry elements
|
||||
if base.cr.productName != "Terra-DMC":
|
||||
self.usernameLabel = DirectLabel(parent=self.dialog, relief=None, pos=(-0.07, 0.0, -0.1),
|
||||
text=OTPLocalizer.ParentLogin, text_scale=0.06, text_align=TextNode.ARight, textMayChange=0)
|
||||
self.usernameEntry = DirectEntry(parent=self.dialog, relief=None, image=nameBalloon,
|
||||
image1_color=(0.8, 0.8, 0.8, 1.0), scale=0.064, pos=(0.0, 0.0, -0.1),
|
||||
width=OTPGlobals.maxLoginWidth, numLines=1, focus=1, cursorKeys=1, obscured=1,
|
||||
command=self.__handleUsername)
|
||||
self.passwordLabel = DirectLabel(parent=self.dialog, relief=None, pos=(-0.02, 0.0, -0.3),
|
||||
text=OTPLocalizer.ParentPassword, text_scale=0.06, text_align=TextNode.ARight, textMayChange=0)
|
||||
self.passwordEntry = DirectEntry(parent=self.dialog, relief=None, image=nameBalloon,
|
||||
image1_color=(0.8, 0.8, 0.8, 1.0), scale=0.064, pos=(0.04, 0.0, -0.3),
|
||||
width=OTPGlobals.maxLoginWidth, numLines=1, focus=1, cursorKeys=1, obscured=1, command=okCommand)
|
||||
DirectButton(self.dialog, image=cancelButtonImage, relief=None,
|
||||
text=OTPLocalizer.FriendSecretNeedsPasswordWarningCancel, text_scale=0.05, text_pos=(0.0, -0.1),
|
||||
textMayChange=1, pos=(0.2, 0.0, -0.5), command=self.__handleCancel)
|
||||
|
||||
# hide the parent login as it's not valid yet
|
||||
if withParentAccount:
|
||||
self.usernameEntry.enterText('')
|
||||
self.usernameEntry['focus'] = 1
|
||||
self.passwordEntry.enterText('')
|
||||
|
||||
else:
|
||||
self.usernameEntry.hide()
|
||||
self.usernameLabel.hide()
|
||||
self.passwordEntry['focus'] = 1
|
||||
self.passwordEntry.enterText('')
|
||||
|
||||
guiButton.removeNode()
|
||||
buttons.removeNode()
|
||||
nameBalloon.removeNode()
|
||||
|
|
@ -147,8 +186,8 @@ class FriendSecretNeedsParentLogin(StateData.StateData):
|
|||
elif self.passwordEntry:
|
||||
self.passwordEntry['focus'] = 1
|
||||
self.passwordEntry.enterText('')
|
||||
|
||||
self.dialog.show()
|
||||
return
|
||||
|
||||
def exit(self):
|
||||
self.ignoreAll()
|
||||
|
|
@ -156,11 +195,11 @@ class FriendSecretNeedsParentLogin(StateData.StateData):
|
|||
self.dialog.destroy()
|
||||
self.dialog = None
|
||||
if self.isEntered:
|
||||
base.localAvatar.chatMgr.fsm.request('mainMenu')
|
||||
base.localAvatar.chatMgr.fsm.request("mainMenu")
|
||||
StateData.StateData.exit(self)
|
||||
return
|
||||
|
||||
def __handleUsername(self, *args):
|
||||
# activate password entry
|
||||
if self.passwordEntry:
|
||||
self.passwordEntry['focus'] = 1
|
||||
self.passwordEntry.enterText('')
|
||||
|
|
@ -168,17 +207,29 @@ class FriendSecretNeedsParentLogin(StateData.StateData):
|
|||
def __handleOKWithParentAccount(self, *args):
|
||||
username = self.usernameEntry.get()
|
||||
password = self.passwordEntry.get()
|
||||
# we need to store these in base.cr for __enterSecret
|
||||
base.cr.parentUsername = username
|
||||
base.cr.parentPassword = password
|
||||
tt = base.cr.loginInterface
|
||||
okflag, message = tt.authenticateParentUsernameAndPassword(localAvatar.DISLid, base.cr.password, username, password)
|
||||
try:
|
||||
DISLIdFromLogin = base.cr.DISLIdFromLogin
|
||||
except:
|
||||
DISLIdFromLogin = 0
|
||||
if DISLIdFromLogin and (DISLIdFromLogin != localAvatar.DISLid):
|
||||
# we only expect to have 1 DISLId per player, we're screwed if this happens
|
||||
self.notify.error(
|
||||
"Mismatched DISLIds, fromLogin=%s, localAvatar.dislId=%s" % (DISLIdFromLogin, localAvatar.DISLid))
|
||||
okflag, message = tt.authenticateParentUsernameAndPassword(localAvatar.DISLid, base.cr.password, username,
|
||||
password)
|
||||
if okflag:
|
||||
self.exit()
|
||||
openFriendSecret(self.secretType)
|
||||
elif message:
|
||||
base.localAvatar.chatMgr.fsm.request('problemActivatingChat')
|
||||
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % message
|
||||
# Error connecting.
|
||||
base.localAvatar.chatMgr.fsm.request("problemActivatingChat")
|
||||
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % (message)
|
||||
else:
|
||||
# Wrong password.
|
||||
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsPasswordWarningWrongPassword
|
||||
self.passwordEntry['focus'] = 1
|
||||
self.passwordEntry.enterText('')
|
||||
|
|
@ -186,6 +237,7 @@ class FriendSecretNeedsParentLogin(StateData.StateData):
|
|||
def __oldHandleOK(self, *args):
|
||||
username = self.usernameEntry.get()
|
||||
password = self.passwordEntry.get()
|
||||
# we need to store these in base.cr for __enterSecret
|
||||
base.cr.parentUsername = username
|
||||
base.cr.parentPassword = password
|
||||
tt = base.cr.loginInterface
|
||||
|
|
@ -194,59 +246,83 @@ class FriendSecretNeedsParentLogin(StateData.StateData):
|
|||
self.exit()
|
||||
openFriendSecret(self.secretType)
|
||||
elif message:
|
||||
base.localAvatar.chatMgr.fsm.request('problemActivatingChat')
|
||||
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % message
|
||||
# Error connecting.
|
||||
base.localAvatar.chatMgr.fsm.request("problemActivatingChat")
|
||||
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % (message)
|
||||
else:
|
||||
# Wrong password.
|
||||
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsPasswordWarningWrongPassword
|
||||
self.passwordEntry['focus'] = 1
|
||||
self.passwordEntry.enterText('')
|
||||
|
||||
def __handleOK(self, *args):
|
||||
|
||||
base.cr.parentUsername = self.usernameEntry.get()
|
||||
base.cr.parentPassword = self.passwordEntry.get()
|
||||
# we don't have a request for this yet, so pretend we are submitting a limited secret
|
||||
base.cr.playerFriendsManager.sendRequestUseLimitedSecret('', base.cr.parentUsername, base.cr.parentPassword)
|
||||
self.accept(OTPGlobals.PlayerFriendRejectUseSecretEvent, self.__handleParentLogin)
|
||||
# we won't get an answer yet, so spoof a return code
|
||||
# self.__handleParentLogin(0)
|
||||
# that doesn't work, just immediately close the panel
|
||||
self.exit()
|
||||
|
||||
def __handleParentLogin(self, reason):
|
||||
# don't know reason codes yet, spoof something
|
||||
if reason == 0:
|
||||
self.exit()
|
||||
openFriendSecret(self.secretType)
|
||||
elif reason == 1:
|
||||
# Wrong username
|
||||
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsPasswordWarningWrongUsername
|
||||
self.usernameEntry['focus'] = 1
|
||||
self.usernameEntry.enterText('')
|
||||
elif reason == 2:
|
||||
# Wrong password
|
||||
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsPasswordWarningWrongPassword
|
||||
self.passwordEntry['focus'] = 1
|
||||
self.passwordEntry.enterText('')
|
||||
else:
|
||||
base.localAvatar.chatMgr.fsm.request('problemActivatingChat')
|
||||
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % message
|
||||
# Error connecting (fall through case)
|
||||
base.localAvatar.chatMgr.fsm.request("problemActivatingChat")
|
||||
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % (message)
|
||||
|
||||
def __handleCancel(self):
|
||||
self.exit()
|
||||
|
||||
|
||||
class FriendSecret(DirectFrame, StateData.StateData):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('FriendSecret')
|
||||
"""
|
||||
This is a panel that allows the user to manage 'secrets' that is,
|
||||
code words that identify people who are actually friends in real
|
||||
life (and thus are entitled to use full chat with each other).
|
||||
|
||||
This panel is the place the user will come to either get a new
|
||||
'secret' to give to someone else, or to enter the 'secret' they
|
||||
got from someone.
|
||||
"""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("FriendSecret")
|
||||
|
||||
def __init__(self, secretType):
|
||||
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))
|
||||
StateData.StateData.__init__(self, 'friend-secret-done')
|
||||
DirectFrame.__init__(self, parent=aspect2dp, pos=(0, 0, 0.30), 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), )
|
||||
StateData.StateData.__init__(self, "friend-secret-done")
|
||||
self.initialiseoptions(FriendSecret)
|
||||
self.prefix = OTPGlobals.getDefaultProductPrefix()
|
||||
# what types of secret friends will we offer
|
||||
self.secretType = secretType
|
||||
self.notify.debug('### secretType = %s' % self.secretType)
|
||||
self.notify.debug("### secretType = %s" % self.secretType)
|
||||
# what type of secret friend has the user chosen
|
||||
self.requestedSecretType = secretType
|
||||
self.notify.debug('### requestedSecretType = %s' % self.requestedSecretType)
|
||||
return
|
||||
self.notify.debug("### requestedSecretType = %s" % self.requestedSecretType)
|
||||
|
||||
def unload(self):
|
||||
if self.isLoaded == 0:
|
||||
return None
|
||||
self.isLoaded = 0
|
||||
self.exit()
|
||||
|
||||
del self.introText
|
||||
del self.getSecret
|
||||
del self.enterSecretText
|
||||
|
|
@ -259,34 +335,48 @@ class FriendSecret(DirectFrame, StateData.StateData):
|
|||
del self.accountButton
|
||||
DirectFrame.destroy(self)
|
||||
self.ignore('clientCleanup')
|
||||
return None
|
||||
|
||||
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=OTPLocalizer.FriendSecretIntro, text_fg=(0, 0, 0, 1), text_wordwrap=30)
|
||||
|
||||
self.introText = DirectLabel(parent=self, relief=None, pos=(0, 0, 0.4), scale=0.05,
|
||||
text=OTPLocalizer.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=OTPLocalizer.FSgetSecret, text=OTPLocalizer.FriendSecretGetSecret, text_scale=OTPLocalizer.FSgetSecretButton, text_pos=(0, -0.02), command=self.__determineSecret)
|
||||
|
||||
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=OTPLocalizer.FSgetSecret, text=OTPLocalizer.FriendSecretGetSecret,
|
||||
text_scale=OTPLocalizer.FSgetSecretButton, text_pos=(0, -0.02), command=self.__determineSecret, )
|
||||
self.getSecret.hide()
|
||||
self.enterSecretText = DirectLabel(parent=self, relief=None, pos=OTPLocalizer.FSenterSecretTextPos, scale=0.05, text=OTPLocalizer.FriendSecretEnterSecret, text_fg=(0, 0, 0, 1), text_wordwrap=30)
|
||||
|
||||
self.enterSecretText = DirectLabel(parent=self, relief=None, pos=OTPLocalizer.FSenterSecretTextPos, scale=0.05,
|
||||
text=OTPLocalizer.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 = DirectEntry(parent=self, relief=DGG.SUNKEN, scale=0.06, pos=(-0.60, 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)
|
||||
|
||||
# This fixes a little problem with the initial frame size.
|
||||
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=OTPLocalizer.FSok1, text=OTPLocalizer.FriendSecretEnter, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.5), command=self.__ok1)
|
||||
|
||||
self.ok1 = DirectButton(parent=self, relief=None, image=(
|
||||
guiButton.find("**/QuitBtn_UP"), guiButton.find("**/QuitBtn_DN"), guiButton.find("**/QuitBtn_RLVR"),),
|
||||
image_scale=OTPLocalizer.FSok1, text=OTPLocalizer.FriendSecretEnter, text_scale=0.06, text_pos=(0, -0.02),
|
||||
pos=(0, 0, -0.5), command=self.__ok1, )
|
||||
self.ok1.hide()
|
||||
if base.cr.productName in ['JP',
|
||||
'DE',
|
||||
'BR',
|
||||
'FR']:
|
||||
|
||||
if base.cr.productName in ['JP', 'DE', 'BR', 'FR']:
|
||||
# There should be no 'change secret friends options' button in
|
||||
# the UK version.
|
||||
# the only thing we do to self.changeOptions is show and hide it;
|
||||
# avoid adding a bunch of 'if' statements
|
||||
class ShowHide:
|
||||
|
||||
def show(self):
|
||||
pass
|
||||
|
||||
|
|
@ -294,16 +384,32 @@ class FriendSecret(DirectFrame, StateData.StateData):
|
|||
pass
|
||||
|
||||
self.changeOptions = ShowHide()
|
||||
self.ok2 = DirectButton(parent=self, relief=None, image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=OTPLocalizer.FSok2, text=OTPLocalizer.FriendSecretOK, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.57), command=self.__ok2)
|
||||
|
||||
self.ok2 = DirectButton(parent=self, relief=None, image=(
|
||||
guiButton.find("**/QuitBtn_UP"), guiButton.find("**/QuitBtn_DN"), guiButton.find("**/QuitBtn_RLVR"),),
|
||||
image_scale=OTPLocalizer.FSok2, text=OTPLocalizer.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=OTPLocalizer.FriendSecretCancel, image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=OTPLocalizer.FScancel, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.57), command=self.__cancel)
|
||||
|
||||
self.cancel = DirectButton(parent=self, relief=None, text=OTPLocalizer.FriendSecretCancel, image=(
|
||||
guiButton.find("**/QuitBtn_UP"), guiButton.find("**/QuitBtn_DN"), guiButton.find("**/QuitBtn_RLVR"),),
|
||||
image_scale=OTPLocalizer.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=OTPLocalizer.FSnextText, text_fg=(0, 0, 0, 1), text_wordwrap=25.5)
|
||||
|
||||
self.nextText = DirectLabel(parent=self, relief=None, pos=(0, 0, 0.30), scale=0.06, text="",
|
||||
text_scale=OTPLocalizer.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.1, text='', text_fg=(0, 0, 0, 1), text_wordwrap=30)
|
||||
|
||||
self.secretText = DirectLabel(parent=self, relief=None, pos=(0, 0, -0.42), scale=0.1, text="",
|
||||
text_fg=(0, 0, 0, 1), text_wordwrap=30, )
|
||||
self.secretText.hide()
|
||||
|
||||
guiButton.removeNode()
|
||||
|
||||
# moved into it's own method to make overloading easier
|
||||
self.makeFriendTypeButtons()
|
||||
|
||||
self.accept('clientCleanup', self.__handleCleanup)
|
||||
self.accept('walkDone', self.__handleStop)
|
||||
|
||||
|
|
@ -314,59 +420,100 @@ class FriendSecret(DirectFrame, StateData.StateData):
|
|||
self.unload()
|
||||
|
||||
def makeFriendTypeButtons(self):
|
||||
# NOTE: this uses generic text, if you want game-specific text, please inherit and override
|
||||
# (see $TOONTOWN/src/friends/ToontownFriendSecret.py for an example)
|
||||
buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui')
|
||||
self.avatarButton = DirectButton(self, image=(buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')), relief=None, text=OTPLocalizer.FriendSecretDetermineSecretAvatar, text_scale=0.07, text_pos=(0.0, -0.1), pos=(-0.35, 0.0, -0.05), command=self.__handleAvatar)
|
||||
avatarText = DirectLabel(parent=self, relief=None, pos=Vec3(0.35, 0, -0.3), text=OTPLocalizer.FriendSecretDetermineSecretAvatarRollover, text_fg=(0, 0, 0, 1), text_pos=(0, 0), text_scale=0.055, text_align=TextNode.ACenter)
|
||||
|
||||
# make an avatar friend
|
||||
self.avatarButton = DirectButton(self, image=(
|
||||
buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')),
|
||||
relief=None, text=OTPLocalizer.FriendSecretDetermineSecretAvatar, text_scale=0.07, text_pos=(0.0, -0.1),
|
||||
pos=(-0.35, 0.0, -0.05), command=self.__handleAvatar)
|
||||
# make a label to show avatar friend desc on rollover
|
||||
avatarText = DirectLabel(parent=self, relief=None, pos=Vec3(0.35, 0, -0.3),
|
||||
text=OTPLocalizer.FriendSecretDetermineSecretAvatarRollover, text_fg=(0, 0, 0, 1), text_pos=(0, 0),
|
||||
text_scale=0.055, text_align=TextNode.ACenter, )
|
||||
avatarText.reparentTo(self.avatarButton.stateNodePath[2])
|
||||
self.avatarButton.hide()
|
||||
self.accountButton = DirectButton(self, image=(buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')), relief=None, text=OTPLocalizer.FriendSecretDetermineSecretAccount, text_scale=0.07, text_pos=(0.0, -0.1), pos=(0.35, 0.0, -0.05), command=self.__handleAccount)
|
||||
accountText = DirectLabel(parent=self, relief=None, pos=Vec3(-0.35, 0, -0.3), text=OTPLocalizer.FriendSecretDetermineSecretAccountRollover, text_fg=(0, 0, 0, 1), text_pos=(0, 0), text_scale=0.055, text_align=TextNode.ACenter)
|
||||
|
||||
# make an account friend
|
||||
self.accountButton = DirectButton(self, image=(
|
||||
buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')),
|
||||
relief=None, text=OTPLocalizer.FriendSecretDetermineSecretAccount, text_scale=0.07, text_pos=(0.0, -0.1),
|
||||
pos=(0.35, 0.0, -0.05), command=self.__handleAccount)
|
||||
# make a label to show feature desc on rollover
|
||||
accountText = DirectLabel(parent=self, relief=None, pos=Vec3(-0.35, 0, -0.3),
|
||||
text=OTPLocalizer.FriendSecretDetermineSecretAccountRollover, text_fg=(0, 0, 0, 1), text_pos=(0, 0),
|
||||
text_scale=0.055, text_align=TextNode.ACenter, )
|
||||
accountText.reparentTo(self.accountButton.stateNodePath[2])
|
||||
self.accountButton.hide()
|
||||
|
||||
buttons.removeNode()
|
||||
return
|
||||
|
||||
def enter(self):
|
||||
if self.isEntered == 1:
|
||||
return
|
||||
self.isEntered = 1
|
||||
# Use isLoaded to avoid redundant loading
|
||||
if self.isLoaded == 0:
|
||||
self.load()
|
||||
|
||||
self.show()
|
||||
|
||||
# Set us up on the first page.
|
||||
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')
|
||||
|
||||
# While the entry's on the screen, we have to turn off the
|
||||
# background focus on the normal chat entry. Otherwise,
|
||||
# keypresses would start chatting!
|
||||
base.localAvatar.chatMgr.fsm.request("otherDialog")
|
||||
|
||||
# And now we can set the focus on our entry.
|
||||
self.enterSecret['focus'] = 1
|
||||
|
||||
# The secret panel uses up a lot of space onscreen; in
|
||||
# particular, it will hide most of the chat balloons. Force
|
||||
# these to go to the margins.
|
||||
NametagGlobals.setOnscreenChatForced(1)
|
||||
|
||||
def exit(self):
|
||||
if self.isEntered == 0:
|
||||
return
|
||||
self.isEntered = 0
|
||||
|
||||
# Restore the normal chat behavior.
|
||||
NametagGlobals.setOnscreenChatForced(0)
|
||||
|
||||
self.__cleanupFirstPage()
|
||||
self.ignoreAll()
|
||||
self.accept('clientCleanup', self.unload)
|
||||
self.hide()
|
||||
|
||||
def __determineSecret(self):
|
||||
# If we support both types of secrets...
|
||||
if self.secretType == BothSecrets:
|
||||
# ask the player what type they want
|
||||
self.__cleanupFirstPage()
|
||||
self.ok1.hide()
|
||||
# NOTE: this uses generic text, if you want game-specific text, please inherit and override
|
||||
# (see $TOONTOWN/src/friends/ToontownFriendSecret.py for an example)
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretDetermineSecret
|
||||
self.nextText.setPos(0, 0, 0.3)
|
||||
self.nextText.setPos(0, 0, 0.30)
|
||||
self.nextText.show()
|
||||
self.avatarButton.show()
|
||||
self.accountButton.show()
|
||||
self.cancel.show()
|
||||
else:
|
||||
# or just get the secret
|
||||
self.__getSecret()
|
||||
|
||||
def __handleAvatar(self):
|
||||
|
|
@ -383,39 +530,36 @@ class FriendSecret(DirectFrame, StateData.StateData):
|
|||
def __getSecret(self):
|
||||
self.__cleanupFirstPage()
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretGettingSecret
|
||||
self.nextText.setPos(0, 0, 0.3)
|
||||
self.nextText.setPos(0, 0, 0.30)
|
||||
self.nextText.show()
|
||||
self.avatarButton.hide()
|
||||
self.accountButton.hide()
|
||||
self.ok1.hide()
|
||||
self.cancel.show()
|
||||
if self.requestedSecretType == AvatarSecret:
|
||||
if not base.cr.friendManager:
|
||||
self.notify.warning('No FriendManager available.')
|
||||
self.exit()
|
||||
return
|
||||
base.cr.friendManager.up_requestSecret()
|
||||
self.accept('requestSecretResponse', self.__gotAvatarSecret)
|
||||
else:
|
||||
if base.cr.needParentPasswordForSecretChat():
|
||||
self.notify.info('### requestLimitedSecret')
|
||||
base.cr.playerFriendsManager.sendRequestLimitedSecret(base.cr.parentUsername, base.cr.parentPassword)
|
||||
else:
|
||||
base.cr.playerFriendsManager.sendRequestUnlimitedSecret()
|
||||
self.notify.info('### requestUnlimitedSecret')
|
||||
self.accept(OTPGlobals.PlayerFriendNewSecretEvent, self.__gotAccountSecret)
|
||||
self.accept(OTPGlobals.PlayerFriendRejectNewSecretEvent, self.__rejectAccountSecret)
|
||||
# If we don't have a FriendManager, something's badly wrong.
|
||||
# Most likely we're running in a development environment
|
||||
# without an AI client.
|
||||
if not base.cr.friendManager:
|
||||
self.notify.warning("No FriendManager available.")
|
||||
self.exit()
|
||||
return
|
||||
base.cr.friendManager.up_requestSecret()
|
||||
self.accept('requestSecretResponse',
|
||||
self.__gotAvatarSecret) # else: # if base.cr.needParentPasswordForSecretChat(): # self.notify.info("### requestLimitedSecret") # base.cr.playerFriendsManager.sendRequestLimitedSecret(base.cr.parentUsername, base.cr.parentPassword) # else: # base.cr.playerFriendsManager.sendRequestUnlimitedSecret() # self.notify.info("### requestUnlimitedSecret") # self.accept(OTPGlobals.PlayerFriendNewSecretEvent, self.__gotAccountSecret) # self.accept(OTPGlobals.PlayerFriendRejectNewSecretEvent, self.__rejectAccountSecret)
|
||||
|
||||
def __gotAvatarSecret(self, result, secret):
|
||||
self.ignore('requestSecretResponse')
|
||||
|
||||
if result == 1:
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretGotSecret
|
||||
self.nextText.setPos(*OTPLocalizer.FSgotSecretPos)
|
||||
if self.prefix:
|
||||
self.secretText['text'] = self.prefix + ' ' + secret
|
||||
else:
|
||||
self.secretText['text'] = secret
|
||||
# always append the prefix
|
||||
self.secretText['text'] = self.prefix + ' ' + secret
|
||||
elif result == 2:
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretTooManyFriends
|
||||
|
||||
else:
|
||||
# Oops, too many secrets.
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretTooMany
|
||||
self.nextText.show()
|
||||
self.secretText.show()
|
||||
|
|
@ -423,133 +567,148 @@ class FriendSecret(DirectFrame, StateData.StateData):
|
|||
self.ok1.hide()
|
||||
self.ok2.show()
|
||||
|
||||
def __gotAccountSecret(self, secret):
|
||||
self.ignore(OTPGlobals.PlayerFriendNewSecretEvent)
|
||||
self.ignore(OTPGlobals.PlayerFriendRejectNewSecretEvent)
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretGotSecret
|
||||
self.nextText.setPos(0, 0, 0.47)
|
||||
self.secretText['text'] = secret
|
||||
self.nextText.show()
|
||||
self.secretText.show()
|
||||
self.cancel.hide()
|
||||
self.ok1.hide()
|
||||
self.ok2.show()
|
||||
|
||||
def __rejectAccountSecret(self, reason):
|
||||
print('## rejectAccountSecret: reason = ', reason)
|
||||
self.ignore(OTPGlobals.PlayerFriendNewSecretEvent)
|
||||
self.ignore(OTPGlobals.PlayerFriendRejectNewSecretEvent)
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretTooMany
|
||||
self.nextText.show()
|
||||
self.secretText.show()
|
||||
self.cancel.hide()
|
||||
self.ok1.hide()
|
||||
self.ok2.show()
|
||||
|
||||
def __enterSecret(self, secret):
|
||||
self.enterSecret.set('')
|
||||
# Empty the entry for next time.
|
||||
self.enterSecret.set("")
|
||||
|
||||
secret = secret.strip()
|
||||
if not secret:
|
||||
# If the secret is empty, it just means to close down
|
||||
# the dialog.
|
||||
self.exit()
|
||||
return
|
||||
|
||||
# If we don't have a FriendManager, something's badly wrong.
|
||||
# Most likely we're running in a development environment
|
||||
# without an AI client.
|
||||
if not base.cr.friendManager:
|
||||
self.notify.warning('No FriendManager available.')
|
||||
self.notify.warning("No FriendManager available.")
|
||||
self.exit()
|
||||
return
|
||||
|
||||
self.__cleanupFirstPage()
|
||||
|
||||
# The client can now prepend a product prefix to all secrets - strip this off if present
|
||||
if self.prefix:
|
||||
if secret[0:2] == self.prefix:
|
||||
secret = secret[3:]
|
||||
self.notify.info('### use TT secret')
|
||||
self.notify.info("### use TT secret")
|
||||
self.accept('submitSecretResponse', self.__enteredSecret)
|
||||
base.cr.friendManager.up_submitSecret(secret)
|
||||
else:
|
||||
self.accept(OTPGlobals.PlayerFriendUpdateEvent, self.__useAccountSecret)
|
||||
self.accept(OTPGlobals.PlayerFriendRejectUseSecretEvent, self.__rejectUseAccountSecret)
|
||||
if base.cr.needParentPasswordForSecretChat():
|
||||
self.notify.info('### useLimitedSecret')
|
||||
base.cr.playerFriendsManager.sendRequestUseLimitedSecret(secret, base.cr.parentUsername, base.cr.parentPassword)
|
||||
else:
|
||||
self.notify.info('### useUnlimitedSecret')
|
||||
base.cr.playerFriendsManager.sendRequestUseUnlimitedSecret(secret)
|
||||
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretTryingSecret
|
||||
self.nextText.setPos(0, 0, 0.3)
|
||||
self.nextText.setPos(0, 0, 0.30)
|
||||
self.nextText.show()
|
||||
self.ok1.hide()
|
||||
self.cancel.show()
|
||||
|
||||
def __enteredSecret(self, result, avId):
|
||||
self.ignore('submitSecretResponse')
|
||||
|
||||
if result == 1:
|
||||
# We made it!
|
||||
handle = base.cr.identifyAvatar(avId)
|
||||
if handle != None:
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretSuccess % handle.getName()
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretSuccess % (handle.getName())
|
||||
else:
|
||||
# Shoot. We just made friends with someone, but we
|
||||
# don't know who it is yet. We'll have to ask the
|
||||
# server who this is, and wait for the response before
|
||||
# we can continue.
|
||||
self.accept('friendsMapComplete', self.__nowFriends, [avId])
|
||||
ready = base.cr.fillUpFriendsMap()
|
||||
if ready:
|
||||
self.__nowFriends(avId)
|
||||
return
|
||||
|
||||
elif result == 0:
|
||||
# Unknown secret.
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretUnknown
|
||||
|
||||
elif result == 2:
|
||||
# Friends list full.
|
||||
handle = base.cr.identifyAvatar(avId)
|
||||
if handle != None:
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretFull % handle.getName()
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretFull % (handle.getName())
|
||||
else:
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretFullNoName
|
||||
|
||||
elif result == 3:
|
||||
# Self match.
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretSelf
|
||||
|
||||
elif result == 4:
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretWrongProduct % self.prefix
|
||||
# This doesn't look like our secret friend code - wrong prefix
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretWrongProduct % (self.prefix)
|
||||
|
||||
self.nextText.show()
|
||||
self.cancel.hide()
|
||||
self.ok1.hide()
|
||||
self.ok2.show()
|
||||
return
|
||||
|
||||
def __useAccountSecret(self, avId, friendInfo):
|
||||
self.ignore(OTPGlobals.PlayerFriendUpdateEvent)
|
||||
self.ignore(OTPGlobals.PlayerFriendRejectUseSecretEvent)
|
||||
|
||||
# todo - pass an avId?
|
||||
self.__enteredSecret(1, 0)
|
||||
|
||||
def __rejectUseAccountSecret(self, reason):
|
||||
print('## rejectUseAccountSecret: reason = ', reason)
|
||||
print("## rejectUseAccountSecret: reason = ", reason)
|
||||
self.ignore(OTPGlobals.PlayerFriendUpdateEvent)
|
||||
self.ignore(OTPGlobals.PlayerFriendRejectUseSecretEvent)
|
||||
if reason == RejectCode.RejectCode.FRIENDS_LIST_FULL:
|
||||
|
||||
if (reason == RejectCode.RejectCode.FRIENDS_LIST_FULL):
|
||||
self.__enteredSecret(2, 0)
|
||||
elif reason == RejectCode.RejectCode.ALREADY_FRIENDS_WITH_SELF:
|
||||
elif (reason == RejectCode.RejectCode.ALREADY_FRIENDS_WITH_SELF):
|
||||
self.__enteredSecret(3, 0)
|
||||
else:
|
||||
# todo: this shouldn't be the fall thru
|
||||
self.__enteredSecret(0, 0)
|
||||
|
||||
def __nowFriends(self, avId):
|
||||
# This is called only from enteredSecret(), after the friend
|
||||
# transaction has completed. This will be called only if the
|
||||
# client didn't know the identity of the friend at the time,
|
||||
# but it should know now.
|
||||
|
||||
self.ignore('friendsMapComplete')
|
||||
|
||||
handle = base.cr.identifyAvatar(avId)
|
||||
if handle != None:
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretNowFriends % handle.getName()
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretNowFriends % (handle.getName())
|
||||
else:
|
||||
# This really shouldn't be possible.
|
||||
self.nextText['text'] = OTPLocalizer.FriendSecretNowFriendsNoName
|
||||
|
||||
self.nextText.show()
|
||||
self.cancel.hide()
|
||||
self.ok1.hide()
|
||||
self.ok2.show()
|
||||
return
|
||||
|
||||
def __ok1(self):
|
||||
# Clicking "ok" from the front screen is the same thing as
|
||||
# pressing Enter in the entry.
|
||||
secret = self.enterSecret.get()
|
||||
self.__enterSecret(secret)
|
||||
|
||||
def __ok2(self):
|
||||
# Clicking "ok" from a finished screen just makes the thing go
|
||||
# away.
|
||||
self.exit()
|
||||
|
||||
def __cancel(self):
|
||||
# Clicking "cancel" makes the panel close too.
|
||||
self.exit()
|
||||
|
||||
def __cleanupFirstPage(self):
|
||||
# Removes all the widgets etc. that were created for the
|
||||
# welcome page, except the introText.
|
||||
|
||||
self.introText.hide()
|
||||
self.getSecret.hide()
|
||||
self.enterSecretText.hide()
|
||||
self.enterSecret.hide()
|
||||
base.localAvatar.chatMgr.fsm.request('mainMenu')
|
||||
|
||||
# Restore the background focus on the chat entry.
|
||||
base.localAvatar.chatMgr.fsm.request("mainMenu")
|
||||
|
|
|
|||
|
|
@ -3,9 +3,13 @@ from direct.gui.DirectGui import *
|
|||
from direct.directnotify import DirectNotifyGlobal
|
||||
from otp.otpbase import OTPLocalizer
|
||||
from toontown.toonbase import TTLocalizer
|
||||
|
||||
# This file overrides key methods in FriendSecret to add Toontown specific text to the OTP buttons
|
||||
|
||||
from otp.friends.FriendSecret import AccountSecret
|
||||
from otp.friends.FriendSecret import AvatarSecret
|
||||
from otp.friends.FriendSecret import BothSecrets
|
||||
|
||||
from otp.friends import FriendSecret
|
||||
from otp.friends.FriendSecret import globalFriendSecret
|
||||
from otp.friends.FriendSecret import showFriendSecret
|
||||
|
|
@ -18,41 +22,94 @@ def openFriendSecret(secretType):
|
|||
globalFriendSecret.unload()
|
||||
globalFriendSecret = ToontownFriendSecret(secretType)
|
||||
globalFriendSecret.enter()
|
||||
return
|
||||
|
||||
|
||||
# there is no way to overload module level methods, so hammer it in
|
||||
FriendSecret.openFriendSecret = openFriendSecret
|
||||
|
||||
class ToontownFriendSecret(FriendSecret.FriendSecret):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ToontownFriendSecret')
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("ToontownFriendSecret")
|
||||
|
||||
def __init__(self, secretType):
|
||||
#secretType is specefied in toon/ToonAvatarPanel.py-> __handleSecrets(self):
|
||||
FriendSecret.FriendSecret.__init__(self, secretType)
|
||||
self.initialiseoptions(ToontownFriendSecret)
|
||||
|
||||
def makeFriendTypeButtons(self):
|
||||
assert self.notify.debugCall()
|
||||
|
||||
buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui')
|
||||
self.avatarButton = DirectButton(parent=self, image=(buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')), relief=None, text=TTLocalizer.FriendInviterToon, text_scale=0.07, text_pos=(0.0, -0.1), pos=(-0.35, 0.0, -0.05), command=self._FriendSecret__handleAvatar)
|
||||
avatarText = DirectLabel(parent=self, relief=None, pos=Vec3(0.35, 0, -0.3), text=TTLocalizer.FriendInviterToonFriendInfo, text_fg=(0, 0, 0, 1), text_pos=(0, 0), text_scale=0.055, text_align=TextNode.ACenter)
|
||||
|
||||
# make an avatar friend
|
||||
self.avatarButton = DirectButton(
|
||||
parent = self,
|
||||
image = (buttons.find('**/ChtBx_OKBtn_UP'),
|
||||
buttons.find('**/ChtBx_OKBtn_DN'),
|
||||
buttons.find('**/ChtBx_OKBtn_Rllvr')),
|
||||
relief = None,
|
||||
text = TTLocalizer.FriendInviterToon,
|
||||
text_scale = 0.07,
|
||||
text_pos = (0.0, -0.1),
|
||||
pos = (-0.35, 0.0, -0.05),
|
||||
command = self._FriendSecret__handleAvatar
|
||||
)
|
||||
# make a label to show avatar friend desc on rollover
|
||||
avatarText = DirectLabel(
|
||||
parent = self,
|
||||
relief = None,
|
||||
pos = Vec3(0.35, 0, -0.3),
|
||||
text = TTLocalizer.FriendInviterToonFriendInfo,
|
||||
text_fg = (0, 0, 0, 1),
|
||||
text_pos = (0, 0),
|
||||
text_scale = 0.055,
|
||||
text_align = TextNode.ACenter,
|
||||
)
|
||||
avatarText.reparentTo(self.avatarButton.stateNodePath[2])
|
||||
self.avatarButton.hide()
|
||||
self.accountButton = DirectButton(parent=self, image=(buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')), relief=None, text=TTLocalizer.FriendInviterPlayer, text_scale=0.07, text_pos=(0.0, -0.1), pos=(0.35, 0.0, -0.05), command=self._FriendSecret__handleAccount)
|
||||
accountText = DirectLabel(parent=self, relief=None, pos=Vec3(-0.35, 0, -0.3), text=TTLocalizer.FriendInviterPlayerFriendInfo, text_fg=(0, 0, 0, 1), text_pos=(0, 0), text_scale=0.055, text_align=TextNode.ACenter)
|
||||
|
||||
# make an account friend
|
||||
self.accountButton = DirectButton(
|
||||
parent = self,
|
||||
image = (buttons.find('**/ChtBx_OKBtn_UP'),
|
||||
buttons.find('**/ChtBx_OKBtn_DN'),
|
||||
buttons.find('**/ChtBx_OKBtn_Rllvr')),
|
||||
relief = None,
|
||||
text = TTLocalizer.FriendInviterPlayer,
|
||||
text_scale = 0.07,
|
||||
text_pos = (0.0, -0.1),
|
||||
pos = (0.35, 0.0, -0.05),
|
||||
command = self._FriendSecret__handleAccount
|
||||
)
|
||||
# make a label to show feature desc on rollover
|
||||
accountText = DirectLabel(
|
||||
parent = self,
|
||||
relief = None,
|
||||
pos = Vec3(-0.35, 0, -0.3),
|
||||
text = TTLocalizer.FriendInviterPlayerFriendInfo,
|
||||
text_fg = (0, 0, 0, 1),
|
||||
text_pos = (0, 0),
|
||||
text_scale = 0.055,
|
||||
text_align = TextNode.ACenter,
|
||||
)
|
||||
accountText.reparentTo(self.accountButton.stateNodePath[2])
|
||||
self.accountButton.hide()
|
||||
|
||||
buttons.removeNode()
|
||||
return
|
||||
|
||||
def __determineSecret(self):
|
||||
assert self.notify.debugCall()
|
||||
# If we support both types of secrets...
|
||||
if self.secretType == BothSecrets:
|
||||
# ask the player what type they want
|
||||
self._FriendSecret__cleanupFirstPage()
|
||||
self.ok1.hide()
|
||||
self.changeOptions.hide()
|
||||
self.nextText['text'] = TTLocalizer.FriendInviterBegin
|
||||
self.nextText.setPos(0, 0, 0.3)
|
||||
self.nextText.setPos(0, 0, 0.30)
|
||||
self.nextText.show()
|
||||
self.avatarButton.show()
|
||||
self.accountButton.show()
|
||||
self.cancel.show()
|
||||
else:
|
||||
# or just get the secret
|
||||
self._FriendSecret__getSecret()
|
||||
|
|
|
|||
|
|
@ -22,5 +22,8 @@ class ToontownFriendsManagerAI(DistributedObjectGlobalAI):
|
|||
|
||||
messenger.send("makeFriendsReply", [result, context])
|
||||
|
||||
def requestSecretResponse(self, result, secret, avId):
|
||||
messenger.send("requestSecretReply", [result, secret, avId])
|
||||
|
||||
def sendRequestSecret(self, requesterId):
|
||||
self.sendUpdate('requestSecret', [requesterId])
|
||||
|
|
|
|||
|
|
@ -3,26 +3,52 @@ from direct.distributed.DistributedObjectGlobalUD import DistributedObjectGlobal
|
|||
from direct.distributed.PyDatagram import *
|
||||
|
||||
from otp.otpbase import OTPGlobals
|
||||
|
||||
|
||||
import random
|
||||
import string
|
||||
import json
|
||||
class FriendsOperation:
|
||||
"""
|
||||
Base class for all friend-related operations.
|
||||
"""
|
||||
|
||||
def __init__(self, friendsManager, sender):
|
||||
"""
|
||||
Initialize the FriendsOperation.
|
||||
|
||||
:param friendsManager: The friends manager instance.
|
||||
:param sender: The sender's ID.
|
||||
"""
|
||||
self.friendsManager = friendsManager
|
||||
self.sender = sender
|
||||
|
||||
def _handleDone(self):
|
||||
# TODO
|
||||
pass
|
||||
"""
|
||||
Handle the completion of the operation.
|
||||
"""
|
||||
self.friendsManager.operations.remove(self)
|
||||
|
||||
def _handleError(self, error):
|
||||
# TODO
|
||||
pass
|
||||
"""
|
||||
Handle an error during the operation.
|
||||
|
||||
:param error: The error message.
|
||||
"""
|
||||
self.friendsManager.notify.warning(error)
|
||||
self.friendsManager.operations.remove(self)
|
||||
|
||||
|
||||
class GetFriendsListOperation(FriendsOperation):
|
||||
"""
|
||||
Operation to retrieve the friends list of a sender.
|
||||
"""
|
||||
|
||||
def __init__(self, friendsManager, sender):
|
||||
"""
|
||||
Initialize the GetFriendsListOperation.
|
||||
|
||||
:param friendsManager: The friends manager instance.
|
||||
:param sender: The sender's ID.
|
||||
"""
|
||||
FriendsOperation.__init__(self, friendsManager, sender)
|
||||
self.friendsList = None
|
||||
self.tempFriendsList = None
|
||||
|
|
@ -30,6 +56,9 @@ class GetFriendsListOperation(FriendsOperation):
|
|||
self.currentFriendIdx = None
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Start the operation to retrieve the friends list.
|
||||
"""
|
||||
self.friendsList = []
|
||||
self.tempFriendsList = []
|
||||
self.onlineFriends = []
|
||||
|
|
@ -38,6 +67,12 @@ class GetFriendsListOperation(FriendsOperation):
|
|||
self.__handleSenderRetrieved)
|
||||
|
||||
def __handleSenderRetrieved(self, dclass, fields):
|
||||
"""
|
||||
Handle the retrieval of the sender's data.
|
||||
|
||||
:param dclass: The data class of the sender.
|
||||
:param fields: The fields of the sender.
|
||||
"""
|
||||
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||||
self._handleError('Retrieved sender is not a DistributedToonUD!')
|
||||
return
|
||||
|
|
@ -51,6 +86,12 @@ class GetFriendsListOperation(FriendsOperation):
|
|||
self.__handleFriendRetrieved)
|
||||
|
||||
def __handleFriendRetrieved(self, dclass, fields):
|
||||
"""
|
||||
Handle the retrieval of a friend's data.
|
||||
|
||||
:param dclass: The data class of the friend.
|
||||
:param fields: The fields of the friend.
|
||||
"""
|
||||
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||||
self._handleError('Retrieved friend is not a DistributedToonUD!')
|
||||
return
|
||||
|
|
@ -67,11 +108,20 @@ class GetFriendsListOperation(FriendsOperation):
|
|||
self.__handleFriendRetrieved)
|
||||
|
||||
def __checkFriendsOnline(self):
|
||||
"""
|
||||
Check which friends are currently online.
|
||||
"""
|
||||
self.currentFriendIdx = 0
|
||||
for friendDetails in self.friendsList:
|
||||
self.friendsManager.air.getActivated(friendDetails[0], self.__gotActivatedResp)
|
||||
|
||||
def __gotActivatedResp(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if a friend is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the friend is activated.
|
||||
"""
|
||||
self.currentFriendIdx += 1
|
||||
if activated:
|
||||
self.onlineFriends.append(avId)
|
||||
|
|
@ -80,34 +130,67 @@ class GetFriendsListOperation(FriendsOperation):
|
|||
self._handleDone()
|
||||
|
||||
def __sendFriendsList(self, success):
|
||||
"""
|
||||
Send the friends list to the sender.
|
||||
|
||||
:param success: Whether the operation was successful.
|
||||
"""
|
||||
self.friendsManager.sendUpdateToAvatarId(self.sender, 'getFriendsListResponse', [success, self.friendsList if success else []])
|
||||
for friendId in self.onlineFriends:
|
||||
self.friendsManager.sendFriendOnline(self.sender, friendId, 0, 1)
|
||||
|
||||
def _handleDone(self):
|
||||
"""
|
||||
Handle the completion of the operation.
|
||||
"""
|
||||
self.__sendFriendsList(True)
|
||||
FriendsOperation._handleDone(self)
|
||||
|
||||
def _handleError(self, error):
|
||||
"""
|
||||
Handle an error during the operation.
|
||||
|
||||
:param error: The error message.
|
||||
"""
|
||||
self.__sendFriendsList(False)
|
||||
FriendsOperation._handleError(self, error)
|
||||
|
||||
|
||||
class GetAvatarDetailsOperation(FriendsOperation):
|
||||
"""
|
||||
Operation to retrieve the details of an avatar.
|
||||
"""
|
||||
|
||||
def __init__(self, friendsManager, sender):
|
||||
"""
|
||||
Initialize the GetAvatarDetailsOperation.
|
||||
|
||||
:param friendsManager: The friends manager instance.
|
||||
:param sender: The sender's ID.
|
||||
"""
|
||||
FriendsOperation.__init__(self, friendsManager, sender)
|
||||
self.avId = None
|
||||
self.dclass = None
|
||||
self.fields = None
|
||||
|
||||
def start(self, avId):
|
||||
"""
|
||||
Start the operation to retrieve the avatar details.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
"""
|
||||
self.avId = avId
|
||||
self.fields = {}
|
||||
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, avId,
|
||||
self.__handleAvatarRetrieved)
|
||||
|
||||
def __handleAvatarRetrieved(self, dclass, fields):
|
||||
"""
|
||||
Handle the retrieval of the avatar's data.
|
||||
|
||||
:param dclass: The data class of the avatar.
|
||||
:param fields: The fields of the avatar.
|
||||
"""
|
||||
if dclass not in (self.friendsManager.air.dclassesByName['DistributedToonUD'],
|
||||
self.friendsManager.air.dclassesByName['DistributedPetAI']):
|
||||
self._handleError('Retrieved avatar is not a DistributedToonUD or DistributedPetAI!')
|
||||
|
|
@ -119,6 +202,13 @@ class GetAvatarDetailsOperation(FriendsOperation):
|
|||
self._handleDone()
|
||||
|
||||
def __packAvatarDetails(self, dclass, fields):
|
||||
"""
|
||||
Pack the avatar details into a byte array.
|
||||
|
||||
:param dclass: The data class of the avatar.
|
||||
:param fields: The fields of the avatar.
|
||||
:return: The packed avatar details.
|
||||
"""
|
||||
# Pack required fields.
|
||||
fieldPacker = DCPacker()
|
||||
for i in range(dclass.getNumInheritedFields()):
|
||||
|
|
@ -140,6 +230,11 @@ class GetAvatarDetailsOperation(FriendsOperation):
|
|||
return fieldPacker.getBytes()
|
||||
|
||||
def __sendAvatarDetails(self, success):
|
||||
"""
|
||||
Send the avatar details to the sender.
|
||||
|
||||
:param success: Whether the operation was successful.
|
||||
"""
|
||||
datagram = PyDatagram()
|
||||
datagram.addUint32(self.fields['avId']) # avId
|
||||
datagram.addUint8(0 if success else 1) # returnCode
|
||||
|
|
@ -150,17 +245,33 @@ class GetAvatarDetailsOperation(FriendsOperation):
|
|||
self.friendsManager.sendUpdateToAvatarId(self.sender, 'getAvatarDetailsResponse', [datagram.getMessage()])
|
||||
|
||||
def _handleDone(self):
|
||||
"""
|
||||
Handle the completion of the operation.
|
||||
"""
|
||||
self.__sendAvatarDetails(True)
|
||||
FriendsOperation._handleDone(self)
|
||||
|
||||
def _handleError(self, error):
|
||||
"""
|
||||
Handle an error during the operation.
|
||||
|
||||
:param error: The error message.
|
||||
"""
|
||||
self.__sendAvatarDetails(False)
|
||||
FriendsOperation._handleError(self, error)
|
||||
|
||||
|
||||
class MakeFriendsOperation(FriendsOperation):
|
||||
"""
|
||||
Operation to make two avatars friends.
|
||||
"""
|
||||
|
||||
def __init__(self, friendsManager):
|
||||
"""
|
||||
Initialize the MakeFriendsOperation.
|
||||
|
||||
:param friendsManager: The friends manager instance.
|
||||
"""
|
||||
FriendsOperation.__init__(self, friendsManager, None)
|
||||
self.avatarAId = None
|
||||
self.avatarBId = None
|
||||
|
|
@ -172,6 +283,14 @@ class MakeFriendsOperation(FriendsOperation):
|
|||
self.avatarBFriendsList = None
|
||||
|
||||
def start(self, avatarAId, avatarBId, flags, context):
|
||||
"""
|
||||
Start the operation to make two avatars friends.
|
||||
|
||||
:param avatarAId: The first avatar's ID.
|
||||
:param avatarBId: The second avatar's ID.
|
||||
:param flags: The friendship flags.
|
||||
:param context: The context of the operation.
|
||||
"""
|
||||
self.avatarAId = avatarAId
|
||||
self.avatarBId = avatarBId
|
||||
self.flags = flags
|
||||
|
|
@ -181,14 +300,34 @@ class MakeFriendsOperation(FriendsOperation):
|
|||
self.friendsManager.air.getActivated(self.avatarAId, self.__gotActivatedAvatarA)
|
||||
|
||||
def __handleActivatedResp(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if an avatar is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the avatar is activated.
|
||||
"""
|
||||
if activated:
|
||||
self.onlineToons.append(avId)
|
||||
|
||||
def __gotActivatedAvatarA(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if the first avatar is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the avatar is activated.
|
||||
"""
|
||||
self.__handleActivatedResp(avId, activated)
|
||||
self.friendsManager.air.getActivated(self.avatarBId, self.__gotActivatedAvatarB)
|
||||
|
||||
def __handleMakeFriends(self, dclass, fields, friendId):
|
||||
"""
|
||||
Handle the process of making friends.
|
||||
|
||||
:param dclass: The data class of the avatar.
|
||||
:param fields: The fields of the avatar.
|
||||
:param friendId: The friend's ID.
|
||||
:return: A tuple indicating success and the updated friends list.
|
||||
"""
|
||||
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||||
self._handleError('Retrieved avatar is not a DistributedToonUD!')
|
||||
return False, []
|
||||
|
|
@ -207,6 +346,12 @@ class MakeFriendsOperation(FriendsOperation):
|
|||
return True, friendsList
|
||||
|
||||
def __handleAvatarARetrieved(self, dclass, fields):
|
||||
"""
|
||||
Handle the retrieval of the first avatar's data.
|
||||
|
||||
:param dclass: The data class of the avatar.
|
||||
:param fields: The fields of the avatar.
|
||||
"""
|
||||
success, avatarAFriendsList = self.__handleMakeFriends(dclass, fields, self.avatarBId)
|
||||
if success:
|
||||
self.avatarAFriendsList = avatarAFriendsList
|
||||
|
|
@ -214,17 +359,35 @@ class MakeFriendsOperation(FriendsOperation):
|
|||
self.__handleAvatarBRetrieved)
|
||||
|
||||
def __gotActivatedAvatarB(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if the second avatar is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the avatar is activated.
|
||||
"""
|
||||
self.__handleActivatedResp(avId, activated)
|
||||
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.avatarAId,
|
||||
self.__handleAvatarARetrieved)
|
||||
|
||||
def __handleAvatarBRetrieved(self, dclass, fields):
|
||||
"""
|
||||
Handle the retrieval of the second avatar's data.
|
||||
|
||||
:param dclass: The data class of the avatar.
|
||||
:param fields: The fields of the avatar.
|
||||
"""
|
||||
success, avatarBFriendsList = self.__handleMakeFriends(dclass, fields, self.avatarAId)
|
||||
if success:
|
||||
self.avatarBFriendsList = avatarBFriendsList
|
||||
self._handleDone()
|
||||
|
||||
def __handleSetFriendsList(self, avId, friendsList):
|
||||
"""
|
||||
Handle setting the friends list for an avatar.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param friendsList: The updated friends list.
|
||||
"""
|
||||
if avId in self.onlineToons:
|
||||
self.friendsManager.sendUpdateToAvatar(avId, 'setFriendsList', [friendsList])
|
||||
else:
|
||||
|
|
@ -234,6 +397,9 @@ class MakeFriendsOperation(FriendsOperation):
|
|||
{'setFriendsList': [friendsList]})
|
||||
|
||||
def _handleDone(self):
|
||||
"""
|
||||
Handle the completion of the operation.
|
||||
"""
|
||||
self.resultCode = 1
|
||||
if self.avatarAFriendsList is not None and self.avatarBFriendsList is not None:
|
||||
self.__handleSetFriendsList(self.avatarAId, self.avatarAFriendsList)
|
||||
|
|
@ -247,14 +413,28 @@ class MakeFriendsOperation(FriendsOperation):
|
|||
FriendsOperation._handleDone(self)
|
||||
|
||||
def _handleError(self, error):
|
||||
"""
|
||||
Handle an error during the operation.
|
||||
|
||||
:param error: The error message.
|
||||
"""
|
||||
self.resultCode = 0
|
||||
self.friendsManager.sendMakeFriendsResponse(self.avatarAId, self.avatarBId, self.resultCode, self.context)
|
||||
FriendsOperation._handleError(self, error)
|
||||
|
||||
|
||||
class RemoveFriendOperation(FriendsOperation):
|
||||
"""
|
||||
Operation to remove a friend from the sender's friends list.
|
||||
"""
|
||||
|
||||
def __init__(self, friendsManager, sender):
|
||||
"""
|
||||
Initialize the RemoveFriendOperation.
|
||||
|
||||
:param friendsManager: The friends manager instance.
|
||||
:param sender: The sender's ID.
|
||||
"""
|
||||
FriendsOperation.__init__(self, friendsManager, sender)
|
||||
self.friendId = None
|
||||
self.onlineToons = None
|
||||
|
|
@ -262,24 +442,55 @@ class RemoveFriendOperation(FriendsOperation):
|
|||
self.friendFriendsList = None
|
||||
|
||||
def start(self, friendId):
|
||||
"""
|
||||
Start the operation to remove a friend.
|
||||
|
||||
:param friendId: The friend's ID.
|
||||
"""
|
||||
self.friendId = friendId
|
||||
self.onlineToons = []
|
||||
self.friendsManager.air.getActivated(self.sender, self.__gotSenderActivated)
|
||||
|
||||
def __handleActivatedResp(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if an avatar is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the avatar is activated.
|
||||
"""
|
||||
if activated:
|
||||
self.onlineToons.append(avId)
|
||||
|
||||
def __gotSenderActivated(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if the sender is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the avatar is activated.
|
||||
"""
|
||||
self.__handleActivatedResp(avId, activated)
|
||||
self.friendsManager.air.getActivated(self.friendId, self.__gotFriendActivated)
|
||||
|
||||
def __gotFriendActivated(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if the friend is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the avatar is activated.
|
||||
"""
|
||||
self.__handleActivatedResp(avId, activated)
|
||||
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.sender,
|
||||
self.__handleSenderRetrieved)
|
||||
|
||||
def __handleRemoveFriend(self, dclass, fields, friendId):
|
||||
"""
|
||||
Handle the process of removing a friend.
|
||||
|
||||
:param dclass: The data class of the avatar.
|
||||
:param fields: The fields of the avatar.
|
||||
:param friendId: The friend's ID.
|
||||
:return: A tuple indicating success and the updated friends list.
|
||||
"""
|
||||
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||||
self._handleError('Retrieved sender is not a DistributedToonUD!')
|
||||
return False, []
|
||||
|
|
@ -299,6 +510,12 @@ class RemoveFriendOperation(FriendsOperation):
|
|||
return False, []
|
||||
|
||||
def __handleSenderRetrieved(self, dclass, fields):
|
||||
"""
|
||||
Handle the retrieval of the sender's data.
|
||||
|
||||
:param dclass: The data class of the sender.
|
||||
:param fields: The fields of the sender.
|
||||
"""
|
||||
success, senderFriendsList = self.__handleRemoveFriend(dclass, fields, self.friendId)
|
||||
if success:
|
||||
self.senderFriendsList = senderFriendsList
|
||||
|
|
@ -306,12 +523,24 @@ class RemoveFriendOperation(FriendsOperation):
|
|||
self.__handleFriendRetrieved)
|
||||
|
||||
def __handleFriendRetrieved(self, dclass, fields):
|
||||
"""
|
||||
Handle the retrieval of the friend's data.
|
||||
|
||||
:param dclass: The data class of the friend.
|
||||
:param fields: The fields of the friend.
|
||||
"""
|
||||
success, friendFriendsList = self.__handleRemoveFriend(dclass, fields, self.sender)
|
||||
if success:
|
||||
self.friendFriendsList = friendFriendsList
|
||||
self._handleDone()
|
||||
|
||||
def __handleSetFriendsList(self, avId, friendsList):
|
||||
"""
|
||||
Handle setting the friends list for an avatar.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param friendsList: The updated friends list.
|
||||
"""
|
||||
if avId in self.onlineToons:
|
||||
self.friendsManager.sendUpdateToAvatar(avId, 'setFriendsList', [friendsList])
|
||||
else:
|
||||
|
|
@ -321,6 +550,9 @@ class RemoveFriendOperation(FriendsOperation):
|
|||
{'setFriendsList': [friendsList]})
|
||||
|
||||
def _handleDone(self):
|
||||
"""
|
||||
Handle the completion of the operation.
|
||||
"""
|
||||
if self.senderFriendsList is not None and self.friendFriendsList is not None:
|
||||
self.__handleSetFriendsList(self.sender, self.senderFriendsList)
|
||||
self.__handleSetFriendsList(self.friendId, self.friendFriendsList)
|
||||
|
|
@ -336,24 +568,47 @@ class RemoveFriendOperation(FriendsOperation):
|
|||
|
||||
|
||||
class ComingOnlineOperation(FriendsOperation):
|
||||
"""
|
||||
Operation to handle an avatar coming online.
|
||||
"""
|
||||
|
||||
def __init__(self, friendsManager):
|
||||
"""
|
||||
Initialize the ComingOnlineOperation.
|
||||
|
||||
:param friendsManager: The friends manager instance.
|
||||
"""
|
||||
FriendsOperation.__init__(self, friendsManager, None)
|
||||
self.avId = None
|
||||
self.friendsList = None
|
||||
self.currentFriendIdx = None
|
||||
|
||||
def start(self, avId, friendsList):
|
||||
"""
|
||||
Start the operation to handle an avatar coming online.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param friendsList: The friends list of the avatar.
|
||||
"""
|
||||
self.avId = avId
|
||||
self.friendsList = friendsList
|
||||
self.__checkFriendsOnline()
|
||||
|
||||
def __checkFriendsOnline(self):
|
||||
"""
|
||||
Check which friends are currently online.
|
||||
"""
|
||||
self.currentFriendIdx = 0
|
||||
for friendId in self.friendsList:
|
||||
self.friendsManager.air.getActivated(friendId, self.__gotFriendActivated)
|
||||
|
||||
def __gotFriendActivated(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if a friend is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the friend is activated.
|
||||
"""
|
||||
self.currentFriendIdx += 1
|
||||
if activated:
|
||||
self.friendsManager.declareObject(avId, self.avId)
|
||||
|
|
@ -365,8 +620,16 @@ class ComingOnlineOperation(FriendsOperation):
|
|||
|
||||
|
||||
class GoingOfflineOperation(FriendsOperation):
|
||||
"""
|
||||
Operation to handle an avatar going offline.
|
||||
"""
|
||||
|
||||
def __init__(self, friendsManager):
|
||||
"""
|
||||
Initialize the GoingOfflineOperation.
|
||||
|
||||
:param friendsManager: The friends manager instance.
|
||||
"""
|
||||
FriendsOperation.__init__(self, friendsManager, None)
|
||||
self.avId = None
|
||||
self.friendsList = None
|
||||
|
|
@ -374,12 +637,23 @@ class GoingOfflineOperation(FriendsOperation):
|
|||
self.currentFriendIdx = None
|
||||
|
||||
def start(self, avId):
|
||||
"""
|
||||
Start the operation to handle an avatar going offline.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
"""
|
||||
self.avId = avId
|
||||
self.friendsList = []
|
||||
self.accId = 0
|
||||
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.avId, self.__handleAvatarRetrieved)
|
||||
|
||||
def __handleAvatarRetrieved(self, dclass, fields):
|
||||
"""
|
||||
Handle the retrieval of the avatar's data.
|
||||
|
||||
:param dclass: The data class of the avatar.
|
||||
:param fields: The fields of the avatar.
|
||||
"""
|
||||
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||||
self._handleError('Retrieved avatar is not a DistributedToonUD!')
|
||||
return
|
||||
|
|
@ -389,11 +663,20 @@ class GoingOfflineOperation(FriendsOperation):
|
|||
self.__checkFriendsOnline()
|
||||
|
||||
def __checkFriendsOnline(self):
|
||||
"""
|
||||
Check which friends are currently online.
|
||||
"""
|
||||
self.currentFriendIdx = 0
|
||||
for friendId, _ in self.friendsList:
|
||||
self.friendsManager.air.getActivated(friendId, self.__gotFriendActivated)
|
||||
|
||||
def __gotFriendActivated(self, avId, activated):
|
||||
"""
|
||||
Handle the response of checking if a friend is activated.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param activated: Whether the friend is activated.
|
||||
"""
|
||||
self.currentFriendIdx += 1
|
||||
if activated:
|
||||
self.friendsManager.undeclareObject(avId, self.avId)
|
||||
|
|
@ -403,19 +686,97 @@ class GoingOfflineOperation(FriendsOperation):
|
|||
if self.currentFriendIdx >= len(self.friendsList):
|
||||
self._handleDone()
|
||||
|
||||
class GenerateSecretOperation(FriendsOperation):
|
||||
"""
|
||||
Operation to generate a secret.
|
||||
"""
|
||||
|
||||
def __init__(self, friendsManager):
|
||||
"""
|
||||
Initialize the GenerateSecretOperation.
|
||||
|
||||
:param friendsManager: The friends manager instance.
|
||||
:param requesterId: The requester's ID.
|
||||
"""
|
||||
FriendsOperation.__init__(self, friendsManager, None)
|
||||
self.secret = None
|
||||
self.requesterId = None
|
||||
|
||||
def start(self, requesterId):
|
||||
"""
|
||||
Start the operation to generate a secret.
|
||||
Format of secret:
|
||||
TT 3 random letters/numbers 3 random letters/numbers
|
||||
"""
|
||||
self.requesterId = requesterId
|
||||
# first check if friends list is full
|
||||
|
||||
# check if too many secrets
|
||||
# TODO
|
||||
self.secret = ''
|
||||
for i in range(3):
|
||||
self.secret += random.choice(string.ascii_letters + string.digits)
|
||||
self.secret += ' '
|
||||
for i in range(3):
|
||||
self.secret += random.choice(string.ascii_letters + string.digits)
|
||||
|
||||
self.friendsManager.secrets[self.secret] = requesterId
|
||||
self._handleDone()
|
||||
|
||||
def _handleDone(self):
|
||||
"""
|
||||
Handle the completion of the operation.
|
||||
"""
|
||||
FriendsOperation._handleDone(self)
|
||||
# send the response to the requester that it was a success, the result and the secret
|
||||
self.friendsManager.sendRequestSecretResponse(self.requesterId, 1, self.secret)
|
||||
|
||||
|
||||
def _handleError(self, error):
|
||||
"""
|
||||
Handle an error during the operation.
|
||||
|
||||
:param error: The error message.
|
||||
"""
|
||||
FriendsOperation._handleError(self, error)
|
||||
# send the response to the requester that it was a failure, the result and the secret
|
||||
self.friendsManager.sendRequestSecretResponse(self.requesterId, 0, '')
|
||||
|
||||
class ToontownFriendsManagerUD(DistributedObjectGlobalUD):
|
||||
"""
|
||||
The main friends manager class for Toontown.
|
||||
"""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('ToontownFriendsManagerUD')
|
||||
|
||||
def __init__(self, air):
|
||||
"""
|
||||
Initialize the ToontownFriendsManagerUD.
|
||||
|
||||
:param air: The AI repository instance.
|
||||
"""
|
||||
DistributedObjectGlobalUD.__init__(self, air)
|
||||
self.secret = None
|
||||
self.operations = []
|
||||
self.secrets = []
|
||||
self.secrets = {}
|
||||
|
||||
def sendMakeFriendsResponse(self, avatarAId, avatarBId, result, context):
|
||||
"""
|
||||
Send the response for making friends.
|
||||
|
||||
:param avatarAId: The first avatar's ID.
|
||||
:param avatarBId: The second avatar's ID.
|
||||
:param result: The result of the operation.
|
||||
:param context: The context of the operation.
|
||||
"""
|
||||
self.sendUpdate('makeFriendsResponse', [avatarAId, avatarBId, result, context])
|
||||
|
||||
def declareObject(self, doId, objId):
|
||||
"""
|
||||
Declare an object to the client.
|
||||
|
||||
:param doId: The distributed object ID.
|
||||
:param objId: The object ID.
|
||||
"""
|
||||
datagram = PyDatagram()
|
||||
datagram.addServerHeader(self.GetPuppetConnectionChannel(doId), self.air.ourChannel, CLIENTAGENT_DECLARE_OBJECT)
|
||||
datagram.addUint32(objId)
|
||||
|
|
@ -423,6 +784,13 @@ class ToontownFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
self.air.send(datagram)
|
||||
|
||||
def undeclareObject(self, doId, objId, isAccount=False):
|
||||
"""
|
||||
Undeclare an object to the client.
|
||||
|
||||
:param doId: The distributed object ID.
|
||||
:param objId: The object ID.
|
||||
:param isAccount: Whether the object is an account.
|
||||
"""
|
||||
datagram = PyDatagram()
|
||||
if isAccount:
|
||||
datagram.addServerHeader(self.GetAccountConnectionChannel(doId), self.air.ourChannel,
|
||||
|
|
@ -435,12 +803,33 @@ class ToontownFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
self.air.send(datagram)
|
||||
|
||||
def sendFriendOnline(self, avId, friendId, commonChatFlags, whitelistChatFlags):
|
||||
"""
|
||||
Notify that a friend has come online.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param friendId: The friend's ID.
|
||||
:param commonChatFlags: The common chat flags.
|
||||
:param whitelistChatFlags: The whitelist chat flags.
|
||||
"""
|
||||
self.sendUpdateToAvatarId(avId, 'friendOnline', [friendId, commonChatFlags, whitelistChatFlags])
|
||||
|
||||
def sendFriendOffline(self, avId, friendId):
|
||||
"""
|
||||
Notify that a friend has gone offline.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param friendId: The friend's ID.
|
||||
"""
|
||||
self.sendUpdateToAvatarId(avId, 'friendOffline', [friendId])
|
||||
|
||||
def sendUpdateToAvatar(self, avId, fieldName, args=[]):
|
||||
"""
|
||||
Send an update to an avatar.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param fieldName: The field name to update.
|
||||
:param args: The arguments for the update.
|
||||
"""
|
||||
dclass = self.air.dclassesByName['DistributedToonUD']
|
||||
if not dclass:
|
||||
return
|
||||
|
|
@ -453,6 +842,12 @@ class ToontownFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
self.air.send(datagram)
|
||||
|
||||
def runSenderOperation(self, operationType, *args):
|
||||
"""
|
||||
Run an operation initiated by the sender.
|
||||
|
||||
:param operationType: The type of operation.
|
||||
:param args: The arguments for the operation.
|
||||
"""
|
||||
sender = self.air.getAvatarIdFromSender()
|
||||
if not sender:
|
||||
return
|
||||
|
|
@ -462,27 +857,84 @@ class ToontownFriendsManagerUD(DistributedObjectGlobalUD):
|
|||
newOperation.start(*args)
|
||||
|
||||
def runServerOperation(self, operationType, *args):
|
||||
"""
|
||||
Run an operation initiated by the server.
|
||||
|
||||
:param operationType: The type of operation.
|
||||
:param args: The arguments for the operation.
|
||||
"""
|
||||
newOperation = operationType(self)
|
||||
self.operations.append(newOperation)
|
||||
newOperation.start(*args)
|
||||
|
||||
def getFriendsListRequest(self):
|
||||
"""
|
||||
Handle a request to get the friends list.
|
||||
"""
|
||||
self.runSenderOperation(GetFriendsListOperation)
|
||||
|
||||
def getAvatarDetailsRequest(self, avId):
|
||||
"""
|
||||
Handle a request to get avatar details.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
"""
|
||||
self.runSenderOperation(GetAvatarDetailsOperation, avId)
|
||||
|
||||
def makeFriends(self, avatarAId, avatarBId, flags, context):
|
||||
"""
|
||||
Handle a request to make two avatars friends.
|
||||
|
||||
:param avatarAId: The first avatar's ID.
|
||||
:param avatarBId: The second avatar's ID.
|
||||
:param flags: The friendship flags.
|
||||
:param context: The context of the operation.
|
||||
"""
|
||||
self.runServerOperation(MakeFriendsOperation, avatarAId, avatarBId, flags, context)
|
||||
|
||||
def removeFriend(self, friendId):
|
||||
"""
|
||||
Handle a request to remove a friend.
|
||||
|
||||
:param friendId: The friend's ID.
|
||||
"""
|
||||
self.runSenderOperation(RemoveFriendOperation, friendId)
|
||||
|
||||
def requestSecret(self, requesterId):
|
||||
"""
|
||||
Handle a request to generate a secret.
|
||||
|
||||
"""
|
||||
self.runServerOperation(GenerateSecretOperation, requesterId)
|
||||
|
||||
def comingOnline(self, avId, friendsList):
|
||||
"""
|
||||
Handle a request for an avatar coming online.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
:param friendsList: The friends list of the avatar.
|
||||
"""
|
||||
self.runServerOperation(ComingOnlineOperation, avId, friendsList)
|
||||
|
||||
def goingOffline(self, avId):
|
||||
"""
|
||||
Handle a request for an avatar going offline.
|
||||
|
||||
:param avId: The avatar ID.
|
||||
"""
|
||||
self.runServerOperation(GoingOfflineOperation, avId)
|
||||
|
||||
def requestSecret(self, requesterId):
|
||||
print('requestSecret')
|
||||
def sendRequestSecretResponse(self, requesterId, success, secret):
|
||||
"""
|
||||
Send a response to a secret request.
|
||||
|
||||
:param requesterId: The requester's ID.
|
||||
:param success: Whether the operation was successful.
|
||||
:param secret: The generated secret.
|
||||
"""
|
||||
self.sendUpdate('requestSecretResponse', [success, secret, requesterId])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue