oldschool-toontown/toontown/estate/DistributedPhone.py
2019-11-02 18:27:54 -04:00

379 lines
17 KiB
Python

from toontown.toonbase import ToontownGlobals
import PhoneGlobals
from toontown.catalog import CatalogScreen
from toontown.catalog import CatalogItem
from toontown.toontowngui import TTDialog
from toontown.toonbase import TTLocalizer
import DistributedHouseInterior
from direct.actor import Actor
import DistributedFurnitureItem
from direct.distributed import ClockDelta
from direct.showbase import PythonUtil
from direct.showutil import Rope
from direct.directnotify.DirectNotifyGlobal import *
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
import string
from toontown.quest import Quests
from direct.task import Task
class DistributedPhone(DistributedFurnitureItem.DistributedFurnitureItem):
notify = directNotify.newCategory('DistributedPhone')
movieDelay = 0.5
def __init__(self, cr):
DistributedFurnitureItem.DistributedFurnitureItem.__init__(self, cr)
self.lastAvId = 0
self.hasLocalAvatar = 0
self.lastTime = 0
self.initialScale = None
self.usedInitialScale = 0
self.toonScale = None
self.phoneGui = None
self.phoneDialog = None
self.model = None
self.cord = None
self.receiverGeom = None
self.receiverJoint = None
self.phoneSphereEvent = 'phoneSphere'
self.phoneSphereEnterEvent = 'enter' + self.phoneSphereEvent
self.phoneGuiDoneEvent = 'phoneGuiDone'
self.pickupMovieDoneEvent = 'phonePickupDone'
self.numHouseItems = None
self.interval = None
self.intervalAvatar = None
self.phoneInUse = 0
self.origToonHpr = None
return
def announceGenerate(self):
self.notify.debug('announceGenerate')
DistributedFurnitureItem.DistributedFurnitureItem.announceGenerate(self)
self.accept(self.phoneSphereEnterEvent, self.__handleEnterSphere)
self.load()
taskMgr.doMethodLater(6, self.ringIfHasPhoneQuest, self.uniqueName('ringDoLater'))
def loadModel(self):
self.model = Actor.Actor('phase_5.5/models/estate/prop_phone-mod', {'SS_phoneOut': 'phase_5.5/models/estate/prop_phone-SS_phoneOut',
'SS_takePhone': 'phase_5.5/models/estate/prop_phone-SS_takePhone',
'SS_phoneNeutral': 'phase_5.5/models/estate/prop_phone-SS_phoneNeutral',
'SS_phoneBack': 'phase_5.5/models/estate/prop_phone-SS_phoneBack',
'SM_phoneOut': 'phase_5.5/models/estate/prop_phone-SM_phoneOut',
'SM_takePhone': 'phase_5.5/models/estate/prop_phone-SM_takePhone',
'SM_phoneNeutral': 'phase_5.5/models/estate/prop_phone-SM_phoneNeutral',
'SM_phoneBack': 'phase_5.5/models/estate/prop_phone-SM_phoneBack',
'SL_phoneOut': 'phase_5.5/models/estate/prop_phone-SL_phoneOut',
'SL_takePhone': 'phase_5.5/models/estate/prop_phone-SL_takePhone',
'SL_phoneNeutral': 'phase_5.5/models/estate/prop_phone-SL_phoneNeutral',
'SL_phoneBack': 'phase_5.5/models/estate/prop_phone-SL_phoneBack',
'MS_phoneOut': 'phase_5.5/models/estate/prop_phone-MS_phoneOut',
'MS_takePhone': 'phase_5.5/models/estate/prop_phone-MS_takePhone',
'MS_phoneNeutral': 'phase_5.5/models/estate/prop_phone-MS_phoneNeutral',
'MS_phoneBack': 'phase_5.5/models/estate/prop_phone-MS_phoneBack',
'MM_phoneOut': 'phase_5.5/models/estate/prop_phone-MM_phoneOut',
'MM_takePhone': 'phase_5.5/models/estate/prop_phone-MM_takePhone',
'MM_phoneNeutral': 'phase_5.5/models/estate/prop_phone-MM_phoneNeutral',
'MM_phoneBack': 'phase_5.5/models/estate/prop_phone-MM_phoneBack',
'ML_phoneOut': 'phase_5.5/models/estate/prop_phone-ML_phoneOut',
'ML_takePhone': 'phase_5.5/models/estate/prop_phone-ML_takePhone',
'ML_phoneNeutral': 'phase_5.5/models/estate/prop_phone-ML_phoneNeutral',
'ML_phoneBack': 'phase_5.5/models/estate/prop_phone-ML_phoneBack',
'LS_phoneOut': 'phase_5.5/models/estate/prop_phone-LS_phoneOut',
'LS_takePhone': 'phase_5.5/models/estate/prop_phone-LS_takePhone',
'LS_phoneNeutral': 'phase_5.5/models/estate/prop_phone-LS_phoneNeutral',
'LS_phoneBack': 'phase_5.5/models/estate/prop_phone-LS_phoneBack',
'LM_phoneOut': 'phase_5.5/models/estate/prop_phone-LM_phoneOut',
'LM_takePhone': 'phase_5.5/models/estate/prop_phone-LM_takePhone',
'LM_phoneNeutral': 'phase_5.5/models/estate/prop_phone-LM_phoneNeutral',
'LM_phoneBack': 'phase_5.5/models/estate/prop_phone-LM_phoneBack',
'LL_phoneOut': 'phase_5.5/models/estate/prop_phone-LL_phoneOut',
'LL_takePhone': 'phase_5.5/models/estate/prop_phone-LL_takePhone',
'LL_phoneNeutral': 'phase_5.5/models/estate/prop_phone-LL_phoneNeutral',
'LL_phoneBack': 'phase_5.5/models/estate/prop_phone-LL_phoneBack'})
self.model.pose('SS_phoneOut', 0)
self.receiverJoint = self.model.find('**/joint_receiver')
self.receiverGeom = self.receiverJoint.getChild(0)
mount = loader.loadModel('phase_5.5/models/estate/phoneMount-mod')
mount.setTransparency(0, 1)
self.model.reparentTo(mount)
self.ringSfx = loader.loadSfx('phase_3.5/audio/sfx/telephone_ring.mp3')
self.handleSfx = loader.loadSfx('phase_5.5/audio/sfx/telephone_handle2.mp3')
self.hangUpSfx = loader.loadSfx('phase_5.5/audio/sfx/telephone_hang_up.mp3')
self.pickUpSfx = loader.loadSfx('phase_5.5/audio/sfx/telephone_pickup1.mp3')
if self.initialScale:
mount.setScale(*self.initialScale)
self.usedInitialScale = 1
phoneSphere = CollisionSphere(0, -0.66, 0, 0.2)
phoneSphere.setTangible(0)
phoneSphereNode = CollisionNode(self.phoneSphereEvent)
phoneSphereNode.setIntoCollideMask(ToontownGlobals.WallBitmask)
phoneSphereNode.addSolid(phoneSphere)
mount.attachNewNode(phoneSphereNode)
if not self.model.find('**/CurveNode7').isEmpty():
self.setupCord()
return mount
def setupCamera(self, mode):
camera.wrtReparentTo(render)
if mode == PhoneGlobals.PHONE_MOVIE_PICKUP:
camera.lerpPosHpr(4, -4, base.localAvatar.getHeight() - 0.5, 35, -8, 0, 1, other=base.localAvatar, blendType='easeOut', task=self.uniqueName('lerpCamera'))
def setupCord(self):
if self.cord:
self.cord.detachNode()
self.cord = None
self.cord = Rope.Rope(self.uniqueName('phoneCord'))
self.cord.setColor(0, 0, 0, 1)
self.cord.setup(4, ((self.receiverGeom, (0, 0, 0)),
(self.model.find('**/joint_curveNode1'), (0, 0, 0)),
(self.model.find('**/joint_curveNode2'), (0, 0, 0)),
(self.model.find('**/joint_curveNode3'), (0, 0, 0)),
(self.model.find('**/joint_curveNode4'), (0, 0, 0)),
(self.model.find('**/joint_curveNode5'), (0, 0, 0)),
(self.model.find('**/joint_curveNode6'), (0, 0, 0)),
(self.model.find('**/CurveNode7'), (0, 0, 0))))
self.cord.reparentTo(self.model)
self.cord.node().setBounds(BoundingSphere(Point3(-1.0, -3.2, 2.6), 2.0))
return
def disable(self):
self.notify.debug('disable')
taskMgr.remove(self.uniqueName('ringDoLater'))
self.clearInterval()
if self.phoneGui:
self.phoneGui.hide()
self.phoneGui.unload()
self.phoneGui = None
if self.phoneDialog:
self.phoneDialog.cleanup()
self.phoneDialog = None
self.__receiverToPhone()
if self.hasLocalAvatar:
self.freeAvatar()
self.ignoreAll()
DistributedFurnitureItem.DistributedFurnitureItem.disable(self)
return
def delete(self):
self.notify.debug('delete')
self.model.cleanup()
DistributedFurnitureItem.DistributedFurnitureItem.delete(self)
def setInitialScale(self, sx, sy, sz):
self.initialScale = (sx, sy, sz)
if not self.usedInitialScale and self.model:
self.setScale(*self.initialScale)
self.usedInitialScale = 1
def __handleEnterSphere(self, collEntry):
if self.smoothStarted:
return
if base.localAvatar.doId == self.lastAvId and globalClock.getFrameTime() <= self.lastTime + 0.5:
self.notify.debug('Ignoring duplicate entry for avatar.')
return
if self.hasLocalAvatar:
self.freeAvatar()
base.localAvatar.lookupPetDNA()
self.notify.debug('Entering Phone Sphere....')
taskMgr.remove(self.uniqueName('ringDoLater'))
self.ignore(self.phoneSphereEnterEvent)
self.cr.playGame.getPlace().detectedPhoneCollision()
self.hasLocalAvatar = 1
self.sendUpdate('avatarEnter', [])
def __handlePhoneDone(self):
self.sendUpdate('avatarExit', [])
self.ignore(self.phoneGuiDoneEvent)
self.phoneGui = None
return
def freeAvatar(self):
if self.hasLocalAvatar:
base.localAvatar.speed = 0
taskMgr.remove(self.uniqueName('lerpCamera'))
base.localAvatar.posCamera(0, 0)
if base.cr.playGame.place != None:
base.cr.playGame.getPlace().setState('walk')
self.hasLocalAvatar = 0
self.ignore(self.pickupMovieDoneEvent)
self.accept(self.phoneSphereEnterEvent, self.__handleEnterSphere)
self.lastTime = globalClock.getFrameTime()
return
def setLimits(self, numHouseItems):
self.numHouseItems = numHouseItems
def setMovie(self, mode, avId, timestamp):
elapsed = ClockDelta.globalClockDelta.localElapsedTime(timestamp, bits=32)
elapsed = max(elapsed - self.movieDelay, 0)
self.ignore(self.pickupMovieDoneEvent)
if avId != 0:
self.lastAvId = avId
self.lastTime = globalClock.getFrameTime()
isLocalToon = avId == base.localAvatar.doId
avatar = self.cr.doId2do.get(avId)
self.notify.debug('setMovie: %s %s %s' % (mode, avId, isLocalToon))
if mode == PhoneGlobals.PHONE_MOVIE_CLEAR:
self.notify.debug('setMovie: clear')
self.numHouseItems = None
if self.phoneInUse:
self.clearInterval()
self.phoneInUse = 0
elif mode == PhoneGlobals.PHONE_MOVIE_EMPTY:
self.notify.debug('setMovie: empty')
if isLocalToon:
self.phoneDialog = TTDialog.TTDialog(dialogName='PhoneEmpty', style=TTDialog.Acknowledge, text=TTLocalizer.DistributedPhoneEmpty, text_wordwrap=15, fadeScreen=1, command=self.__clearDialog)
self.numHouseItems = None
self.phoneInUse = 0
elif mode == PhoneGlobals.PHONE_MOVIE_PICKUP:
self.notify.debug('setMovie: gui')
if avatar:
interval = self.takePhoneInterval(avatar)
if isLocalToon:
self.setupCamera(mode)
interval.setDoneEvent(self.pickupMovieDoneEvent)
self.acceptOnce(self.pickupMovieDoneEvent, self.__showPhoneGui)
self.playInterval(interval, elapsed, avatar)
self.phoneInUse = 1
elif mode == PhoneGlobals.PHONE_MOVIE_HANGUP:
self.notify.debug('setMovie: gui')
if avatar:
interval = self.replacePhoneInterval(avatar)
self.playInterval(interval, elapsed, avatar)
self.numHouseItems = None
self.phoneInUse = 0
else:
self.notify.warning('unknown mode in setMovie: %s' % mode)
return
def __showPhoneGui(self):
if self.toonScale:
self.sendUpdate('setNewScale', [self.toonScale[0], self.toonScale[1], self.toonScale[2]])
self.phoneGui = CatalogScreen.CatalogScreen(phone=self, doneEvent=self.phoneGuiDoneEvent)
self.phoneGui.show()
self.accept(self.phoneGuiDoneEvent, self.__handlePhoneDone)
self.accept('phoneAsleep', self.__handlePhoneAsleep)
def __handlePhoneAsleep(self):
self.ignore('phoneAsleep')
if self.phoneGui:
self.phoneGui.unload()
self.__handlePhoneDone()
def requestPurchase(self, item, callback, optional = -1):
blob = item.getBlob(store=CatalogItem.Customization)
context = self.getCallbackContext(callback, [item])
self.sendUpdate('requestPurchaseMessage', [context, blob, optional])
def requestGiftPurchase(self, item, targetDoID, callback, optional = -1):
print 'in the client phone'
blob = item.getBlob(store=CatalogItem.Customization)
context = self.getCallbackContext(callback, [item])
self.sendUpdate('requestGiftPurchaseMessage', [context,
targetDoID,
blob,
optional])
def requestPurchaseResponse(self, context, retcode):
self.doCallbackContext(context, [retcode])
def requestGiftPurchaseResponse(self, context, retcode):
self.doCallbackContext(context, [retcode])
def __clearDialog(self, event):
self.phoneDialog.cleanup()
self.phoneDialog = None
self.freeAvatar()
return
def takePhoneInterval(self, toon):
torso = TextEncoder.upper(toon.style.torso[0])
legs = TextEncoder.upper(toon.style.legs[0])
phoneOutAnim = '%s%s_phoneOut' % (torso, legs)
takePhoneAnim = '%s%s_takePhone' % (torso, legs)
phoneNeutralAnim = '%s%s_phoneNeutral' % (torso, legs)
self.toonScale = toon.getGeomNode().getChild(0).getScale(self.getParent())
walkTime = 1.0
scaleTime = 1.0
origScale = self.getScale()
origToonPos = toon.getPos()
origToonHpr = toon.getHpr()
self.origToonHpr = origToonHpr
self.setScale(self.toonScale)
toon.setPosHpr(self, 0, -4.5, 0, 0, 0, 0)
destToonPos = toon.getPos()
destToonHpr = toon.getHpr()
destToonHpr = VBase3(PythonUtil.fitSrcAngle2Dest(destToonHpr[0], origToonHpr[0]), destToonHpr[1], destToonHpr[2])
self.setScale(origScale)
toon.setPos(origToonPos)
toon.setHpr(origToonHpr)
walkToPhone = Sequence(Func(toon.stopSmooth), Func(toon.loop, 'walk'), Func(base.playSfx, base.localAvatar.soundWalk), toon.posHprInterval(walkTime, destToonPos, destToonHpr, blendType='easeInOut'), Func(toon.loop, 'neutral'), Func(toon.startSmooth))
interval = Sequence(Parallel(walkToPhone, ActorInterval(self.model, phoneOutAnim), self.scaleInterval(scaleTime, self.toonScale, blendType='easeInOut')), Parallel(ActorInterval(self.model, takePhoneAnim), ActorInterval(toon, 'takePhone'), Sequence(Wait(0.625), Func(base.playSfx, self.pickUpSfx), Func(self.__receiverToHand, toon), Wait(1), Func(base.playSfx, self.handleSfx))), Func(self.model.loop, phoneNeutralAnim), Func(toon.loop, 'phoneNeutral'), Func(base.playSfx, self.ringSfx))
return interval
def replacePhoneInterval(self, toon):
torso = TextEncoder.upper(toon.style.torso[0])
legs = TextEncoder.upper(toon.style.legs[0])
phoneBackAnim = '%s%s_phoneBack' % (torso, legs)
scaleTime = 1.0
interval = Sequence(Parallel(ActorInterval(self.model, phoneBackAnim), ActorInterval(toon, 'phoneBack'), Sequence(Wait(1.0), Func(self.__receiverToPhone), Func(base.playSfx, self.hangUpSfx))), self.scaleInterval(scaleTime, localAvatar.getGeomNode().getScale()[2], blendType='easeInOut'), Func(toon.loop, 'neutral'))
if self.origToonHpr:
interval.append(Func(toon.setHpr, self.origToonHpr))
self.origToonHpr = None
if toon == base.localAvatar:
interval.append(Func(self.freeAvatar))
return interval
def __receiverToHand(self, toon):
self.receiverGeom.reparentTo(toon.leftHand)
self.receiverGeom.setPosHpr(0.0906813, 0.380375, 0.1, 32.41, 70.68, 137.04)
def __receiverToPhone(self):
self.receiverGeom.reparentTo(self.receiverJoint)
self.receiverGeom.setPosHpr(0, 0, 0, 0, 0, 0)
def playInterval(self, interval, elapsed, avatar):
if self.interval != None:
self.interval.finish()
self.interval = None
self.interval = interval
self.interval.start(elapsed)
if self.intervalAvatar != avatar:
if self.intervalAvatar:
self.ignore(self.intervalAvatar.uniqueName('disable'))
if avatar:
self.accept(avatar.uniqueName('disable'), self.clearInterval)
self.intervalAvatar = avatar
return
def clearInterval(self):
if self.interval != None:
self.interval.finish()
self.interval = None
if self.intervalAvatar:
self.ignore(self.intervalAvatar.uniqueName('disable'))
self.intervalAvatar = None
self.__receiverToPhone()
self.model.pose('SS_phoneOut', 0)
self.phoneInUse = 0
return
def ringIfHasPhoneQuest(self, task):
if Quests.avatarHasPhoneQuest(base.localAvatar) and not Quests.avatarHasCompletedPhoneQuest(base.localAvatar):
self.ring()
return Task.done
def ring(self):
if self.phoneInUse:
return 0
phone = self.find('**/prop_phone')
r = 2.0
w = 0.05
shakeOnce = Sequence(Func(phone.setR, r), Wait(w), Func(phone.setR, -r), Wait(w))
shakeSeq = Sequence()
for i in range(16):
shakeSeq.append(shakeOnce)
ringIval = Parallel(Func(base.playSfx, self.ringSfx), shakeSeq, Func(phone.setR, 0))
self.playInterval(ringIval, 0.0, None)
return