mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-23 03:35:12 -06:00
481 lines
19 KiB
Python
481 lines
19 KiB
Python
from panda3d.core import *
|
|
from direct.distributed.ClockDelta import *
|
|
from direct.task.Task import Task
|
|
from direct.interval.IntervalGlobal import *
|
|
from TrolleyConstants import *
|
|
from toontown.golf import GolfGlobals
|
|
from toontown.toonbase import ToontownGlobals
|
|
from direct.distributed import DistributedObject
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.fsm import ClassicFSM, State
|
|
from direct.fsm import State
|
|
from toontown.distributed import DelayDelete
|
|
from direct.task.Task import Task
|
|
from direct.showbase import PythonUtil
|
|
from toontown.toon import ToonDNA
|
|
from toontown.hood import ZoneUtil
|
|
|
|
class DistributedGolfKart(DistributedObject.DistributedObject):
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGolfKart')
|
|
SeatOffsets = ((0.5, -0.5, 0),
|
|
(-0.5, -0.5, 0),
|
|
(0.5, 0.5, 0),
|
|
(-0.5, 0.5, 0))
|
|
JumpOutOffsets = ((3, 5, 0),
|
|
(1.5, 4, 0),
|
|
(-1.5, 4, 0),
|
|
(-3, 4, 0))
|
|
KART_ENTER_TIME = 400
|
|
|
|
def __init__(self, cr):
|
|
DistributedObject.DistributedObject.__init__(self, cr)
|
|
self.localToonOnBoard = 0
|
|
self.trolleyCountdownTime = base.config.GetFloat('trolley-countdown-time', TROLLEY_COUNTDOWN_TIME)
|
|
self.fsm = ClassicFSM.ClassicFSM('DistributedTrolley', [State.State('off', self.enterOff, self.exitOff, ['entering',
|
|
'waitEmpty',
|
|
'waitCountdown',
|
|
'leaving']),
|
|
State.State('entering', self.enterEntering, self.exitEntering, ['waitEmpty']),
|
|
State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty, ['waitCountdown']),
|
|
State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown, ['waitEmpty', 'leaving']),
|
|
State.State('leaving', self.enterLeaving, self.exitLeaving, ['entering'])], 'off', 'off')
|
|
self.fsm.enterInitialState()
|
|
self.trolleyAwaySfx = base.loadSfx('phase_4/audio/sfx/SZ_trolley_away.ogg')
|
|
self.trolleyBellSfx = base.loadSfx('phase_4/audio/sfx/SZ_trolley_bell.ogg')
|
|
self.__toonTracks = {}
|
|
self.avIds = [0,
|
|
0,
|
|
0,
|
|
0]
|
|
self.kartModelPath = 'phase_6/models/golf/golf_cart3.bam'
|
|
|
|
def generate(self):
|
|
DistributedObject.DistributedObject.generate(self)
|
|
self.loader = self.cr.playGame.hood.loader
|
|
if self.loader:
|
|
self.notify.debug('Loader has been loaded')
|
|
self.notify.debug(str(self.loader))
|
|
else:
|
|
self.notify.debug('Loader has not been loaded')
|
|
self.golfKart = render.attachNewNode('golfKartNode')
|
|
self.kart = loader.loadModel(self.kartModelPath)
|
|
self.kart.setPos(0, 0, 0)
|
|
self.kart.setScale(1)
|
|
self.kart.reparentTo(self.golfKart)
|
|
self.golfKart.reparentTo(self.loader.geom)
|
|
self.wheels = self.kart.findAllMatches('**/wheelNode*')
|
|
self.numWheels = self.wheels.getNumPaths()
|
|
trolleyExitBellInterval = SoundInterval(self.trolleyBellSfx, node=self.golfKart)
|
|
trolleyExitAwayInterval = SoundInterval(self.trolleyAwaySfx, node=self.golfKart)
|
|
|
|
def announceGenerate(self):
|
|
DistributedObject.DistributedObject.announceGenerate(self)
|
|
self.golfKartSphereNode = self.golfKart.attachNewNode(CollisionNode('golfkart_sphere_%d' % self.getDoId()))
|
|
self.golfKartSphereNode.node().addSolid(CollisionSphere(0, 0, 0, 2))
|
|
angle = self.startingHpr[0]
|
|
angle -= 90
|
|
radAngle = deg2Rad(angle)
|
|
unitVec = Vec3(math.cos(radAngle), math.sin(radAngle), 0)
|
|
unitVec *= 45.0
|
|
self.endPos = self.startingPos + unitVec
|
|
dist = Vec3(self.endPos - self.enteringPos).length()
|
|
wheelAngle = dist / (4.8 * 1.4 * math.pi) * 360
|
|
self.kartEnterAnimateInterval = Parallel(LerpHprInterval(self.wheels[0], 5.0, Vec3(self.wheels[0].getH(), wheelAngle, self.wheels[0].getR())), LerpHprInterval(self.wheels[1], 5.0, Vec3(self.wheels[1].getH(), wheelAngle, self.wheels[1].getR())), LerpHprInterval(self.wheels[2], 5.0, Vec3(self.wheels[2].getH(), wheelAngle, self.wheels[2].getR())), LerpHprInterval(self.wheels[3], 5.0, Vec3(self.wheels[3].getH(), wheelAngle, self.wheels[3].getR())), name='KartAnimate')
|
|
trolleyExitTrack1 = Parallel(LerpPosInterval(self.golfKart, 5.0, self.endPos), self.kartEnterAnimateInterval, name='KartExitTrack')
|
|
self.trolleyExitTrack = Sequence(trolleyExitTrack1, Func(self.hideSittingToons))
|
|
self.trolleyEnterTrack = Sequence(LerpPosInterval(self.golfKart, 5.0, self.startingPos, startPos=self.enteringPos))
|
|
|
|
def disable(self):
|
|
DistributedObject.DistributedObject.disable(self)
|
|
self.fsm.request('off')
|
|
self.clearToonTracks()
|
|
del self.wheels
|
|
del self.numWheels
|
|
del self.golfKartSphereNode
|
|
self.notify.debug('Deleted self loader ' + str(self.getDoId()))
|
|
del self.loader
|
|
self.golfKart.removeNode()
|
|
self.kart.removeNode()
|
|
del self.kart
|
|
del self.golfKart
|
|
self.trolleyEnterTrack.pause()
|
|
self.trolleyEnterTrack = None
|
|
del self.kartEnterAnimateInterval
|
|
del self.trolleyEnterTrack
|
|
self.trolleyExitTrack.pause()
|
|
self.trolleyExitTrack = None
|
|
del self.trolleyExitTrack
|
|
return
|
|
|
|
def delete(self):
|
|
self.notify.debug('Golf kart getting deleted: %s' % self.getDoId())
|
|
del self.trolleyAwaySfx
|
|
del self.trolleyBellSfx
|
|
DistributedObject.DistributedObject.delete(self)
|
|
del self.fsm
|
|
|
|
def setState(self, state, timestamp):
|
|
self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])
|
|
|
|
def handleEnterTrolleySphere(self, collEntry):
|
|
self.notify.debug('Entering Trolley Sphere....')
|
|
self.loader.place.detectedTrolleyCollision()
|
|
|
|
def handleEnterGolfKartSphere(self, collEntry):
|
|
self.notify.debug('Entering Golf Kart Sphere.... %s' % self.getDoId())
|
|
self.loader.place.detectedGolfKartCollision(self)
|
|
|
|
def handleEnterTrolley(self):
|
|
toon = base.localAvatar
|
|
self.sendUpdate('requestBoard', [])
|
|
|
|
def handleEnterGolfKart(self):
|
|
toon = base.localAvatar
|
|
self.sendUpdate('requestBoard', [])
|
|
|
|
def fillSlot0(self, avId):
|
|
self.fillSlot(0, avId)
|
|
|
|
def fillSlot1(self, avId):
|
|
self.fillSlot(1, avId)
|
|
|
|
def fillSlot2(self, avId):
|
|
self.fillSlot(2, avId)
|
|
|
|
def fillSlot3(self, avId):
|
|
self.fillSlot(3, avId)
|
|
|
|
def fillSlot(self, index, avId):
|
|
self.avIds[index] = avId
|
|
if avId == 0:
|
|
pass
|
|
else:
|
|
if avId == base.localAvatar.getDoId():
|
|
self.loader.place.trolley.fsm.request('boarding', [self.golfKart])
|
|
self.localToonOnBoard = 1
|
|
if avId == base.localAvatar.getDoId():
|
|
self.loader.place.trolley.fsm.request('boarded')
|
|
if avId in self.cr.doId2do:
|
|
toon = self.cr.doId2do[avId]
|
|
toon.stopSmooth()
|
|
toon.wrtReparentTo(self.golfKart)
|
|
sitStartDuration = toon.getDuration('sit-start')
|
|
jumpTrack = self.generateToonJumpTrack(toon, index)
|
|
track = Sequence(jumpTrack, Func(toon.setAnimState, 'Sit', 1.0), Func(self.clearToonTrack, avId), name=toon.uniqueName('fillTrolley'), autoPause=1)
|
|
track.delayDelete = DelayDelete.DelayDelete(toon, 'GolfKart.fillSlot')
|
|
self.storeToonTrack(avId, track)
|
|
track.start()
|
|
else:
|
|
self.notify.warning('toon: ' + str(avId) + " doesn't exist, and" + ' cannot board the trolley!')
|
|
|
|
def emptySlot0(self, avId, timestamp):
|
|
self.emptySlot(0, avId, timestamp)
|
|
|
|
def emptySlot1(self, avId, timestamp):
|
|
self.emptySlot(1, avId, timestamp)
|
|
|
|
def emptySlot2(self, avId, timestamp):
|
|
self.emptySlot(2, avId, timestamp)
|
|
|
|
def emptySlot3(self, avId, timestamp):
|
|
self.emptySlot(3, avId, timestamp)
|
|
|
|
def notifyToonOffTrolley(self, toon):
|
|
toon.setAnimState('neutral', 1.0)
|
|
if toon == base.localAvatar:
|
|
self.loader.place.trolley.handleOffTrolley()
|
|
self.localToonOnBoard = 0
|
|
else:
|
|
toon.startSmooth()
|
|
|
|
def emptySlot(self, index, avId, timestamp):
|
|
if avId == 0:
|
|
pass
|
|
else:
|
|
self.avIds[index] = 0
|
|
if avId in self.cr.doId2do:
|
|
toon = self.cr.doId2do[avId]
|
|
toon.stopSmooth()
|
|
sitStartDuration = toon.getDuration('sit-start')
|
|
jumpOutTrack = self.generateToonReverseJumpTrack(toon, index)
|
|
track = Sequence(jumpOutTrack, Func(self.notifyToonOffTrolley, toon), Func(self.clearToonTrack, avId), name=toon.uniqueName('emptyTrolley'), autoPause=1)
|
|
track.delayDelete = DelayDelete.DelayDelete(toon, 'GolfKart.emptySlot')
|
|
self.storeToonTrack(avId, track)
|
|
track.start()
|
|
if avId == base.localAvatar.getDoId():
|
|
self.loader.place.trolley.fsm.request('exiting')
|
|
else:
|
|
self.notify.warning('toon: ' + str(avId) + " doesn't exist, and" + ' cannot exit the trolley!')
|
|
|
|
def rejectBoard(self, avId):
|
|
self.loader.place.trolley.handleRejectBoard()
|
|
|
|
def setMinigameZone(self, zoneId, minigameId):
|
|
self.localToonOnBoard = 0
|
|
messenger.send('playMinigame', [zoneId, minigameId])
|
|
|
|
def setGolfZone(self, zoneId, courseId):
|
|
self.localToonOnBoard = 0
|
|
messenger.send('playGolf', [zoneId, courseId])
|
|
|
|
def __enableCollisions(self):
|
|
self.accept('entertrolley_sphere', self.handleEnterTrolleySphere)
|
|
self.accept('enterTrolleyOK', self.handleEnterTrolley)
|
|
self.accept('entergolfkart_sphere_%d' % self.getDoId(), self.handleEnterGolfKartSphere)
|
|
self.accept('enterGolfKartOK_%d' % self.getDoId(), self.handleEnterGolfKart)
|
|
self.golfKartSphereNode.setCollideMask(ToontownGlobals.WallBitmask)
|
|
|
|
def __disableCollisions(self):
|
|
self.ignore('entertrolley_sphere')
|
|
self.ignore('enterTrolleyOK')
|
|
self.ignore('entergolfkart_sphere_%d' % self.getDoId())
|
|
self.ignore('enterTrolleyOK_%d' % self.getDoId())
|
|
self.ignore('enterGolfKartOK_%d' % self.getDoId())
|
|
self.golfKartSphereNode.setCollideMask(BitMask32(0))
|
|
|
|
def enterOff(self):
|
|
return None
|
|
|
|
def exitOff(self):
|
|
return None
|
|
|
|
def enterEntering(self, ts):
|
|
self.trolleyEnterTrack.start(ts)
|
|
|
|
def exitEntering(self):
|
|
self.trolleyEnterTrack.finish()
|
|
|
|
def enterWaitEmpty(self, ts):
|
|
self.__enableCollisions()
|
|
|
|
def exitWaitEmpty(self):
|
|
self.__disableCollisions()
|
|
|
|
def enterWaitCountdown(self, ts):
|
|
self.__enableCollisions()
|
|
self.accept('trolleyExitButton', self.handleExitButton)
|
|
self.clockNode = TextNode('trolleyClock')
|
|
self.clockNode.setFont(ToontownGlobals.getSignFont())
|
|
self.clockNode.setAlign(TextNode.ACenter)
|
|
self.clockNode.setTextColor(0.9, 0.1, 0.1, 1)
|
|
self.clockNode.setText('10')
|
|
self.clock = self.golfKart.attachNewNode(self.clockNode)
|
|
self.clock.setBillboardAxis()
|
|
self.clock.setPosHprScale(0, -1, 7.0, -0.0, 0.0, 0.0, 2.0, 2.0, 2.0)
|
|
if ts < self.trolleyCountdownTime:
|
|
self.countdown(self.trolleyCountdownTime - ts)
|
|
|
|
def timerTask(self, task):
|
|
countdownTime = int(task.duration - task.time)
|
|
timeStr = str(countdownTime)
|
|
if self.clockNode.getText() != timeStr:
|
|
self.clockNode.setText(timeStr)
|
|
if task.time >= task.duration:
|
|
return Task.done
|
|
else:
|
|
return Task.cont
|
|
|
|
def countdown(self, duration):
|
|
countdownTask = Task(self.timerTask)
|
|
countdownTask.duration = duration
|
|
taskMgr.remove(self.uniqueName('golfKartTimerTask'))
|
|
return taskMgr.add(countdownTask, self.uniqueName('golfKartTimerTask'))
|
|
|
|
def handleExitButton(self):
|
|
self.sendUpdate('requestExit')
|
|
|
|
def exitWaitCountdown(self):
|
|
self.__disableCollisions()
|
|
self.ignore('trolleyExitButton')
|
|
taskMgr.remove(self.uniqueName('golfKartTimerTask'))
|
|
self.clock.removeNode()
|
|
del self.clock
|
|
del self.clockNode
|
|
|
|
def enterLeaving(self, ts):
|
|
self.trolleyExitTrack.start(ts)
|
|
if self.localToonOnBoard:
|
|
if hasattr(self.loader.place, 'trolley') and self.loader.place.trolley:
|
|
self.loader.place.trolley.fsm.request('trolleyLeaving')
|
|
|
|
def exitLeaving(self):
|
|
self.trolleyExitTrack.finish()
|
|
|
|
def getStareAtNodeAndOffset(self):
|
|
return (self.golfKart, Point3(0, 0, 4))
|
|
|
|
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()
|
|
if self.__toonTracks.get(avId):
|
|
DelayDelete.cleanupDelayDeletes(self.__toonTracks[avId])
|
|
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)
|
|
|
|
def setGolfCourse(self, golfCourse):
|
|
self.golfCourse = golfCourse
|
|
|
|
def setPosHpr(self, x, y, z, h, p, r):
|
|
self.startingPos = Vec3(x, y, z)
|
|
self.enteringPos = Vec3(x, y, z - 10)
|
|
self.startingHpr = Vec3(h, 0, 0)
|
|
self.golfKart.setPosHpr(x, y, z, h, 0, 0)
|
|
|
|
def setColor(self, r, g, b):
|
|
kartBody = self.kart.find('**/main_body')
|
|
kartBody.setColor(r / 255.0, g / 255.0, b / 255.0, 1)
|
|
cartBase = self.kart.find('**/cart_base*')
|
|
red = r / 255.0
|
|
green = g / 255.0
|
|
blue = b / 255.0
|
|
if red >= green and red > blue:
|
|
s = (red - blue) / float(red)
|
|
v = red
|
|
if green > blue:
|
|
h = (green - blue) / (red - blue)
|
|
else:
|
|
h = (green - blue) / (red - green)
|
|
elif green >= blue:
|
|
s = (green - blue) / float(green)
|
|
v = green
|
|
if red > blue:
|
|
h = 2 + (blue - red) / (green - blue)
|
|
else:
|
|
h = 2 + (blue - red) / (green - red)
|
|
else:
|
|
if red > green:
|
|
s = (blue - green) / blue
|
|
h = 4 + (red - green) / (blue - green)
|
|
else:
|
|
s = (blue - red) / blue
|
|
h = 4 + (red - green) / (blue - red)
|
|
v = blue
|
|
if h < 0:
|
|
h *= 60
|
|
h += 360
|
|
h /= 60
|
|
s /= 3
|
|
if s == 0:
|
|
red = green = blue = v
|
|
else:
|
|
i = int(h)
|
|
f = h - i
|
|
p = v * (1 - s)
|
|
q = v * (1 - s * f)
|
|
t = v * (1 - s * (1 - f))
|
|
if i == 0:
|
|
red = v
|
|
green = t
|
|
blue = p
|
|
elif i == 1:
|
|
red = q
|
|
green = v
|
|
blue = p
|
|
elif i == 2:
|
|
red = p
|
|
green = v
|
|
blue = t
|
|
elif i == 3:
|
|
red = p
|
|
green = q
|
|
blue = v
|
|
elif i == 4:
|
|
red = t
|
|
green = p
|
|
blue = v
|
|
elif i == 5:
|
|
red = v
|
|
green = p
|
|
blue = q
|
|
cartBase.setColorScale(red, green, blue, 1)
|
|
|
|
def generateToonJumpTrack(self, av, seatIndex):
|
|
av.pose('sit', 47)
|
|
hipOffset = av.getHipsParts()[2].getPos(av)
|
|
|
|
def getToonJumpTrack(av, seatIndex):
|
|
|
|
def getJumpDest(av = av, node = self.golfKart):
|
|
dest = Point3(0, 0, 0)
|
|
if hasattr(self, 'golfKart') and self.golfKart:
|
|
dest = Vec3(self.golfKart.getPos(av.getParent()))
|
|
seatNode = self.golfKart.find('**/seat' + str(seatIndex + 1))
|
|
dest += seatNode.getPos(self.golfKart)
|
|
dna = av.getStyle()
|
|
dest -= hipOffset
|
|
if seatIndex < 2:
|
|
dest.setY(dest.getY() + 2 * hipOffset.getY())
|
|
dest.setZ(dest.getZ() + 0.1)
|
|
else:
|
|
self.notify.warning('getJumpDestinvalid golfKart, returning (0,0,0)')
|
|
return dest
|
|
|
|
def getJumpHpr(av = av, node = self.golfKart):
|
|
hpr = Point3(0, 0, 0)
|
|
if hasattr(self, 'golfKart') and self.golfKart:
|
|
hpr = self.golfKart.getHpr(av.getParent())
|
|
if seatIndex < 2:
|
|
hpr.setX(hpr.getX() + 180)
|
|
else:
|
|
hpr.setX(hpr.getX())
|
|
angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX())
|
|
hpr.setX(angle)
|
|
else:
|
|
self.notify.warning('getJumpHpr invalid golfKart, returning (0,0,0)')
|
|
return hpr
|
|
|
|
toonJumpTrack = Parallel(ActorInterval(av, 'jump'), Sequence(Wait(0.43), Parallel(LerpHprInterval(av, hpr=getJumpHpr, duration=0.9), ProjectileInterval(av, endPos=getJumpDest, duration=0.9))))
|
|
return toonJumpTrack
|
|
|
|
def getToonSitTrack(av):
|
|
toonSitTrack = Sequence(ActorInterval(av, 'sit-start'), Func(av.loop, 'sit'))
|
|
return toonSitTrack
|
|
|
|
toonJumpTrack = getToonJumpTrack(av, seatIndex)
|
|
toonSitTrack = getToonSitTrack(av)
|
|
jumpTrack = Sequence(Parallel(toonJumpTrack, Sequence(Wait(1), toonSitTrack)), Func(av.wrtReparentTo, self.golfKart))
|
|
return jumpTrack
|
|
|
|
def generateToonReverseJumpTrack(self, av, seatIndex):
|
|
self.notify.debug('av.getH() = %s' % av.getH())
|
|
|
|
def getToonJumpTrack(av, destNode):
|
|
|
|
def getJumpDest(av = av, node = destNode):
|
|
dest = node.getPos(av.getParent())
|
|
dest += Vec3(*self.JumpOutOffsets[seatIndex])
|
|
return dest
|
|
|
|
def getJumpHpr(av = av, node = destNode):
|
|
hpr = node.getHpr(av.getParent())
|
|
hpr.setX(hpr.getX() + 180)
|
|
angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX())
|
|
hpr.setX(angle)
|
|
return hpr
|
|
|
|
toonJumpTrack = Parallel(ActorInterval(av, 'jump'), Sequence(Wait(0.1), Parallel(ProjectileInterval(av, endPos=getJumpDest, duration=0.9))))
|
|
return toonJumpTrack
|
|
|
|
toonJumpTrack = getToonJumpTrack(av, self.golfKart)
|
|
jumpTrack = Sequence(toonJumpTrack, Func(av.loop, 'neutral'), Func(av.wrtReparentTo, render))
|
|
return jumpTrack
|
|
|
|
def hideSittingToons(self):
|
|
for avId in self.avIds:
|
|
if avId:
|
|
av = base.cr.doId2do.get(avId)
|
|
if av:
|
|
av.hide()
|