toontown-just-works/toontown/estate/DistributedLawnDecor.py
2024-07-07 18:08:39 -05:00

376 lines
14 KiB
Python

from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.distributed import ClockDelta
from direct.showbase.PythonUtil import lerp
import math
from direct.directnotify import DirectNotifyGlobal
from pandac.PandaModules import NodePath
from direct.task import Task
from toontown.toonbase import ToontownGlobals
from direct.distributed import DistributedObject
from direct.distributed import DistributedNode
from direct.showbase import PythonUtil
from otp.avatar import ShadowCaster
import random
from otp.otpbase import OTPGlobals
from toontown.estate import GardenGlobals
def recurseParent(intoNode, ParentName):
# funny fact: cogtown had a func like this
parent = intoNode.getParent(0)
if not parent or parent.getName() == 'render':
return 0
elif parent.getName() == ParentName:
return 1
else:
return recurseParent(parent, ParentName)
class DistributedLawnDecor(DistributedNode.DistributedNode, NodePath, ShadowCaster.ShadowCaster):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLawnDecor')
def __init__(self, cr):
DistributedNode.DistributedNode.__init__(self, cr)
NodePath.__init__(self, 'decor')
ShadowCaster.ShadowCaster.__init__(self, False)
self.plantPath = NodePath('plantPath')
self.plantPath.reparentTo(self)
self.defaultModel = 'phase_9/models/cogHQ/woodCrateB'
self.messageName = None
self.model = None
self.colSphereNode = None
self.rotateNode = None
self.collSphereOffset = 0.0
self.collSphereRadius = 1.0
self.stickUp = 0.0
self.movieNode = None
self.shadowJoint = None
self.shadowScale = 1
self.expectingReplacement = 0
self.movie = None
return
def setHeading(self, h):
self.notify.debug('setting h')
DistributedNode.DistributedNode.setH(self, h)
def generateInit(self):
self.notify.debug('generateInit')
DistributedNode.DistributedNode.generateInit(self)
def generate(self):
self.notify.debug('generate')
self.reparentTo(render)
DistributedNode.DistributedNode.generate(self)
def announceGenerate(self):
self.notify.debug('announceGenerate')
DistributedNode.DistributedNode.announceGenerate(self)
self.doModelSetup()
self.loadModel()
self.setupShadow()
self.makeMovieNode()
self.stick2Ground()
self.setupCollision()
def doModelSetup(self):
pass
def disable(self):
self.notify.debug('disable')
self.finishMovies()
self.handleExitPlot()
self.ignoreAll()
DistributedNode.DistributedNode.disable(self)
if hasattr(self, 'nodePath'):
self.nodePath.detachNode()
def delete(self):
self.notify.debug('delete')
ShadowCaster.ShadowCaster.delete(self)
self.unloadModel()
DistributedNode.DistributedNode.delete(self)
def loadModel(self):
if not self.rotateNode:
self.rotateNode = self.plantPath.attachNewNode('rotate')
self.model = None
if __dev__:
self.model = loader.loadModel(self.defaultModel)
self.model.setScale(0.4, 0.4, 0.1)
self.model.reparentTo(self.rotateNode)
return
def setupShadow(self):
self.shadowJoint = self.rotateNode.attachNewNode('shadow')
self.initializeDropShadow(False)
self.shadowJoint.setScale(self.shadowScale)
self.setActiveShadow()
def makeMovieNode(self):
self.movieNode = self.rotateNode.attachNewNode('moviePos')
self.movieNode.setPos(0, -3, 0)
def setupCollision(self):
self.messageName = self.uniqueName('enterplotSphere')
self.messageStartName = self.uniqueName('plotSphere')
self.exitMessageName = self.uniqueName('exitplotSphere')
if self.collSphereOffset <= 0.1:
colSphere = CollisionSphere(0, 0, 0, self.collSphereRadius)
else:
colSphere = CollisionTube(0, -self.collSphereOffset, 0, 0, self.collSphereOffset, 0, self.collSphereRadius)
colSphere.setTangible(0)
colNode = CollisionNode(self.messageStartName)
colNode.addSolid(colSphere)
colSphereNode = self.attachNewNode(colNode)
self.colSphereNode = colSphereNode
self.accept(self.messageName, self.handleEnterPlot)
self.accept(self.exitMessageName, self.handleExitPlot)
def handleEnterPlot(self, optional = None):
self.notify.debug('handleEnterPlot %d' % self.doId)
self.sendUpdate('plotEntered', [])
def handleExitPlot(self, optional = None):
if base.localAvatar.inGardenAction == self:
base.localAvatar.handleEndPlantInteraction(self, replacement=self.expectingReplacement)
def handleWatering(self):
self.handleExitPlot()
base.localAvatar.removeShovelRelatedDoId(self.doId)
def unloadModel(self):
if self.model:
self.model.removeNode()
del self.model
self.model = None
if hasattr(self, 'nodePath') and self.nodePath:
self.nodePath.removeNode()
self.nodePath = None
taskMgr.remove(self.uniqueName('adjust tree'))
return
def setPos(self, x, y, z):
DistributedNode.DistributedNode.setPos(self, x, y, z)
self.stick2Ground()
def setPosition(self, x, y, z):
DistributedNode.DistributedNode.setPos(self, x, y, z)
self.stick2Ground()
def stick2Ground(self, taskfooler = 0):
if self.isEmpty():
return Task.done
testPath = NodePath('testPath')
testPath.reparentTo(render)
cRay = CollisionRay(0.0, 0.0, 40000.0, 0.0, 0.0, -1.0)
cRayNode = CollisionNode(self.uniqueName('estate-FloorRay'))
cRayNode.addSolid(cRay)
cRayNode.setFromCollideMask(OTPGlobals.FloorBitmask)
cRayNode.setIntoCollideMask(BitMask32.allOff())
cRayNodePath = testPath.attachNewNode(cRayNode)
queue = CollisionHandlerQueue()
picker = CollisionTraverser()
picker.addCollider(cRayNodePath, queue)
if self.movieNode:
testPath.setPos(self.movieNode.getX(render), self.movieNode.getY(render), 0)
picker.traverse(render)
if queue.getNumEntries() > 0:
queue.sortEntries()
for index in xrange(queue.getNumEntries()):
entry = queue.getEntry(index)
if recurseParent(entry.getIntoNode(), 'terrain_DNARoot'):
self.movieNode.setZ(entry.getSurfacePoint(self)[2])
testPath.setPos(self.getX(), self.getY(), 0)
picker.traverse(render)
if queue.getNumEntries() > 0:
queue.sortEntries()
for index in xrange(queue.getNumEntries()):
entry = queue.getEntry(index)
if recurseParent(entry.getIntoNode(), 'terrain_DNARoot'):
self.setZ(entry.getSurfacePoint(render)[2] + self.stickUp + 0.1)
self.stickParts()
return Task.done
taskMgr.doMethodLater(1.0, self.stick2Ground, uniqueName('groundsticker'))
return Task.done
def stickParts(self):
pass
def setPlot(self, plot):
self.plot = plot
def setH(self, h):
DistributedNode.DistributedNode.setH(self, h)
def getPlot(self):
return self.plot
def setOwnerIndex(self, index):
self.ownerIndex = index
def getOwnerIndex(self):
return self.ownerIndex
def getOwnerId(self):
retval = 0
estate = base.cr.doFind('DistributedEstate')
if estate and hasattr(estate, 'idList') and estate.idList:
if self.ownerIndex < len(estate.idList):
retval = estate.idList[self.ownerIndex]
return retval
def canBePicked(self):
retval = True
self.notify.debug('base.localAvatar.doId : %s' % base.localAvatar.doId)
self.notify.debug('self.getOwnerId : %s ' % self.getOwnerId())
self.notify.debug("statue's DoId : %s " % self.doId)
if not hasattr(base, 'localAvatar') or not base.localAvatar.doId == self.getOwnerId():
retval = False
return retval
def allowedToPick(self):
return True
def unlockPick(self):
return True
def handleRemove(self):
if not self.canBePicked():
self.notify.debug("I don't own this item, just returning")
return
base.localAvatar.hideShovelButton()
base.localAvatar.hideWateringCanButton()
self.startInteraction()
self.sendUpdate('removeItem', [])
def generateToonMoveTrack(self, toon):
node = NodePath('tempNode')
displacement = Vec3(toon.getPos(render) - self.getPos(render))
displacement.setZ(0)
displacement.normalize()
movieDistance = self.movieNode.getDistance(self.rotateNode)
displacement *= movieDistance
node.reparentTo(render)
node.setPos(displacement + self.getPos(render))
node.lookAt(self)
heading = PythonUtil.fitDestAngle2Src(toon.getH(render), node.getH(render))
hpr = toon.getHpr(render)
hpr.setX(heading)
finalX = node.getX(render)
finalY = node.getY(render)
finalZ = node.getZ(render)
node.removeNode()
toonTrack = Sequence(Parallel(ActorInterval(toon, 'walk', loop=True, duration=1), Parallel(LerpPosInterval(toon, 1.0, Point3(finalX, finalY, toon.getZ(render)), fluid=True, bakeInStart=False)), LerpHprInterval(toon, 1.0, hpr=hpr)), Func(toon.loop, 'neutral'))
return toonTrack
def unprint(self, string):
print string
def startInteraction(self):
place = base.cr.playGame.getPlace()
if place:
place.detectedGardenPlotUse()
base.localAvatar.setInGardenAction(self)
def finishInteraction(self):
if hasattr(base.cr.playGame.getPlace(), 'detectedGardenPlotDone'):
base.cr.playGame.getPlace().detectedGardenPlotDone()
self.notify.debug('done interaction')
else:
self.notify.warning('base.cr.playGame.getPlace() does not have detectedGardenPlotDone')
if hasattr(base, 'localAvatar'):
base.localAvatar.handleEndPlantInteraction(self)
def startCamIval(self, avId):
track = Sequence()
if avId == localAvatar.doId:
track = Sequence(Func(base.localAvatar.disableSmartCameraViews), Func(base.localAvatar.setCameraPosForPetInteraction))
return track
def stopCamIval(self, avId):
track = Sequence()
if avId == localAvatar.doId:
track = Sequence(Func(base.localAvatar.unsetCameraPosForPetInteraction), Wait(0.8), Func(base.localAvatar.enableSmartCameraViews))
return track
def canBeWatered(self):
return 0
def getShovelAction(self):
return None
def getShovelCommand(self):
return None
def canBePlanted(self):
return 0
def movieDone(self):
self.sendUpdate('movieDone', [])
def setMovie(self, mode, avId):
if mode == GardenGlobals.MOVIE_FINISHPLANTING:
self.doFinishPlantingTrack(avId)
elif mode == GardenGlobals.MOVIE_REMOVE:
self.doDigupTrack(avId)
def finishMovies(self):
if self.movie:
self.movie.finish()
self.movie = None
return
def doDigupTrack(self, avId):
toon = base.cr.doId2do.get(avId)
if not toon:
return
self.finishMovies()
self.model.setTransparency(1)
self.model.setAlphaScale(1)
shovel = toon.attachShovel()
shovel.hide()
moveTrack = self.generateToonMoveTrack(toon)
digupTrack = self.generateDigupTrack(toon)
self.movie = Sequence(self.startCamIval(avId), moveTrack, Func(shovel.show), digupTrack)
if avId == localAvatar.doId:
# self.expectingReplacement = 1
self.movie.append(Func(self.movieDone))
self.movie.start()
def generateDigupTrack(self, toon):
sound = loader.loadSfx('phase_5.5/audio/sfx/burrow.ogg')
sound.setPlayRate(0.5)
pos = self.model.getPos()
pos.setZ(pos[2] - 1)
track = Parallel()
track.append(Sequence(ActorInterval(toon, 'start-dig'), Parallel(ActorInterval(toon, 'loop-dig', loop=1, duration=5.13), Sequence(Wait(0.25), SoundInterval(sound, node=toon, duration=0.55), Wait(0.8), SoundInterval(sound, node=toon, duration=0.55), Wait(1.35), SoundInterval(sound, node=toon, duration=0.55))), ActorInterval(toon, 'start-dig', playRate=-1), LerpFunc(self.model.setAlphaScale, fromData=1, toData=0, duration=1), Func(toon.loop, 'neutral'), Func(toon.detachShovel)))
return track
def doFinishPlantingTrack(self, avId):
toon = base.cr.doId2do.get(avId)
if not toon:
return
self.finishMovies()
self.movie = Sequence()
if avId == localAvatar.doId:
self.startInteraction()
if self.model:
self.model.setTransparency(1)
self.model.setAlphaScale(0)
self.movie.append(LerpFunc(self.model.setAlphaScale, fromData=0, toData=1, duration=3))
self.movie.append(self.stopCamIval(avId))
self.movie.append(Func(toon.detachShovel))
self.movie.append(Func(toon.loop, 'neutral'))
if avId == localAvatar.doId:
self.movie.append(Func(self.finishInteraction))
self.movie.append(Func(self.movieDone))
if hasattr(self, 'doResultDialog'):
self.movie.append(Func(self.doResultDialog))
self.movie.start()
def interactionDenied(self, avId):
if avId == localAvatar.doId:
self.finishInteraction()