Poodletooth-iLand/toontown/safezone/DistributedGolfKart.py

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()