373 lines
18 KiB
Python
373 lines
18 KiB
Python
import copy
|
|
from direct.actor import Actor
|
|
from direct.distributed.ClockDelta import *
|
|
from direct.fsm import ClassicFSM, State
|
|
from direct.fsm import State
|
|
from direct.interval.IntervalGlobal import *
|
|
from panda3d.core import *
|
|
import random
|
|
|
|
from otp.avatar import Avatar
|
|
from otp.otpbase import OTPGlobals
|
|
from toontown.distributed import DelayDelete
|
|
from toontown.effects import Bubbles
|
|
from toontown.hood import ZoneUtil
|
|
from toontown.safezone.OZPlayground import OZPlayground
|
|
from toontown.safezone.SafeZoneLoader import SafeZoneLoader
|
|
from toontown.toon import Toon, ToonDNA
|
|
|
|
|
|
class OZSafeZoneLoader(SafeZoneLoader):
|
|
def __init__(self, hood, parentFSM, doneEvent):
|
|
SafeZoneLoader.__init__(self, hood, parentFSM, doneEvent)
|
|
self.musicFile = 'phase_6/audio/bgm/OZ_SZ.ogg'
|
|
self.activityMusicFile = 'phase_6/audio/bgm/GS_KartShop.ogg'
|
|
self.dnaFile = 'phase_6/dna/outdoor_zone_sz.pdna'
|
|
self.safeZoneStorageDNAFile = 'phase_6/dna/storage_OZ_sz.pdna'
|
|
self.__toonTracks = {}
|
|
del self.fsm
|
|
self.fsm = ClassicFSM.ClassicFSM('SafeZoneLoader', [State.State('start', self.enterStart, self.exitStart, ['quietZone', 'playground', 'toonInterior']),
|
|
State.State('playground', self.enterPlayground, self.exitPlayground, ['quietZone', 'golfcourse']),
|
|
State.State('toonInterior', self.enterToonInterior, self.exitToonInterior, ['quietZone']),
|
|
State.State('quietZone', self.enterQuietZone, self.exitQuietZone, ['playground', 'toonInterior', 'golfcourse']),
|
|
State.State('golfcourse', self.enterGolfCourse, self.exitGolfCourse, ['quietZone', 'playground']),
|
|
State.State('final', self.enterFinal, self.exitFinal, ['start'])], 'start', 'final')
|
|
|
|
def load(self):
|
|
self.done = 0
|
|
self.geyserTrack = None
|
|
SafeZoneLoader.load(self)
|
|
self.birdSound = map(base.loadSfx, ['phase_4/audio/sfx/SZ_TC_bird1.ogg', 'phase_4/audio/sfx/SZ_TC_bird2.ogg', 'phase_4/audio/sfx/SZ_TC_bird3.ogg'])
|
|
self.underwaterSound = base.loadSfx('phase_4/audio/sfx/AV_ambient_water.ogg')
|
|
self.swimSound = base.loadSfx('phase_4/audio/sfx/AV_swim_single_stroke.ogg')
|
|
self.submergeSound = base.loadSfx('phase_5.5/audio/sfx/AV_jump_in_water.ogg')
|
|
geyserPlacer = self.geom.find('**/geyser*')
|
|
waterfallPlacer = self.geom.find('**/waterfall*')
|
|
binMgr = CullBinManager.getGlobalPtr()
|
|
binMgr.addBin('water', CullBinManager.BTFixed, 29)
|
|
pool = self.geom.find('**/pPlane5*')
|
|
pool.setTransparency(1)
|
|
pool.setColorScale(1.0, 1.0, 1.0, 1.0)
|
|
pool.setBin('water', 50, 1)
|
|
self.geyserModel = loader.loadModel('phase_6/models/golf/golf_geyser_model')
|
|
self.geyserSound = loader.loadSfx('phase_6/audio/sfx/OZ_Geyser.ogg')
|
|
self.geyserSoundInterval = SoundInterval(self.geyserSound, node=geyserPlacer, listenerNode=base.camera, seamlessLoop=False, volume=1.0, cutOff=120)
|
|
self.geyserSoundNoToon = loader.loadSfx('phase_6/audio/sfx/OZ_Geyser_No_Toon.ogg')
|
|
self.geyserSoundNoToonInterval = SoundInterval(self.geyserSoundNoToon, node=geyserPlacer, listenerNode=base.camera, seamlessLoop=False, volume=1.0, cutOff=120)
|
|
if self.geyserModel:
|
|
self.geyserActor = Actor.Actor(self.geyserModel)
|
|
self.geyserActor.loadAnims({'idle': 'phase_6/models/golf/golf_geyser'})
|
|
self.geyserActor.reparentTo(render)
|
|
self.geyserActor.setPlayRate(8.6, 'idle')
|
|
self.geyserActor.loop('idle')
|
|
self.geyserActor.setDepthWrite(0)
|
|
self.geyserActor.setTwoSided(True, 11)
|
|
self.geyserActor.setColorScale(1.0, 1.0, 1.0, 1.0)
|
|
self.geyserActor.setBin('fixed', 0)
|
|
mesh = self.geyserActor.find('**/mesh_tide1')
|
|
joint = self.geyserActor.find('**/uvj_WakeWhiteTide1')
|
|
mesh.setTexProjector(mesh.findTextureStage('default'), joint, self.geyserActor)
|
|
self.geyserActor.setPos(geyserPlacer.getPos())
|
|
self.geyserActor.setZ(geyserPlacer.getZ() - 100.0)
|
|
self.geyserPos = geyserPlacer.getPos()
|
|
self.geyserPlacer = geyserPlacer
|
|
self.startGeyser()
|
|
base.sfxPlayer.setCutoffDistance(160)
|
|
self.geyserPoolSfx = loader.loadSfx('phase_6/audio/sfx/OZ_Geyser_BuildUp_Loop.ogg')
|
|
self.geyserPoolSoundInterval = SoundInterval(self.geyserPoolSfx, node=self.geyserPlacer, listenerNode=base.camera, seamlessLoop=True, volume=1.0, cutOff=120)
|
|
self.geyserPoolSoundInterval.loop()
|
|
self.bubbles = Bubbles.Bubbles(self.geyserPlacer, render)
|
|
self.bubbles.renderParent.setDepthWrite(0)
|
|
self.bubbles.start()
|
|
self.collBase = render.attachNewNode('collisionBase')
|
|
self.geyserCollSphere = CollisionSphere(0, 0, 0, 7.5)
|
|
self.geyserCollSphere.setTangible(1)
|
|
self.geyserCollNode = CollisionNode('barrelSphere')
|
|
self.geyserCollNode.setIntoCollideMask(OTPGlobals.WallBitmask)
|
|
self.geyserCollNode.addSolid(self.geyserCollSphere)
|
|
self.geyserNodePath = self.collBase.attachNewNode(self.geyserCollNode)
|
|
self.geyserNodePath.setPos(self.geyserPos[0], self.geyserPos[1], self.geyserPos[2] - 100.0)
|
|
self.waterfallModel = loader.loadModel('phase_6/models/golf/golf_waterfall_model')
|
|
if self.waterfallModel:
|
|
self.waterfallActor = Actor.Actor(self.waterfallModel)
|
|
self.waterfallActor.loadAnims({'idle': 'phase_6/models/golf/golf_waterfall'})
|
|
self.waterfallActor.reparentTo(render)
|
|
self.waterfallActor.setPlayRate(3.5, 'idle')
|
|
self.waterfallActor.loop('idle')
|
|
mesh = self.waterfallActor.find('**/mesh_tide1')
|
|
joint = self.waterfallActor.find('**/uvj_WakeWhiteTide1')
|
|
mesh.setTexProjector(mesh.findTextureStage('default'), joint, self.waterfallActor)
|
|
self.waterfallActor.setPos(waterfallPlacer.getPos())
|
|
self.accept('clientLogout', self._handleLogout)
|
|
|
|
def exit(self):
|
|
self.clearToonTracks()
|
|
SafeZoneLoader.exit(self)
|
|
self.ignore('clientLogout')
|
|
|
|
def startGeyser(self, task = None):
|
|
if hasattr(base.cr, 'DTimer') and base.cr.DTimer:
|
|
self.geyserCycleTime = 20.0
|
|
useTime = base.cr.DTimer.getTime()
|
|
timeToNextGeyser = 20.0 - useTime % 20.0
|
|
taskMgr.doMethodLater(timeToNextGeyser, self.doGeyser, 'geyser Task')
|
|
else:
|
|
taskMgr.doMethodLater(5.0, self.startGeyser, 'start geyser Task')
|
|
|
|
def doGeyser(self, task = None):
|
|
if not self.done:
|
|
self.setGeyserAnim()
|
|
useTime = base.cr.DTimer.getTime()
|
|
timeToNextGeyser = 20.0 - useTime % 20.0
|
|
taskMgr.doMethodLater(timeToNextGeyser, self.doGeyser, 'geyser Task')
|
|
return task.done
|
|
|
|
def restoreLocal(self, task = None):
|
|
place = base.cr.playGame.getPlace()
|
|
if place:
|
|
place.fsm.request('walk')
|
|
base.localAvatar.setTeleportAvailable(1)
|
|
base.localAvatar.collisionsOn()
|
|
base.localAvatar.dropShadow.show()
|
|
|
|
def restoreRemote(self, remoteAv, task = None):
|
|
if remoteAv in Avatar.Avatar.ActiveAvatars:
|
|
remoteAv.startSmooth()
|
|
remoteAv.dropShadow.show()
|
|
|
|
def setGeyserAnim(self, task = None):
|
|
if self.done:
|
|
return
|
|
maxSize = 0.4 * random.random() + 0.75
|
|
time = 1.0
|
|
self.geyserTrack = Sequence()
|
|
upPos = Vec3(self.geyserPos[0], self.geyserPos[1], self.geyserPos[2])
|
|
downPos = Vec3(self.geyserPos[0], self.geyserPos[1], self.geyserPos[2] - 8.0)
|
|
avList = copy.copy(Avatar.Avatar.ActiveAvatars)
|
|
avList.append(base.localAvatar)
|
|
playSound = 0
|
|
for av in avList:
|
|
distance = self.geyserPlacer.getDistance(av)
|
|
if distance < 7.0:
|
|
place = base.cr.playGame.getPlace()
|
|
local = 0
|
|
avPos = av.getPos()
|
|
upToon = Vec3(avPos[0], avPos[1], maxSize * self.geyserPos[2] + 40.0)
|
|
midToon = Vec3(avPos[0], avPos[1], maxSize * self.geyserPos[2] + 30.0)
|
|
downToon = Vec3(avPos[0], avPos[1], self.geyserPos[2])
|
|
returnPoints = [(7, 7),
|
|
(8, 0),
|
|
(-8, 3),
|
|
(-7, 7),
|
|
(3, -7),
|
|
(0, 8),
|
|
(-10, 0),
|
|
(8, -3),
|
|
(5, 8),
|
|
(-8, 5),
|
|
(-1, 7)]
|
|
pick = int((float(av.doId) - 11.0) / 13.0 % len(returnPoints))
|
|
returnChoice = returnPoints[pick]
|
|
toonReturn = Vec3(self.geyserPos[0] + returnChoice[0], self.geyserPos[1] + returnChoice[1], self.geyserPos[2] - 1.5)
|
|
topTrack = Sequence()
|
|
av.dropShadow.hide()
|
|
playSound = 1
|
|
if av == base.localAvatar:
|
|
base.cr.playGame.getPlace().setState('fishing')
|
|
base.localAvatar.setTeleportAvailable(0)
|
|
base.localAvatar.collisionsOff()
|
|
local = 1
|
|
else:
|
|
topTrack.delayDeletes = [DelayDelete.DelayDelete(av, 'OZSafeZoneLoader.setGeyserAnim')]
|
|
av.stopSmooth()
|
|
animTrack = Parallel()
|
|
toonTrack = Sequence()
|
|
toonTrack.append(Wait(0.5))
|
|
animTrack.append(ActorInterval(av, 'jump-idle', loop=1, endTime=11.5 * time))
|
|
animTrack.append(ActorInterval(av, 'neutral', loop=0, endTime=0.25 * time))
|
|
holder = render.attachNewNode('toon hold')
|
|
base.holder = holder
|
|
toonPos = av.getPos(render)
|
|
toonHpr = av.getHpr(render)
|
|
print 'av Pos %s' % av.getPos()
|
|
base.toonPos = toonPos
|
|
holder.setPos(toonPos)
|
|
av.reparentTo(holder)
|
|
av.setPos(0, 0, 0)
|
|
lookAt = 180
|
|
toonH = (lookAt + toonHpr[0]) % 360
|
|
newHpr = Vec3(toonH, toonHpr[1], toonHpr[2])
|
|
if toonH < 180:
|
|
lookIn = Vec3(0 + lookAt, -30, 0)
|
|
else:
|
|
lookIn = Vec3(360 + lookAt, -30, 0)
|
|
print 'Camera Hprs toon %s; lookIn %s; final %s' % (newHpr, lookIn, lookIn - newHpr)
|
|
if local == 1:
|
|
camPosOriginal = camera.getPos()
|
|
camHprOriginal = camera.getHpr()
|
|
camParentOriginal = camera.getParent()
|
|
cameraPivot = holder.attachNewNode('camera pivot')
|
|
chooseHeading = random.choice([-10.0, 15.0, 40.0])
|
|
cameraPivot.setHpr(chooseHeading, -20.0, 0.0)
|
|
cameraArm = cameraPivot.attachNewNode('camera arm')
|
|
cameraArm.setPos(0.0, -23.0, 3.0)
|
|
camPosStart = Point3(0.0, 0.0, 0.0)
|
|
camHprStart = Vec3(0.0, 0.0, 0.0)
|
|
self.changeCamera(cameraArm, camPosStart, camHprStart)
|
|
cameraTrack = Sequence()
|
|
cameraTrack.append(Wait(11.0 * time))
|
|
cameraTrack.append(Func(self.changeCamera, camParentOriginal, camPosOriginal, camHprOriginal))
|
|
cameraTrack.start()
|
|
moveTrack = Sequence()
|
|
moveTrack.append(Wait(0.5))
|
|
moveTrack.append(LerpPosInterval(holder, 3.0 * time, pos=upToon, startPos=downToon, blendType='easeOut'))
|
|
moveTrack.append(LerpPosInterval(holder, 2.0 * time, pos=midToon, startPos=upToon, blendType='easeInOut'))
|
|
moveTrack.append(LerpPosInterval(holder, 1.0 * time, pos=upToon, startPos=midToon, blendType='easeInOut'))
|
|
moveTrack.append(LerpPosInterval(holder, 2.0 * time, pos=midToon, startPos=upToon, blendType='easeInOut'))
|
|
moveTrack.append(LerpPosInterval(holder, 1.0 * time, pos=upToon, startPos=midToon, blendType='easeInOut'))
|
|
moveTrack.append(LerpPosInterval(holder, 2.5 * time, pos=toonReturn, startPos=upToon, blendType='easeIn'))
|
|
animTrack.append(moveTrack)
|
|
animTrack.append(toonTrack)
|
|
topTrack.append(animTrack)
|
|
topTrack.append(Func(av.setPos, toonReturn))
|
|
topTrack.append(Func(av.reparentTo, render))
|
|
topTrack.append(Func(holder.remove))
|
|
if local == 1:
|
|
topTrack.append(Func(self.restoreLocal))
|
|
else:
|
|
topTrack.append(Func(self.restoreRemote, av))
|
|
topTrack.append(Func(self.clearToonTrack, av.doId))
|
|
self.storeToonTrack(av.doId, topTrack)
|
|
topTrack.start()
|
|
|
|
self.geyserTrack.append(Func(self.doPrint, 'geyser start'))
|
|
self.geyserTrack.append(Func(self.geyserNodePath.setPos, self.geyserPos[0], self.geyserPos[1], self.geyserPos[2]))
|
|
self.geyserTrack.append(Parallel(LerpScaleInterval(self.geyserActor, 2.0 * time, 0.75, 0.01), LerpPosInterval(self.geyserActor, 2.0 * time, pos=downPos, startPos=downPos)))
|
|
self.geyserTrack.append(Parallel(LerpScaleInterval(self.geyserActor, time, maxSize, 0.75), LerpPosInterval(self.geyserActor, time, pos=upPos, startPos=downPos)))
|
|
self.geyserTrack.append(Parallel(LerpScaleInterval(self.geyserActor, 2.0 * time, 0.75, maxSize), LerpPosInterval(self.geyserActor, 2.0 * time, pos=downPos, startPos=upPos)))
|
|
self.geyserTrack.append(Parallel(LerpScaleInterval(self.geyserActor, time, maxSize, 0.75), LerpPosInterval(self.geyserActor, time, pos=upPos, startPos=downPos)))
|
|
self.geyserTrack.append(Parallel(LerpScaleInterval(self.geyserActor, 2.0 * time, 0.75, maxSize), LerpPosInterval(self.geyserActor, 2.0 * time, pos=downPos, startPos=upPos)))
|
|
self.geyserTrack.append(Parallel(LerpScaleInterval(self.geyserActor, time, maxSize, 0.75), LerpPosInterval(self.geyserActor, time, pos=upPos, startPos=downPos)))
|
|
self.geyserTrack.append(Parallel(LerpScaleInterval(self.geyserActor, 4.0 * time, 0.01, maxSize), LerpPosInterval(self.geyserActor, 4.0 * time, pos=downPos, startPos=upPos)))
|
|
self.geyserTrack.append(Func(self.geyserNodePath.setPos, self.geyserPos[0], self.geyserPos[1], self.geyserPos[2] - 100.0))
|
|
self.geyserTrack.append(Func(self.doPrint, 'geyser end'))
|
|
self.geyserTrack.start()
|
|
if playSound:
|
|
self.geyserSoundInterval.start()
|
|
else:
|
|
self.geyserSoundNoToonInterval.start()
|
|
|
|
def changeCamera(self, newParent, newPos, newHpr):
|
|
camera.reparentTo(newParent)
|
|
camera.setPosHpr(newPos, newHpr)
|
|
|
|
def doPrint(self, thing):
|
|
return 0
|
|
print thing
|
|
|
|
def unload(self):
|
|
del self.birdSound
|
|
SafeZoneLoader.unload(self)
|
|
self.done = 1
|
|
self.collBase.removeNode()
|
|
if self.geyserTrack:
|
|
self.geyserTrack.finish()
|
|
self.geyserTrack = None
|
|
self.geyserActor.cleanup()
|
|
self.geyserModel.removeNode()
|
|
self.waterfallActor.cleanup()
|
|
self.waterfallModel.removeNode()
|
|
self.bubbles.destroy()
|
|
del self.bubbles
|
|
self.geyserPoolSoundInterval.finish()
|
|
self.geyserPoolSfx.stop()
|
|
self.geyserPoolSfx = None
|
|
self.geyserPoolSoundInterval = None
|
|
self.geyserSoundInterval.finish()
|
|
self.geyserSound.stop()
|
|
self.geyserSoundInterval = None
|
|
self.geyserSound = None
|
|
self.geyserSoundNoToonInterval.finish()
|
|
self.geyserSoundNoToon.stop()
|
|
self.geyserSoundNoToonInterval = None
|
|
self.geyserSoundNoToon = None
|
|
|
|
def enterPlayground(self, requestStatus):
|
|
self.playgroundClass = OZPlayground
|
|
SafeZoneLoader.enterPlayground(self, requestStatus)
|
|
|
|
def exitPlayground(self):
|
|
taskMgr.remove('titleText')
|
|
self.hood.hideTitleText()
|
|
SafeZoneLoader.exitPlayground(self)
|
|
self.playgroundClass = None
|
|
return
|
|
|
|
def handlePlaygroundDone(self):
|
|
status = self.place.doneStatus
|
|
self.doneStatus = status
|
|
messenger.send(self.doneEvent)
|
|
|
|
def enteringARace(self, status):
|
|
if not status['where'] == 'golfcourse':
|
|
return 0
|
|
if ZoneUtil.isDynamicZone(status['zoneId']):
|
|
return status['hoodId'] == self.hood.hoodId
|
|
else:
|
|
return ZoneUtil.getHoodId(status['zoneId']) == self.hood.hoodId
|
|
|
|
def enteringAGolfCourse(self, status):
|
|
if not status['where'] == 'golfcourse':
|
|
return 0
|
|
if ZoneUtil.isDynamicZone(status['zoneId']):
|
|
return status['hoodId'] == self.hood.hoodId
|
|
else:
|
|
return ZoneUtil.getHoodId(status['zoneId']) == self.hood.hoodId
|
|
|
|
def enterGolfCourse(self, requestStatus):
|
|
if 'curseId' in requestStatus:
|
|
self.golfCourseId = requestStatus['courseId']
|
|
else:
|
|
self.golfCourseId = 0
|
|
self.accept('raceOver', self.handleRaceOver)
|
|
self.accept('leavingGolf', self.handleLeftGolf)
|
|
base.transitions.irisOut(t=0.2)
|
|
|
|
def exitGolfCourse(self):
|
|
del self.golfCourseId
|
|
|
|
def handleRaceOver(self):
|
|
print 'you done!!'
|
|
|
|
def handleLeftGolf(self):
|
|
req = {'loader': 'safeZoneLoader',
|
|
'where': 'playground',
|
|
'how': 'teleportIn',
|
|
'zoneId': 6000,
|
|
'hoodId': 6000,
|
|
'shardId': None}
|
|
self.fsm.request('quietZone', [req])
|
|
return
|
|
|
|
def _handleLogout(self):
|
|
self.clearToonTracks()
|
|
|
|
def storeToonTrack(self, avId, track):
|
|
self.clearToonTrack(avId)
|
|
self.__toonTracks[avId] = track
|
|
|
|
def clearToonTrack(self, avId):
|
|
oldTrack = self.__toonTracks.get(avId)
|
|
if oldTrack:
|
|
oldTrack.pause()
|
|
DelayDelete.cleanupDelayDeletes(oldTrack)
|
|
del self.__toonTracks[avId]
|
|
|
|
def clearToonTracks(self):
|
|
keyList = []
|
|
for key in self.__toonTracks:
|
|
keyList.append(key)
|
|
|
|
for key in keyList:
|
|
if key in self.__toonTracks:
|
|
self.clearToonTrack(key)
|