1669 lines
70 KiB
Python
1669 lines
70 KiB
Python
import math
|
|
import random
|
|
import time
|
|
from pandac.PandaModules import TextNode, BitMask32, Point3, Vec3, Vec4, deg2Rad, Mat3, NodePath, VBase4, OdeTriMeshData, OdeTriMeshGeom, OdeRayGeom, CollisionTraverser, CollisionSegment, CollisionNode, CollisionHandlerQueue
|
|
from direct.distributed import DistributedObject
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from otp.otpbase import OTPGlobals
|
|
from toontown.toonbase import ToontownGlobals
|
|
from toontown.toonbase import TTLocalizer
|
|
from toontown.toonbase import ToontownTimer
|
|
from direct.gui.DirectGui import DirectWaitBar, DGG, DirectLabel
|
|
from direct.task import Task
|
|
from direct.fsm.FSM import FSM
|
|
from toontown.minigame import ArrowKeys
|
|
from direct.showbase import PythonUtil
|
|
from toontown.golf import BuildGeometry
|
|
from toontown.golf import DistributedPhysicsWorld
|
|
from toontown.golf import GolfGlobals
|
|
from direct.interval.IntervalGlobal import Sequence, Parallel, LerpScaleInterval, LerpFunctionInterval, Func, Wait, SoundInterval, ParallelEndTogether, LerpPosInterval, ActorInterval, LerpPosHprInterval, LerpColorScaleInterval, WaitInterval
|
|
from direct.actor import Actor
|
|
from toontown.golf import GolfHoleBase
|
|
from toontown.distributed import DelayDelete
|
|
|
|
class DistributedGolfHole(DistributedPhysicsWorld.DistributedPhysicsWorld, FSM, GolfHoleBase.GolfHoleBase):
|
|
defaultTransitions = {'Off': ['Cleanup', 'ChooseTee', 'WatchTee'],
|
|
'ChooseTee': ['Aim', 'Cleanup'],
|
|
'WatchTee': ['WatchAim',
|
|
'Cleanup',
|
|
'WatchTee',
|
|
'ChooseTee',
|
|
'Aim'],
|
|
'Wait': ['Aim',
|
|
'WatchAim',
|
|
'Playback',
|
|
'Cleanup',
|
|
'ChooseTee',
|
|
'WatchTee'],
|
|
'Aim': ['Shoot',
|
|
'Playback',
|
|
'Cleanup',
|
|
'Aim',
|
|
'WatchAim'],
|
|
'WatchAim': ['WatchAim',
|
|
'WatchShoot',
|
|
'Playback',
|
|
'Cleanup',
|
|
'Aim',
|
|
'ChooseTee',
|
|
'WatchTee'],
|
|
'Playback': ['Wait',
|
|
'Aim',
|
|
'WatchAim',
|
|
'Cleanup',
|
|
'ChooseTee',
|
|
'WatchTee'],
|
|
'Cleanup': ['Off']}
|
|
id = 0
|
|
notify = directNotify.newCategory('DistributedGolfHole')
|
|
unlimitedAimTime = base.config.GetBool('unlimited-aim-time', 0)
|
|
unlimitedTeeTime = base.config.GetBool('unlimited-tee-time', 0)
|
|
golfPowerSpeed = base.config.GetDouble('golf-power-speed', 3)
|
|
golfPowerExponent = base.config.GetDouble('golf-power-exponent', 0.75)
|
|
DefaultCamP = -16
|
|
MaxCamP = -90
|
|
|
|
def __init__(self, cr):
|
|
self.notify.debug('Hole Init')
|
|
DistributedPhysicsWorld.DistributedPhysicsWorld.__init__(self, base.cr)
|
|
GolfHoleBase.GolfHoleBase.__init__(self, 1)
|
|
FSM.__init__(self, 'Golf_%s_FSM' % self.id)
|
|
self.currentGolfer = 0
|
|
self.ballDict = {}
|
|
self.ballShadowDict = {}
|
|
self.holeNodes = []
|
|
self.golfCourse = None
|
|
self.golfCourseRequest = None
|
|
self.holePositions = []
|
|
self.timer = None
|
|
self.teeTimer = None
|
|
self.aimStart = None
|
|
self.titleLabel = None
|
|
self.teeInstructions = None
|
|
self.aimInstructions = None
|
|
self.powerReminder = None
|
|
self.lastTimeHeadingSent = 0
|
|
self.lastTempHeadingSent = 0
|
|
self.holdCycleTime = 0.0
|
|
self.inPlayBack = 0
|
|
self.swingInterval = None
|
|
self.sfxInterval = None
|
|
self.isLookingAtPutt = False
|
|
self.clubs = {}
|
|
self.camInterval = None
|
|
self.flyOverInterval = None
|
|
self.needToDoFlyOver = True
|
|
self.translucentLastFrame = []
|
|
self.translucentCurFrame = []
|
|
self.localMissedSwings = 0
|
|
self.localToonHitControl = False
|
|
self.warningInterval = None
|
|
self.playBackDelayDelete = None
|
|
self.aimMomentum = 0.0
|
|
self.lastBumpSfxPos = Point3(0, 0, 0)
|
|
self.__textGen = TextNode('golfHoleText')
|
|
self.__textGen.setFont(ToontownGlobals.getSignFont())
|
|
self.__textGen.setAlign(TextNode.ACenter)
|
|
if TTLocalizer.getLanguage() in ['Castillian',
|
|
'Japanese',
|
|
'German',
|
|
'Portuguese',
|
|
'French']:
|
|
self.__textGen.setGlyphScale(0.7)
|
|
self.avIdList = []
|
|
self.enterAimStart = 0
|
|
return
|
|
|
|
def generate(self):
|
|
self.notify.debug('Hole Generate')
|
|
DistributedPhysicsWorld.DistributedPhysicsWorld.generate(self)
|
|
self.golfPowerTaskName = self.uniqueName('updateGolfPower')
|
|
|
|
def announceGenerate(self):
|
|
DistributedPhysicsWorld.DistributedPhysicsWorld.announceGenerate(self)
|
|
self.setup()
|
|
self.sendReady()
|
|
self.request('Off')
|
|
index = 1
|
|
for avId in self.avIdList:
|
|
self.createBall(avId, index)
|
|
self.createClub(avId)
|
|
index += 1
|
|
|
|
if self.avIdList:
|
|
avId = self.avIdList[0]
|
|
self.currentGolfer = avId
|
|
self.currentGolferActive = False
|
|
|
|
def delete(self):
|
|
self.removePlayBackDelayDelete()
|
|
self.request('Cleanup')
|
|
taskMgr.remove(self.golfPowerTaskName)
|
|
DistributedPhysicsWorld.DistributedPhysicsWorld.delete(self)
|
|
GolfHoleBase.GolfHoleBase.delete(self)
|
|
if hasattr(self, 'perfectIval'):
|
|
self.perfectIval.pause()
|
|
del self.perfectIval
|
|
self.golfCourse = None
|
|
if self.teeInstructions:
|
|
self.teeInstructions.destroy()
|
|
self.teeInstructions = None
|
|
if self.aimInstructions:
|
|
self.aimInstructions.destory()
|
|
self.aimInstructions = None
|
|
if self.powerReminder:
|
|
self.powerReminder.destroy()
|
|
self.powerReminder = None
|
|
if self.swingInterval:
|
|
self.swingInterval.pause()
|
|
self.swingInterval = None
|
|
if self.sfxInterval:
|
|
self.sfxInterval.pause()
|
|
self.sfxInterval = None
|
|
if self.camInterval:
|
|
self.camInterval.pause()
|
|
self.camInterval = None
|
|
for club in self.clubs:
|
|
self.clubs[club].removeNode()
|
|
|
|
del self.clubs
|
|
if hasattr(self, 'scoreBoard'):
|
|
if hasattr(self.scoreBoard, 'maximizeB'):
|
|
if self.scoreBoard.maximizeB:
|
|
self.scoreBoard.maximizeB.hide()
|
|
if not self.titleLabel == None:
|
|
self.titleLabel.destroy()
|
|
self.notify.debug('Deleted title label')
|
|
self.notify.debug('Delete function')
|
|
if self.flyOverInterval:
|
|
self.flyOverInterval.pause()
|
|
self.flyOverInterval = None
|
|
for key in self.ballShadowDict:
|
|
self.ballShadowDict[key].removeNode()
|
|
|
|
self.dropShadowModel.removeNode()
|
|
return
|
|
|
|
def sendReady(self):
|
|
self.sendUpdate('setAvatarReadyHole', [])
|
|
|
|
def createClub(self, avId):
|
|
club = NodePath('club-%s' % avId)
|
|
clubModel = loader.loadModel('phase_6/models/golf/putter')
|
|
clubModel.reparentTo(club)
|
|
clubModel.setR(clubModel, 45)
|
|
self.clubs[avId] = club
|
|
|
|
def attachClub(self, avId, pointToBall = False):
|
|
club = self.clubs[avId]
|
|
if club:
|
|
av = base.cr.doId2do.get(avId)
|
|
if av:
|
|
av.useLOD(1000)
|
|
lHand = av.getLeftHands()[0]
|
|
club.setPos(0, 0, 0)
|
|
club.reparentTo(lHand)
|
|
netScale = club.getNetTransform().getScale()[1]
|
|
counterActToonScale = lHand.find('**/counteractToonScale')
|
|
if counterActToonScale.isEmpty():
|
|
counterActToonScale = lHand.attachNewNode('counteractToonScale')
|
|
counterActToonScale.setScale(1 / netScale)
|
|
self.notify.debug('creating counterActToonScale for %s' % av.getName())
|
|
club.reparentTo(counterActToonScale)
|
|
club.setX(-0.25 * netScale)
|
|
if pointToBall:
|
|
club.lookAt(self.clubLookatSpot)
|
|
|
|
def createToonRay(self):
|
|
self.toonRay = OdeRayGeom(self.space, 10.0)
|
|
self.toonRay.setCollideBits(BitMask32(16777215))
|
|
self.toonRay.setCategoryBits(BitMask32(0))
|
|
self.toonRay.setRotation(Mat3(1, 0, 0, 0, -1, 0, 0, 0, -1))
|
|
self.space.setCollideId(self.toonRay, GolfGlobals.TOON_RAY_COLLIDE_ID)
|
|
self.rayList.append(self.toonRay)
|
|
|
|
def createSkyRay(self):
|
|
self.skyRay = OdeRayGeom(self.space, 100.0)
|
|
self.skyRay.setCollideBits(BitMask32(240))
|
|
self.skyRay.setCategoryBits(BitMask32(0))
|
|
self.skyRay.setRotation(Mat3(1, 0, 0, 0, -1, 0, 0, 0, -1))
|
|
self.space.setCollideId(self.skyRay, 78)
|
|
self.rayList.append(self.skyRay)
|
|
|
|
def createCameraRay(self):
|
|
self.cameraRay = OdeRayGeom(self.space, 30.0)
|
|
self.cameraRay.setCollideBits(BitMask32(8388608))
|
|
self.cameraRay.setCategoryBits(BitMask32(0))
|
|
self.space.setCollideId(self.cameraRay, GolfGlobals.CAMERA_RAY_COLLIDE_ID)
|
|
self.cameraRayNodePath = self.terrainModel.attachNewNode('cameraRayNodePath')
|
|
self.rayList.append(self.cameraRay)
|
|
|
|
def loadLevel(self):
|
|
GolfHoleBase.GolfHoleBase.loadLevel(self)
|
|
self.teeNodePath = self.terrainModel.find('**/tee0')
|
|
if self.teeNodePath.isEmpty():
|
|
teePos = Vec3(0, 0, 10)
|
|
else:
|
|
teePos = self.teeNodePath.getPos()
|
|
teePos.setZ(teePos.getZ() + GolfGlobals.GOLF_BALL_RADIUS)
|
|
self.notify.debug('teeNodePath heading = %s' % self.teeNodePath.getH())
|
|
self.teePositions = [teePos]
|
|
teeIndex = 1
|
|
teeNode = self.terrainModel.find('**/tee%d' % teeIndex)
|
|
while not teeNode.isEmpty():
|
|
teePos = teeNode.getPos()
|
|
teePos.setZ(teePos.getZ() + GolfGlobals.GOLF_BALL_RADIUS)
|
|
self.teePositions.append(teePos)
|
|
self.notify.debug('teeNodeP heading = %s' % teeNode.getH())
|
|
teeIndex += 1
|
|
teeNode = self.terrainModel.find('**/tee%d' % teeIndex)
|
|
|
|
self.holeBottomNodePath = self.terrainModel.find('**/holebottom0')
|
|
if self.holeBottomNodePath.isEmpty():
|
|
self.holeBottomPos = Vec3(*self.holeInfo['holePos'][0])
|
|
else:
|
|
self.holeBottomPos = self.holeBottomNodePath.getPos()
|
|
self.holePositions.append(self.holeBottomPos)
|
|
minHard = Point3(0, 0, 0)
|
|
maxHard = Point3(0, 0, 0)
|
|
self.hardSurfaceNodePath.calcTightBounds(minHard, maxHard)
|
|
centerX = (minHard[0] + maxHard[0]) / 2.0
|
|
centerY = (minHard[1] + maxHard[1]) / 2.0
|
|
heightX = (centerX - minHard[0]) / math.tan(deg2Rad(23))
|
|
heightY = (centerY - minHard[1]) / math.tan(deg2Rad(18))
|
|
height = max(heightX, heightY)
|
|
self.camTopViewPos = Point3(centerX, centerY, height)
|
|
self.camTopViewHpr = Point3(0, -90, 0)
|
|
self.createRays()
|
|
self.createToonRay()
|
|
self.createCameraRay()
|
|
|
|
def createLocatorDict(self):
|
|
self.locDict = {}
|
|
locatorNum = 1
|
|
curNodePath = self.hardSurfaceNodePath.find('**/locator%d' % locatorNum)
|
|
while not curNodePath.isEmpty():
|
|
self.locDict[locatorNum] = curNodePath
|
|
locatorNum += 1
|
|
curNodePath = self.hardSurfaceNodePath.find('**/locator%d' % locatorNum)
|
|
|
|
def loadBlockers(self):
|
|
loadAll = base.config.GetBool('golf-all-blockers', 0)
|
|
self.createLocatorDict()
|
|
self.blockerNums = self.holeInfo['blockers']
|
|
for locatorNum in self.locDict:
|
|
if locatorNum in self.blockerNums or loadAll:
|
|
locator = self.locDict[locatorNum]
|
|
locatorParent = locator.getParent()
|
|
locator.getChildren().wrtReparentTo(locatorParent)
|
|
else:
|
|
self.locDict[locatorNum].removeNode()
|
|
|
|
self.hardSurfaceNodePath.flattenStrong()
|
|
|
|
def loadSounds(self):
|
|
self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.ogg')
|
|
self.holeInOneSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hole_In_One.ogg')
|
|
self.holeInTwoPlusSfx = loader.loadSfx('phase_4/audio/sfx/MG_sfx_vine_game_fall.ogg')
|
|
self.ballGoesInStartSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Ball_Goes_In_Start.ogg')
|
|
self.ballGoesInLoopSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Ball_Goes_In_Loop.ogg')
|
|
self.ballGoesToRestSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Ball_Rest_In_Cup.ogg')
|
|
self.kickedOutSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Sad_Noise_Kicked_Off_Hole.ogg')
|
|
self.crowdBuildupSfx = []
|
|
self.crowdApplauseSfx = []
|
|
self.crowdMissSfx = []
|
|
for i in xrange(4):
|
|
self.crowdBuildupSfx.append(loader.loadSfx('phase_6/audio/sfx/Golf_Crowd_Buildup.ogg'))
|
|
self.crowdApplauseSfx.append(loader.loadSfx('phase_6/audio/sfx/Golf_Crowd_Applause.ogg'))
|
|
self.crowdMissSfx.append(loader.loadSfx('phase_6/audio/sfx/Golf_Crowd_Miss.ogg'))
|
|
|
|
self.bumpHardSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Barrier_3.ogg')
|
|
self.bumpMoverSfx = loader.loadSfx('phase_4/audio/sfx/Golf_Hit_Barrier_2.ogg')
|
|
self.bumpWindmillSfx = loader.loadSfx('phase_4/audio/sfx/Golf_Hit_Barrier_1.ogg')
|
|
|
|
def setup(self):
|
|
self.notify.debug('setup golf hole')
|
|
self.loadLevel()
|
|
self.loadSounds()
|
|
self.camMove = 0
|
|
self.arrowKeys = ArrowKeys.ArrowKeys()
|
|
self.arrowKeys.setPressHandlers([None,
|
|
None,
|
|
self.__leftArrowPressed,
|
|
self.__rightArrowPressed,
|
|
self.__beginTossGolf])
|
|
self.arrowKeys.setReleaseHandlers([None,
|
|
None,
|
|
None,
|
|
None,
|
|
self.__endTossGolf])
|
|
self.targets = render.attachNewNode('targetGameTargets')
|
|
self.ballFollow = render.attachNewNode('nodeAtBall')
|
|
self.startingTeeHeading = self.teeNodePath.getH()
|
|
self.ballFollow.setH(self.startingTeeHeading)
|
|
self.ballFollowToonSpot = self.ballFollow.attachNewNode('toonAimSpot')
|
|
self.ballFollowToonSpot.setX(-2.0)
|
|
self.ballFollowToonSpot.setY(0)
|
|
self.ballFollowToonSpot.setH(-90)
|
|
self.clubLookatSpot = self.ballFollow.attachNewNode('clubLookat')
|
|
self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1))
|
|
camera.reparentTo(self.ballFollow)
|
|
self.camPosBallFollow = Point3(0.0, -23.0, 12.0)
|
|
self.camHprBallFollow = Point3(0, -16.0, 0)
|
|
camera.setPos(self.camPosBallFollow)
|
|
camera.setHpr(self.camHprBallFollow)
|
|
if self.holeBottomNodePath.isEmpty():
|
|
holePositions = self.holePositions
|
|
for index in xrange(len(holePositions)):
|
|
holePos = holePositions[index]
|
|
targetNodePathGeom, t1, t2 = BuildGeometry.addCircleGeom(self.targets, 16, 1)
|
|
targetNodePathGeom.setPos(holePos)
|
|
targetNodePathGeom.setBin('ground', 0)
|
|
targetNodePathGeom.setDepthWrite(False)
|
|
targetNodePathGeom.setDepthTest(False)
|
|
targetNodePathGeom.setTransparency(TransparencyAttrib.MAlpha)
|
|
targetNodePathGeom.setColorScale(0.0, 0.0, 0.0, 1.0)
|
|
self.holeNodes.append(targetNodePathGeom)
|
|
holeSphere = CollisionSphere(0, 0, 0, 1)
|
|
holeSphere.setTangible(1)
|
|
holeCNode = CollisionNode('Hole')
|
|
holeCNode.addSolid(holeSphere)
|
|
holeC = targetNodePathGeom.attachNewNode(holeCNode)
|
|
holeC.show()
|
|
|
|
holeC.setCollideMask(ToontownGlobals.PieBitmask)
|
|
toon = base.localAvatar
|
|
toon.setPos(0.0, 0.0, -100.0)
|
|
toon.b_setAnimState('neutral', 1.0)
|
|
self.pollingCtrl = 0
|
|
self.timeLastCtrl = 0.0
|
|
self.powerBar = DirectWaitBar(guiId='launch power bar', pos=(0.0, 0, -0.65), relief=DGG.SUNKEN, frameSize=(-2.0,
|
|
2.0,
|
|
-0.2,
|
|
0.2), borderWidth=(0.02, 0.02), scale=0.25, range=100, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(1.0, 0.0, 0.0, 1.0), text='', text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05))
|
|
self.power = 0
|
|
self.powerBar['value'] = self.power
|
|
self.powerBar.hide()
|
|
self.accept('tab', self.tabKeyPressed)
|
|
self.putAwayAllToons()
|
|
base.transitions.irisOut(t=0)
|
|
self.dropShadowModel = loader.loadModel('phase_3/models/props/drop_shadow')
|
|
self.dropShadowModel.setColor(0, 0, 0, 0.5)
|
|
self.dropShadowModel.flattenMedium()
|
|
self.dropShadowModel.hide()
|
|
return
|
|
|
|
def switchToAnimState(self, animStateName, forced = False):
|
|
curAnimState = base.localAvatar.animFSM.getCurrentState()
|
|
curAnimStateName = ''
|
|
if curAnimState:
|
|
curAnimStateName = curAnimState.getName()
|
|
if curAnimStateName != animStateName or forced:
|
|
base.localAvatar.b_setAnimState(animStateName)
|
|
|
|
def __aimTask(self, task):
|
|
self.attachClub(self.currentGolfer, True)
|
|
x = -math.sin(self.ballFollow.getH() * 0.0174532925)
|
|
y = math.cos(self.ballFollow.getH() * 0.0174532925)
|
|
dt = globalClock.getDt()
|
|
b = self.curGolfBall()
|
|
forceMove = 500
|
|
forceMoveDt = forceMove * dt
|
|
posUpdate = False
|
|
momentumChange = dt * 60.0
|
|
if (self.arrowKeys.upPressed() or self.arrowKeys.downPressed()) and not self.golfCourse.canDrive(self.currentGolfer):
|
|
posUpdate = True
|
|
self.aimMomentum = 0.0
|
|
self.ballFollow.headsUp(self.holeBottomNodePath)
|
|
elif self.arrowKeys.rightPressed() and not self.arrowKeys.leftPressed():
|
|
self.aimMomentum -= momentumChange
|
|
if self.aimMomentum > 0:
|
|
self.aimMomentum = 0.0
|
|
elif self.aimMomentum < -30.0:
|
|
self.aimMomentum = -30.0
|
|
posUpdate = True
|
|
self.switchToAnimState('GolfRotateLeft')
|
|
self.scoreBoard.hide()
|
|
elif self.arrowKeys.leftPressed() and not self.arrowKeys.rightPressed():
|
|
self.aimMomentum += momentumChange
|
|
if self.aimMomentum < 0.0:
|
|
self.aimMomentum = 0.0
|
|
elif self.aimMomentum > 30.0:
|
|
self.aimMomentum = 30.0
|
|
posUpdate = True
|
|
self.switchToAnimState('GolfRotateRight')
|
|
self.scoreBoard.hide()
|
|
else:
|
|
self.aimMomentum = 0.0
|
|
self.switchToAnimState('GolfPuttLoop')
|
|
self.ballFollow.setH(self.ballFollow.getH() + self.aimMomentum * dt)
|
|
if self.arrowKeys.upPressed() and self.golfCourse.canDrive(self.currentGolfer):
|
|
b.enable()
|
|
b.addForce(Vec3(x * forceMoveDt, y * forceMoveDt, 0))
|
|
if self.arrowKeys.downPressed() and self.golfCourse.canDrive(self.currentGolfer):
|
|
b.enable()
|
|
b.addForce(Vec3(-x * forceMoveDt, -y * forceMoveDt, 0))
|
|
if self.arrowKeys.leftPressed() and self.arrowKeys.rightPressed() and self.golfCourse.canDrive(self.currentGolfer):
|
|
b.enable()
|
|
b.addForce(Vec3(0, 0, 3000 * dt))
|
|
if posUpdate:
|
|
if globalClock.getFrameTime() - self.lastTimeHeadingSent > 0.2:
|
|
self.sendUpdate('setTempAimHeading', [localAvatar.doId, self.ballFollow.getH()])
|
|
self.lastTimeHeadingSent = globalClock.getFrameTime()
|
|
self.lastTempHeadingSent = self.ballFollow.getH()
|
|
elif self.lastTempHeadingSent != self.ballFollow.getH():
|
|
self.sendUpdate('setTempAimHeading', [localAvatar.doId, self.ballFollow.getH()])
|
|
self.lastTimeHeadingSent = globalClock.getFrameTime()
|
|
self.lastTempHeadingSent = self.ballFollow.getH()
|
|
self.setCamera2Ball()
|
|
self.fixCurrentGolferFeet()
|
|
self.adjustClub()
|
|
self.orientCameraRay()
|
|
return task.cont
|
|
|
|
def fixCurrentGolferFeet(self):
|
|
golfer = base.cr.doId2do.get(self.currentGolfer)
|
|
if not golfer:
|
|
return
|
|
golferPos = golfer.getPos(render)
|
|
newPos = Vec3(golferPos[0], golferPos[1], golferPos[2] + 5)
|
|
self.toonRay.setPosition(newPos)
|
|
|
|
def adjustClub(self):
|
|
club = self.clubs[self.currentGolfer]
|
|
if club:
|
|
distance = club.getDistance(self.clubLookatSpot)
|
|
scaleFactor = distance / 2.058
|
|
club.setScale(1, scaleFactor, 1)
|
|
|
|
def resetPowerBar(self):
|
|
self.power = 0
|
|
self.powerBar['value'] = self.power
|
|
self.powerBar['text'] = ''
|
|
|
|
def sendSwingInfo(self):
|
|
kickHimOut = self.updateWarning()
|
|
if kickHimOut:
|
|
return
|
|
curAimTime = globalClock.getRealTime() - self.enterAimStart
|
|
if curAimTime < 0:
|
|
curAimTime = 0
|
|
if curAimTime > GolfGlobals.AIM_DURATION:
|
|
curAimTime = GolfGlobals.AIM_DURATION
|
|
self.notify.debug('curAimTime = %f' % curAimTime)
|
|
x = -math.sin(self.ballFollow.getH() * 0.0174532925)
|
|
y = math.cos(self.ballFollow.getH() * 0.0174532925)
|
|
b = self.curGolfBall()
|
|
if hasattr(base, 'golfPower') and base.golfPower != None:
|
|
self.power = float(base.golfPower)
|
|
if not self.swingInfoSent:
|
|
self.sendUpdate('postSwingState', [self.getCycleTime(),
|
|
self.power,
|
|
b.getPosition()[0],
|
|
b.getPosition()[1],
|
|
b.getPosition()[2],
|
|
x,
|
|
y,
|
|
curAimTime,
|
|
self.getCommonObjectData()])
|
|
self.swingInfoSent = True
|
|
if self.power < 15 and self.golfCourse.scores[localAvatar.doId][self.golfCourse.curHoleIndex] == 0:
|
|
self.powerReminder = DirectLabel(text=TTLocalizer.GolfPowerReminder, text_shadow=(0, 0, 0, 1), text_fg=VBase4(1, 1, 0.0, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.8), scale=0.12)
|
|
return
|
|
|
|
def updateWarning(self):
|
|
retval = False
|
|
if not self.localToonHitControl:
|
|
self.localMissedSwings += 1
|
|
else:
|
|
self.localMissedSwings = 0
|
|
if self.localMissedSwings == GolfGlobals.KICKOUT_SWINGS - 1:
|
|
self.warningLabel = DirectLabel(parent=aspect2d, relief=None, pos=(0, 0, 0), text_align=TextNode.ACenter, text=TTLocalizer.GolfWarningMustSwing, text_scale=0.12, text_font=ToontownGlobals.getSignFont(), text_fg=(1, 0.1, 0.1, 1), text_wordwrap=20)
|
|
self.warningInterval = Sequence(LerpColorScaleInterval(self.warningLabel, 10, Vec4(1, 1, 1, 0), startColorScale=Vec4(1, 1, 1, 1), blendType='easeIn'), Func(self.warningLabel.destroy))
|
|
self.warningInterval.start()
|
|
elif self.localMissedSwings >= GolfGlobals.KICKOUT_SWINGS:
|
|
self.golfCourse.handleFallingAsleepGolf(None)
|
|
retval = True
|
|
return retval
|
|
|
|
def assignRecordSwing(self, avId, cycleTime, power, x, y, z, dirX, dirY, commonObjectData):
|
|
ball = self.ballDict[avId]['golfBall']
|
|
holdBallPos = ball.getPosition()
|
|
self.useCommonObjectData(commonObjectData)
|
|
self.trackRecordBodyFlight(ball, cycleTime, power, Vec3(x, y, z), dirX, dirY)
|
|
ball.setPosition(holdBallPos)
|
|
self.sendUpdate('ballMovie2AI', [cycleTime,
|
|
avId,
|
|
self.recording,
|
|
self.aVRecording,
|
|
self.ballInHoleFrame,
|
|
self.ballTouchedHoleFrame,
|
|
self.ballFirstTouchedHoleFrame,
|
|
commonObjectData])
|
|
self.ballMovie2Client(cycleTime, avId, self.recording, self.aVRecording, self.ballInHoleFrame, self.ballTouchedHoleFrame, self.ballFirstTouchedHoleFrame, commonObjectData)
|
|
|
|
def __watchAimTask(self, task):
|
|
self.setCamera2Ball()
|
|
self.attachClub(self.currentGolfer, True)
|
|
self.adjustClub()
|
|
self.fixCurrentGolferFeet()
|
|
self.orientCameraRay()
|
|
return task.cont
|
|
|
|
def __watchTeeTask(self, task):
|
|
self.setCamera2Ball()
|
|
return task.cont
|
|
|
|
def curGolfBall(self):
|
|
return self.ballDict[self.currentGolfer]['golfBall']
|
|
|
|
def curGolfBallGeom(self):
|
|
return self.ballDict[self.currentGolfer]['golfBallGeom']
|
|
|
|
def curBallShadow(self):
|
|
return self.ballShadowDict[self.currentGolfer]
|
|
|
|
def cleanupGeom(self):
|
|
self.targets.remove()
|
|
self.terrainModel.remove()
|
|
self.powerBar.destroy()
|
|
|
|
def cleanupPowerBar(self):
|
|
self.powerBar.hide()
|
|
|
|
def cleanupPhysics(self):
|
|
pass
|
|
|
|
def curBall(self):
|
|
return self.ballDict[self.currentGolfer]['ball']
|
|
|
|
def curBallANP(self):
|
|
return self.ballDict[self.currentGolfer]['ballActorNodePath']
|
|
|
|
def curBallActor(self):
|
|
return self.ballDict[self.currentGolfer]['ballActor']
|
|
|
|
def enterAim(self):
|
|
self.notify.debug('Aim')
|
|
self.notify.debug('currentGolfer = %s' % self.currentGolfer)
|
|
self.switchToAnimState('GolfPuttLoop', forced=True)
|
|
self.swingInfoSent = False
|
|
self.lastState = self.state
|
|
self.aimMomentum = 0.0
|
|
self.enterAimStart = globalClock.getRealTime()
|
|
taskMgr.add(self.__aimTask, 'Aim Task')
|
|
self.showOnlyCurGolfer()
|
|
strokes = self.golfCourse.getStrokesForCurHole(self.currentGolfer)
|
|
self.camPivot = self.ballFollow.attachNewNode('golf-camPivot')
|
|
self.targetCamPivot = self.ballFollow.attachNewNode('golf-targetCamPivot')
|
|
self.targetCamPivot.setP(self.DefaultCamP)
|
|
self.curCamPivot = self.ballFollow.attachNewNode('golf-curCamPivot')
|
|
self.curCamPivot.setP(self.DefaultCamP)
|
|
self.ccTrav = CollisionTraverser('golf.ccTrav')
|
|
self.ccLine = CollisionSegment(0.0, 0.0, 0.0, 1.0, 0.0, 0.0)
|
|
self.ccLineNode = CollisionNode('golf.ccLineNode')
|
|
self.ccLineNode.addSolid(self.ccLine)
|
|
self.ccLineNodePath = self.camPivot.attachNewNode(self.ccLineNode)
|
|
self.ccLineBitMask = BitMask32(1048576)
|
|
self.ccLineNode.setFromCollideMask(self.ccLineBitMask)
|
|
self.ccLineNode.setIntoCollideMask(BitMask32.allOff())
|
|
self.camCollisionQueue = CollisionHandlerQueue()
|
|
self.ccTrav.addCollider(self.ccLineNodePath, self.camCollisionQueue)
|
|
if strokes:
|
|
self.ballFollow.headsUp(self.holeBottomNodePath)
|
|
self.camPivot.setP(self.DefaultCamP)
|
|
self._golfBarrierCollection = self.terrainModel.findAllMatches('**/collision?')
|
|
self._camAdjust = ScratchPad()
|
|
self._camAdjust.iters = 0
|
|
self._camAdjust.lower = self.DefaultCamP
|
|
self._camAdjust.upper = self.MaxCamP
|
|
base.camera.setPos(self.camPosBallFollow)
|
|
base.camera.setHpr(self.camHprBallFollow)
|
|
self.camPivot.setP(self.DefaultCamP)
|
|
base.camera.wrtReparentTo(self.camPivot)
|
|
A = Point3(0, 0, 0)
|
|
B = base.camera.getPos()
|
|
AtoB = B - A
|
|
AtoBnorm = Point3(AtoB)
|
|
AtoBnorm.normalize()
|
|
A += AtoBnorm * 0.4
|
|
self.ccLine.setPointA(A)
|
|
self.ccLine.setPointB(B)
|
|
self.camPivot.setP(self.DefaultCamP)
|
|
self._camAdjust.task = taskMgr.add(self._adjustCamera, 'adjustCamera')
|
|
self.resetPowerBar()
|
|
self.powerBar.show()
|
|
self.aimDuration = GolfGlobals.AIM_DURATION
|
|
if not self.unlimitedAimTime:
|
|
self.timer = ToontownTimer.ToontownTimer()
|
|
self.timer.posInTopRightCorner()
|
|
self.timer.setTime(self.aimDuration)
|
|
self.timer.countdown(self.aimDuration, self.timerExpired)
|
|
self.aimInstructions = DirectLabel(text=TTLocalizer.GolfAimInstructions, text_shadow=(0, 0, 0, 1), text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, -0.8), scale=TTLocalizer.DGHaimInstructions)
|
|
self.skyContact = 1
|
|
self.localToonHitControl = False
|
|
self._adjustCamera()
|
|
return
|
|
|
|
def exitAim(self):
|
|
localAvatar.wrtReparentTo(render)
|
|
taskMgr.remove(self._camAdjust.task)
|
|
taskMgr.remove('Aim Task')
|
|
taskMgr.remove(self.golfPowerTaskName)
|
|
if self.timer:
|
|
self.timer.stop()
|
|
self.timer.destroy()
|
|
self.timer = None
|
|
self.powerBar.hide()
|
|
self.ccLineNodePath.detachNode()
|
|
self.targetCamPivot.detachNode()
|
|
self.curCamPivot.detachNode()
|
|
self.camPivot.detachNode()
|
|
if self.aimInstructions:
|
|
self.aimInstructions.destroy()
|
|
self.aimInstructions = None
|
|
return
|
|
|
|
def timerExpired(self):
|
|
taskMgr.remove(self.golfPowerTaskName)
|
|
self.aimStart = None
|
|
self.sendSwingInfo()
|
|
self.resetPowerBar()
|
|
return
|
|
|
|
def _adjustCamera(self, task=None, first=True):
|
|
if task is None and first:
|
|
while 1:
|
|
self._adjustCamera(first=False)
|
|
if self._camAdjust.iters == 0:
|
|
return Task.cont
|
|
|
|
MaxIters = 5
|
|
finalP = self._camAdjust.lower
|
|
|
|
localAvatar.stash()
|
|
for barrier in self._golfBarrierCollection:
|
|
barrier.stash()
|
|
|
|
self.ccTrav.traverse(render)
|
|
|
|
for barrier in self._golfBarrierCollection:
|
|
barrier.unstash()
|
|
localAvatar.unstash()
|
|
|
|
midP = (self._camAdjust.lower + self._camAdjust.upper)/2
|
|
if self.camCollisionQueue.getNumEntries() > 0:
|
|
self.camCollisionQueue.sortEntries()
|
|
entry = self.camCollisionQueue.getEntry(0)
|
|
sPoint = entry.getSurfacePoint(self.camPivot)
|
|
self._camAdjust.lower = self.camPivot.getP()
|
|
finalP = midP
|
|
self.camPivot.setP(finalP)
|
|
else:
|
|
self._camAdjust.upper = self.camPivot.getP()
|
|
finalP = self._camAdjust.upper
|
|
self.camPivot.setP(midP)
|
|
if abs(self._camAdjust.lower - self._camAdjust.upper) < 1.0:
|
|
self._camAdjust.iters = MaxIters
|
|
|
|
self._camAdjust.iters += 1
|
|
if self._camAdjust.iters >= MaxIters:
|
|
self.targetCamPivot.setP(self._camAdjust.upper)
|
|
if task is None:
|
|
self.curCamPivot.setP(finalP)
|
|
self._camAdjust.iters = 0
|
|
self._camAdjust.lower = self.DefaultCamP
|
|
self._camAdjust.upper = self.MaxCamP
|
|
self.camPivot.setP(self.DefaultCamP)
|
|
|
|
if task is not None:
|
|
self.curCamPivot.setP(self.curCamPivot,
|
|
self.targetCamPivot.getP(self.curCamPivot)*min(1.0, 1.0*globalClock.getDt()))
|
|
|
|
curP = self.curCamPivot.getP()
|
|
self.curCamPivot.setP(self.DefaultCamP)
|
|
base.camera.reparentTo(self.ballFollow)
|
|
base.camera.setPos(self.camPosBallFollow)
|
|
base.camera.setHpr(self.camHprBallFollow)
|
|
base.camera.wrtReparentTo(self.curCamPivot)
|
|
self.curCamPivot.setP(curP)
|
|
base.camera.wrtReparentTo(self.ballFollow)
|
|
|
|
return Task.cont
|
|
|
|
def enterChooseTee(self):
|
|
self.notify.debug('ChooseTee')
|
|
self.curGolfBallGeom().show()
|
|
self.curBallShadow().show()
|
|
self.lastState = self.state
|
|
taskMgr.add(self.__chooseTeeTask, 'ChooseTee Task')
|
|
self.ballFollow.setH(self.startingTeeHeading)
|
|
self.localAvatarChosenTee = False
|
|
self.localTempTee = 0
|
|
if len(self.teePositions) > 1:
|
|
self.localTempTee = 1
|
|
self.chooseTeeDuration = GolfGlobals.TEE_DURATION
|
|
if not self.unlimitedTeeTime:
|
|
self.teeTimer = ToontownTimer.ToontownTimer()
|
|
self.teeTimer.posInTopRightCorner()
|
|
self.teeTimer.setTime(self.chooseTeeDuration)
|
|
self.teeTimer.countdown(self.chooseTeeDuration, self.teeTimerExpired)
|
|
self.teeInstructions = DirectLabel(text=TTLocalizer.GolfChooseTeeInstructions, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, text_shadow=(0, 0, 0, 1), relief=None, pos=(0, 0, -0.75), scale=TTLocalizer.DGHteeInstructions)
|
|
self.powerBar.hide()
|
|
return
|
|
|
|
def exitChooseTee(self):
|
|
localAvatar.wrtReparentTo(render)
|
|
if hasattr(self, 'teeInstructions') and self.teeInstructions:
|
|
self.teeInstructions.destroy()
|
|
self.teeInstructions = None
|
|
taskMgr.remove('ChooseTee Task')
|
|
taskMgr.remove(self.golfPowerTaskName)
|
|
if self.teeTimer:
|
|
self.teeTimer.stop()
|
|
self.teeTimer.destroy()
|
|
self.teeTimer = None
|
|
self.powerBar.show()
|
|
return
|
|
|
|
def sendTeeInfo(self):
|
|
self.sendUpdate('setAvatarTee', [self.localTempTee])
|
|
self.localAvatarChosenTee = True
|
|
|
|
def __chooseTeeTask(self, task):
|
|
if self.localAvatarChosenTee:
|
|
return task.done
|
|
if self.arrowKeys.jumpPressed():
|
|
if self.flyOverInterval and self.flyOverInterval.isPlaying():
|
|
pass
|
|
else:
|
|
self.sendTeeInfo()
|
|
return task.cont
|
|
|
|
def changeTee(self, newTee):
|
|
ball = self.curGolfBall()
|
|
ball.setPosition(self.teePositions[newTee])
|
|
self.setCamera2Ball()
|
|
self.fixCurrentGolferFeet()
|
|
self.adjustClub()
|
|
|
|
def changeLocalTee(self, newTee):
|
|
self.changeTee(newTee)
|
|
self.sendUpdate('setAvatarTempTee', [localAvatar.doId, newTee])
|
|
self.fixCurrentGolferFeet()
|
|
self.adjustClub()
|
|
|
|
def __leftArrowPressed(self):
|
|
if self.state != 'ChooseTee':
|
|
return
|
|
self.localTempTee -= 1
|
|
if self.localTempTee < 0:
|
|
self.localTempTee = len(self.teePositions) - 1
|
|
self.changeLocalTee(self.localTempTee)
|
|
|
|
def __rightArrowPressed(self):
|
|
if self.state != 'ChooseTee':
|
|
return
|
|
self.localTempTee += 1
|
|
self.localTempTee %= len(self.teePositions)
|
|
self.changeLocalTee(self.localTempTee)
|
|
|
|
def teeTimerExpired(self):
|
|
self.sendTeeInfo()
|
|
|
|
def enterWatchAim(self):
|
|
self.notify.debug('Watch Aim')
|
|
self.notify.debugStateCall(self)
|
|
self.notify.debug('currentGolfer = %s' % self.currentGolfer)
|
|
strokes = self.golfCourse.getStrokesForCurHole(self.currentGolfer)
|
|
if strokes:
|
|
self.ballFollow.lookAt(self.holeBottomNodePath)
|
|
self.ballFollow.setP(0)
|
|
self.showOnlyCurGolfer()
|
|
taskMgr.add(self.__watchAimTask, 'Watch Aim Task')
|
|
|
|
def exitWatchAim(self):
|
|
self.notify.debugStateCall(self)
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
if av:
|
|
heading = av.getH(render)
|
|
toonPos = av.getPos(render)
|
|
av.reparentTo(render)
|
|
av.setH(heading)
|
|
av.setPos(toonPos)
|
|
self.notify.debug('av %s now at position %s' % (av.getName(), av.getPos()))
|
|
else:
|
|
self.notify.debug('could not get avId %d' % self.currentGolfer)
|
|
taskMgr.remove('Watch Aim Task')
|
|
|
|
def enterWatchTee(self):
|
|
self.notify.debug('Watch Tee')
|
|
self.notify.debugStateCall(self)
|
|
self.curGolfBallGeom().show()
|
|
self.ballFollow.setH(self.startingTeeHeading)
|
|
self.ballShadowDict[self.currentGolfer].show()
|
|
|
|
def exitWatchTee(self):
|
|
self.notify.debugStateCall(self)
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
taskMgr.remove('Watch Tee Task')
|
|
|
|
def enterWait(self):
|
|
self.notify.debug('Wait')
|
|
self.notify.debugStateCall(self)
|
|
|
|
def exitWait(self):
|
|
self.notify.debugStateCall(self)
|
|
|
|
def removePlayBackDelayDelete(self):
|
|
if self.playBackDelayDelete:
|
|
self.playBackDelayDelete.destroy()
|
|
self.playBackDelayDelete = None
|
|
return
|
|
|
|
def enterPlayback(self):
|
|
|
|
def shiftClubToRightHand():
|
|
club = self.clubs[self.currentGolfer]
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
if av and club:
|
|
club.wrtReparentTo(av.getRightHands()[0])
|
|
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
if not av:
|
|
return
|
|
else:
|
|
self.removePlayBackDelayDelete()
|
|
self.playBackDelayDelete = DelayDelete.DelayDelete(av, 'GolfHole.enterPlayback')
|
|
self.accept('clientCleanup', self._handleClientCleanup)
|
|
self.inPlayBack = 1
|
|
self.setLookingAtPutt(False)
|
|
self.swingInterval = Sequence(ActorInterval(av, 'swing-putt', startFrame=0, endFrame=GolfGlobals.BALL_CONTACT_FRAME), Func(self.startBallPlayback), ActorInterval(av, 'swing-putt', startFrame=GolfGlobals.BALL_CONTACT_FRAME, endFrame=23), Func(shiftClubToRightHand), Func(self.setLookingAtPutt, True), Func(self.removePlayBackDelayDelete))
|
|
adjustedBallTouchedHoleTime = self.ballTouchedHoleTime + GolfGlobals.BALL_CONTACT_TIME
|
|
adjustedBallFirstTouchedHoleTime = self.ballFirstTouchedHoleTime + GolfGlobals.BALL_CONTACT_TIME
|
|
adjustedBallDropTime = self.ballDropTime + GolfGlobals.BALL_CONTACT_TIME
|
|
adjustedPlaybackEndTime = self.playbackMovieDuration + GolfGlobals.BALL_CONTACT_TIME
|
|
self.notify.debug('adjustedTimes ballTouched=%.2f ballFirstTouched=%.2f ballDrop=%.2f playbaybackEnd=%.2f' % (adjustedBallTouchedHoleTime,
|
|
adjustedBallFirstTouchedHoleTime,
|
|
adjustedBallDropTime,
|
|
adjustedPlaybackEndTime))
|
|
if self.ballWillGoInHole:
|
|
curDuration = self.swingInterval.getDuration()
|
|
lookPuttInterval = ActorInterval(av, 'look-putt')
|
|
if curDuration < adjustedBallDropTime:
|
|
self.swingInterval.append(lookPuttInterval)
|
|
curDuration = self.swingInterval.getDuration()
|
|
diffTime = adjustedBallDropTime - curDuration
|
|
if diffTime > 0:
|
|
self.swingInterval.append(ActorInterval(av, 'lookloop-putt', endTime=diffTime))
|
|
self.swingInterval.append(ActorInterval(av, 'good-putt', endTime=self.playbackMovieDuration, loop=1))
|
|
elif self.ballTouchedHoleTime:
|
|
self.notify.debug('doing self.ballTouchedHoleTime')
|
|
curDuration = self.swingInterval.getDuration()
|
|
lookPuttInterval = ActorInterval(av, 'look-putt')
|
|
if curDuration < adjustedBallTouchedHoleTime:
|
|
self.swingInterval.append(lookPuttInterval)
|
|
curDuration = self.swingInterval.getDuration()
|
|
diffTime = adjustedBallTouchedHoleTime - curDuration
|
|
if diffTime > 0:
|
|
self.swingInterval.append(ActorInterval(av, 'lookloop-putt', endTime=diffTime))
|
|
self.swingInterval.append(ActorInterval(av, 'bad-putt', endFrame=32))
|
|
self.swingInterval.append(ActorInterval(av, 'badloop-putt', endTime=self.playbackMovieDuration, loop=1))
|
|
else:
|
|
self.swingInterval.append(ActorInterval(av, 'look-putt'))
|
|
self.swingInterval.append(ActorInterval(av, 'lookloop-putt', endTime=self.playbackMovieDuration, loop=1))
|
|
sfxInterval = Parallel()
|
|
ballHitInterval = Sequence(Wait(GolfGlobals.BALL_CONTACT_TIME), SoundInterval(self.hitBallSfx))
|
|
sfxInterval.append(ballHitInterval)
|
|
if self.ballWillGoInHole:
|
|
ballRattle = Sequence()
|
|
timeToPlayBallRest = adjustedPlaybackEndTime - self.ballGoesToRestSfx.length()
|
|
if adjustedBallFirstTouchedHoleTime < timeToPlayBallRest:
|
|
diffTime = timeToPlayBallRest - adjustedBallFirstTouchedHoleTime
|
|
if self.ballGoesInStartSfx.length() < diffTime:
|
|
ballRattle.append(Wait(adjustedBallFirstTouchedHoleTime))
|
|
ballRattle.append(SoundInterval(self.ballGoesInStartSfx))
|
|
timeToPlayLoop = adjustedBallFirstTouchedHoleTime + self.ballGoesInStartSfx.length()
|
|
loopTime = timeToPlayBallRest - timeToPlayLoop
|
|
if self.ballGoesInLoopSfx.length() == 0.0:
|
|
numLoops = 0
|
|
else:
|
|
numLoops = int(loopTime / self.ballGoesInLoopSfx.length())
|
|
self.notify.debug('numLoops=%d loopTime=%f' % (numLoops, loopTime))
|
|
if loopTime > 0:
|
|
ballRattle.append(SoundInterval(self.ballGoesInLoopSfx, loop=1, duration=loopTime, seamlessLoop=True))
|
|
ballRattle.append(SoundInterval(self.ballGoesToRestSfx))
|
|
self.notify.debug('playing full rattling')
|
|
else:
|
|
self.notify.debug('playing abbreviated rattling')
|
|
timeToPlayBallGoesIn = adjustedBallFirstTouchedHoleTime
|
|
ballRattle.append(Wait(timeToPlayBallGoesIn))
|
|
startTime = self.ballGoesInStartSfx.length() - diffTime
|
|
self.notify.debug('adjustedBallDropTime=%s diffTime=%s starTime=%s' % (adjustedBallDropTime, diffTime, startTime))
|
|
ballRattle.append(SoundInterval(self.ballGoesInStartSfx, startTime=startTime))
|
|
ballRattle.append(SoundInterval(self.ballGoesToRestSfx))
|
|
else:
|
|
self.notify.debug('playing abbreviated ball goes to rest')
|
|
ballRattle.append(Wait(adjustedBallFirstTouchedHoleTime))
|
|
diffTime = adjustedPlaybackEndTime - adjustedBallFirstTouchedHoleTime
|
|
startTime = self.ballGoesToRestSfx.length() - diffTime
|
|
self.notify.debug('adjustedBallDropTime=%s diffTime=%s starTime=%s' % (adjustedBallDropTime, diffTime, startTime))
|
|
ballRattle.append(SoundInterval(self.ballGoesToRestSfx, startTime=startTime))
|
|
sfxInterval.append(ballRattle)
|
|
crowdBuildupSfx = self.crowdBuildupSfx[self.avIdList.index(self.currentGolfer)]
|
|
crowdApplauseSfx = self.crowdApplauseSfx[self.avIdList.index(self.currentGolfer)]
|
|
crowdMissSfx = self.crowdMissSfx[self.avIdList.index(self.currentGolfer)]
|
|
if self.ballWillGoInHole:
|
|
crowdIval = Sequence()
|
|
buildupLength = crowdBuildupSfx.length()
|
|
self.notify.debug('buildupLength=%s' % buildupLength)
|
|
diffTime = adjustedBallFirstTouchedHoleTime - buildupLength
|
|
if diffTime > 0:
|
|
crowdIval.append(Wait(diffTime))
|
|
crowdIval.append(SoundInterval(crowdBuildupSfx))
|
|
crowdIval.append(SoundInterval(crowdApplauseSfx))
|
|
else:
|
|
startTime = buildupLength - adjustedBallFirstTouchedHoleTime
|
|
self.notify.debug('playing abbreviated crowd build and applause diffTime=%s startTime=%s' % (diffTime, startTime))
|
|
crowdIval.append(SoundInterval(crowdBuildupSfx, startTime=startTime))
|
|
crowdIval.append(SoundInterval(crowdApplauseSfx))
|
|
sfxInterval.append(crowdIval)
|
|
elif self.ballFirstTouchedHoleTime:
|
|
crowdIval = Sequence()
|
|
buildupLength = crowdBuildupSfx.length()
|
|
self.notify.debug('touched but not going in buildupLength=%s' % buildupLength)
|
|
diffTime = adjustedBallFirstTouchedHoleTime - buildupLength
|
|
if diffTime > 0:
|
|
self.notify.debug('waiting %.2f to play crowd buildup' % diffTime)
|
|
crowdIval.append(Wait(diffTime))
|
|
crowdIval.append(SoundInterval(crowdBuildupSfx))
|
|
crowdIval.append(SoundInterval(crowdMissSfx))
|
|
else:
|
|
startTime = buildupLength - adjustedBallFirstTouchedHoleTime
|
|
self.notify.debug('playing abbreviated crowd build and miss diffTime=%s startTime=%s' % (diffTime, startTime))
|
|
crowdIval.append(SoundInterval(crowdBuildupSfx, startTime=startTime))
|
|
crowdIval.append(SoundInterval(crowdMissSfx))
|
|
sfxInterval.append(crowdIval)
|
|
if self.sfxInterval:
|
|
sfxInterval.finish()
|
|
self.sfxInterval = sfxInterval
|
|
self.sfxInterval.start()
|
|
self.swingInterval.start()
|
|
|
|
def exitPlayback(self):
|
|
self.notify.debug('Exiting Playback')
|
|
if self.swingInterval:
|
|
self.swingInterval.pause()
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
if av:
|
|
if self.ballWillGoInHole:
|
|
av.loop('good-putt', restart=0)
|
|
elif self.ballTouchedHoleTime:
|
|
pass
|
|
else:
|
|
av.loop('neutral')
|
|
self.setLookingAtPutt(False)
|
|
if av == base.localAvatar:
|
|
if self.ballWillGoInHole:
|
|
av.b_setAnimState('GolfGoodPutt')
|
|
elif self.ballTouchedHoleTime:
|
|
av.b_setAnimState('GolfBadPutt')
|
|
else:
|
|
av.b_setAnimState('neutral')
|
|
taskMgr.remove('playback task')
|
|
self.curGolfBall().disable()
|
|
self.readyCurrentGolfer(None)
|
|
self.inPlayBack = 0
|
|
if self.powerReminder:
|
|
self.powerReminder.destroy()
|
|
self.powerReminder = None
|
|
return
|
|
|
|
def setLookingAtPutt(self, newVal):
|
|
self.isLookingAtPutt = newVal
|
|
|
|
def getLookingAtPutt(self):
|
|
return self.isLookingAtPutt
|
|
|
|
def startBallPlayback(self):
|
|
self.playbackFrameNum = 0
|
|
self.sourceFrame = self.recording[0]
|
|
self.destFrameNum = 1
|
|
self.destFrame = self.recording[self.destFrameNum]
|
|
self.aVSourceFrame = self.aVRecording[0]
|
|
self.aVDestFrameNum = 1
|
|
self.aVDestFrame = self.aVRecording[self.aVDestFrameNum]
|
|
self.inPlayBack = 2
|
|
|
|
def isCurBallInHole(self):
|
|
retval = False
|
|
ball = self.curGolfBall()
|
|
ballPos = ball.getPosition()
|
|
for holePos in self.holePositions:
|
|
displacement = ballPos - holePos
|
|
length = displacement.length()
|
|
self.notify.debug('hole %s length=%s' % (holePos, length))
|
|
if length <= GolfGlobals.DistanceToBeInHole:
|
|
retval = True
|
|
break
|
|
|
|
return retval
|
|
|
|
def handleBallGoingInHole(self):
|
|
par = GolfGlobals.HoleInfo[self.holeId]['par']
|
|
unlimitedSwing = False
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
if av:
|
|
unlimitedSwing = av.getUnlimitedSwing()
|
|
if not unlimitedSwing:
|
|
self.curGolfBall().setPosition(0, 0, -100)
|
|
self.ballShadowDict[self.currentGolfer].setPos(0, 0, -100)
|
|
self.ballShadowDict[self.currentGolfer].hide()
|
|
strokes = 3
|
|
if self.golfCourse:
|
|
strokes = self.golfCourse.getStrokesForCurHole(self.currentGolfer)
|
|
else:
|
|
self.notify.warning('self.golfCourse is None')
|
|
diff = strokes - par
|
|
if diff > 0:
|
|
textStr = '+' + str(diff)
|
|
else:
|
|
textStr = diff
|
|
if strokes == 1:
|
|
textStr = TTLocalizer.GolfHoleInOne
|
|
elif diff in TTLocalizer.GolfShotDesc:
|
|
if self.ballWillGoInHole:
|
|
textStr = TTLocalizer.GolfShotDesc[diff]
|
|
perfectTextSubnode = hidden.attachNewNode(self.__genText(textStr))
|
|
perfectText = hidden.attachNewNode('perfectText')
|
|
perfectTextSubnode.reparentTo(perfectText)
|
|
frame = self.__textGen.getCardActual()
|
|
offsetY = -abs(frame[2] + frame[3]) / 2.0 - 1.35
|
|
perfectTextSubnode.setPos(0, 0, offsetY)
|
|
perfectText.setColor(1, 0.1, 0.1, 1)
|
|
|
|
def fadeFunc(t, text = perfectText):
|
|
text.setColorScale(1, 1, 1, t)
|
|
|
|
def destroyText(text = perfectText):
|
|
text.removeNode()
|
|
|
|
animTrack = Sequence()
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
animTrack.append(Func(self.golfCourse.updateScoreBoard))
|
|
textTrack = Sequence(Func(perfectText.reparentTo, aspect2d), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5), Func(self.sendUpdate, 'turnDone', []))
|
|
soundTrack = Sequence()
|
|
if strokes == 1:
|
|
soundTrack.append(SoundInterval(self.holeInOneSfx))
|
|
elif self.hasCurGolferReachedMaxSwing and not self.ballWillGoInHole:
|
|
soundTrack.append(SoundInterval(self.kickedOutSfx))
|
|
self.perfectIval = Parallel(textTrack, soundTrack, animTrack)
|
|
self.perfectIval.start()
|
|
|
|
def __playbackTask(self, task):
|
|
return self.playBackFrame(task)
|
|
|
|
def toonRayCollisionCallback(self, x, y, z):
|
|
if self.state not in ('Aim', 'WatchAim', 'ChooseTee', 'WatchTee'):
|
|
return
|
|
tempPath = render.attachNewNode('temp')
|
|
tempPath.setPos(x, y, z)
|
|
relPos = tempPath.getPos(self.ballFollowToonSpot)
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
if av:
|
|
zToUse = relPos[2]
|
|
if zToUse < 0 - GolfGlobals.GOLF_BALL_RADIUS:
|
|
zToUse = 0 - GolfGlobals.GOLF_BALL_RADIUS
|
|
av.setPos(0, 0, zToUse)
|
|
tempPath.removeNode()
|
|
|
|
def preStep(self):
|
|
if self.currentGolferActive:
|
|
GolfHoleBase.GolfHoleBase.preStep(self)
|
|
|
|
def postStep(self):
|
|
if self.currentGolferActive:
|
|
GolfHoleBase.GolfHoleBase.postStep(self)
|
|
DistributedPhysicsWorld.DistributedPhysicsWorld.postStep(self)
|
|
if self.inPlayBack == 2:
|
|
self.playBackFrame()
|
|
self.makeCurGolferLookAtBall()
|
|
elif self.state == 'Playback' and self.inPlayBack == 0:
|
|
self.request('Wait')
|
|
self.updateTranslucentObjects()
|
|
|
|
def updateTranslucentObjects(self):
|
|
for translucentNodePathLastFrame in self.translucentLastFrame:
|
|
if translucentNodePathLastFrame not in self.translucentCurFrame:
|
|
translucentNodePathLastFrame.setColorScale(1, 1, 1, 1)
|
|
|
|
for transNpCurFrame in self.translucentCurFrame:
|
|
if transNpCurFrame not in self.translucentLastFrame:
|
|
self.notify.debug('making translucent %s' % transNpCurFrame)
|
|
transNpCurFrame.setColorScale(1, 1, 1, 0.25)
|
|
transNpCurFrame.setTransparency(1)
|
|
|
|
def makeCurGolferLookAtBall(self):
|
|
if self.getLookingAtPutt():
|
|
av = base.cr.doId2do.get(self.currentGolfer)
|
|
if av:
|
|
ballPos = self.curGolfBall().getPosition()
|
|
av.headsUp(ballPos[0], ballPos[1], ballPos[2])
|
|
av.setH(av.getH() - 90)
|
|
|
|
def playBackFrame(self):
|
|
doPrint = 0
|
|
doAVPrint = 0
|
|
lastFrame = self.recording[len(self.recording) - 1][0]
|
|
if self.playbackFrameNum >= self.destFrame[0]:
|
|
self.sourceFrame = self.destFrame
|
|
self.destFrameNum += 1
|
|
doPrint = 1
|
|
if self.destFrameNum < len(self.recording):
|
|
self.destFrame = self.recording[self.destFrameNum]
|
|
else:
|
|
self.notify.debug('recording length %s' % len(self.recording))
|
|
if self.isCurBallInHole() or self.hasCurGolferReachedMaxSwing():
|
|
self.handleBallGoingInHole()
|
|
self.request('Wait')
|
|
else:
|
|
self.golfCourse.updateScoreBoard()
|
|
self.request('Wait')
|
|
self.sendUpdate('turnDone', [])
|
|
return
|
|
self.projLength = self.destFrame[0] - self.sourceFrame[0]
|
|
self.projPen = self.destFrame[0] - self.playbackFrameNum
|
|
propSource = float(self.projPen) / float(self.projLength)
|
|
propDest = 1.0 - propSource
|
|
projX = self.sourceFrame[1] * propSource + self.destFrame[1] * propDest
|
|
projY = self.sourceFrame[2] * propSource + self.destFrame[2] * propDest
|
|
projZ = self.sourceFrame[3] * propSource + self.destFrame[3] * propDest
|
|
newPos = Vec3(projX, projY, projZ)
|
|
ball = self.curGolfBall()
|
|
ball.setPosition(newPos)
|
|
if self.playbackFrameNum >= self.aVDestFrame[0]:
|
|
self.aVSourceFrame = self.aVDestFrame
|
|
self.aVDestFrameNum += 1
|
|
doAVPrint = 1
|
|
if self.aVDestFrameNum < len(self.aVRecording):
|
|
self.aVDestFrame = self.aVRecording[self.aVDestFrameNum]
|
|
newAV = Vec3(self.aVSourceFrame[1], self.aVSourceFrame[2], self.aVSourceFrame[3])
|
|
self.projLength = self.aVDestFrame[0] - self.aVSourceFrame[0]
|
|
self.projPen = self.aVDestFrame[0] - self.playbackFrameNum
|
|
propSource = float(self.projPen) / float(self.projLength)
|
|
propDest = 1.0 - propSource
|
|
projX = self.aVSourceFrame[1] * propSource + self.aVDestFrame[1] * propDest
|
|
projY = self.aVSourceFrame[2] * propSource + self.aVDestFrame[2] * propDest
|
|
projZ = self.aVSourceFrame[3] * propSource + self.aVDestFrame[3] * propDest
|
|
newAV = Vec3(projX, projY, projZ)
|
|
ball = self.curGolfBall()
|
|
ball.setAngularVel(newAV)
|
|
if self.playbackFrameNum < lastFrame - 1:
|
|
ball.enable()
|
|
else:
|
|
ball.disable()
|
|
self.setCamera2Ball()
|
|
self.placeBodies()
|
|
if doAVPrint:
|
|
pass
|
|
if doPrint:
|
|
self.notify.debug('. %s %s %s %s %s' % (self.playbackFrameNum,
|
|
self.sourceFrame[0],
|
|
self.destFrame[0],
|
|
self.destFrameNum,
|
|
newPos))
|
|
self.playbackFrameNum += 1
|
|
|
|
def enterCleanup(self):
|
|
taskMgr.remove('update task')
|
|
if hasattr(self, 'arrowKeys'):
|
|
self.arrowKeys.destroy()
|
|
self.arrowKeys = None
|
|
self.ignoreAll()
|
|
if self.swingInterval:
|
|
self.swingInterval.pause()
|
|
self.swingInterval = None
|
|
if self.sfxInterval:
|
|
self.sfxInterval.pause()
|
|
self.sfxInterval = None
|
|
self.cleanupGeom()
|
|
return
|
|
|
|
def exitCleanup(self):
|
|
pass
|
|
|
|
def setCamera2Ball(self):
|
|
b = self.curGolfBall()
|
|
ballPos = Point3(b.getPosition()[0], b.getPosition()[1], b.getPosition()[2])
|
|
self.ballFollow.setPos(ballPos)
|
|
|
|
def hitBall(self, ball, power, x, y):
|
|
self.performSwing(self, ball, power, x, y)
|
|
|
|
def ballMovie2Client(self, cycleTime, avId, movie, spinMovie, ballInFrame, ballTouchedHoleFrame, ballFirstTouchedHoleFrame, commonObjectData):
|
|
self.notify.debug('received Movie, number of frames %s %s ballInFrame=%d ballTouchedHoleFrame=%d ballFirstTouchedHoleFrame=%d' % (len(movie),
|
|
len(spinMovie),
|
|
ballInFrame,
|
|
ballTouchedHoleFrame,
|
|
ballFirstTouchedHoleFrame))
|
|
if self.state == 'Playback':
|
|
self.notify.debug('SMASHED PLAYBACK')
|
|
return
|
|
self.ballShadowDict[avId].show()
|
|
self.holdCycleTime = cycleTime
|
|
self.holdCommonObjectData = commonObjectData
|
|
self.useCommonObjectData(self.holdCommonObjectData)
|
|
self.recording = movie
|
|
self.aVRecording = spinMovie
|
|
endingBallPos = Vec3(movie[-1][1], movie[-1][2], movie[-1][3])
|
|
endingFrame = movie[-1][0]
|
|
self.playbackMovieDuration = endingFrame * self.DTAStep
|
|
self.notify.debug('playback movie duration=%s' % self.playbackMovieDuration)
|
|
displacement = self.holePositions[0] - endingBallPos
|
|
self.ballWillGoInHole = False
|
|
if displacement.length() <= GolfGlobals.DistanceToBeInHole:
|
|
self.ballWillGoInHole = True
|
|
self.notify.debug('endingBallPos=%s, distanceToHole=%s, ballWillGoInHole=%s' % (endingBallPos, displacement.length(), self.ballWillGoInHole))
|
|
self.ballDropTime = ballInFrame * self.DTAStep
|
|
self.ballTouchedHoleTime = ballTouchedHoleFrame * self.DTAStep
|
|
self.ballFirstTouchedHoleTime = ballFirstTouchedHoleFrame * self.DTAStep
|
|
if self.state == 'WatchTee':
|
|
self.request('WatchAim')
|
|
self.request('Playback')
|
|
|
|
def golfersTurn(self, avId):
|
|
self.readyCurrentGolfer(avId)
|
|
if avId == localAvatar.doId:
|
|
self.setCamera2Ball()
|
|
self.request('Aim')
|
|
else:
|
|
self.setCamera2Ball()
|
|
self.request('WatchAim')
|
|
|
|
def readyCurrentGolfer(self, avId):
|
|
for index in self.ballDict:
|
|
self.ballDict[index]['golfBallOdeGeom'].setCollideBits(BitMask32(0))
|
|
self.ballDict[index]['golfBallOdeGeom'].setCategoryBits(BitMask32(0))
|
|
self.ballDict[index]['golfBall'].disable()
|
|
|
|
if avId:
|
|
self.currentGolfer = avId
|
|
self.currentGolferActive = True
|
|
if avId in self.ballDict:
|
|
self.ballDict[avId]['golfBallOdeGeom'].setCollideBits(BitMask32(16777215))
|
|
self.ballDict[avId]['golfBallOdeGeom'].setCategoryBits(BitMask32(4278190080L))
|
|
else:
|
|
self.currentGolferActive = False
|
|
|
|
def setGolferIds(self, avIds):
|
|
self.avIdList = avIds
|
|
self.numPlayers = len(self.avIdList)
|
|
self.teeChosen = {}
|
|
for avId in self.avIdList:
|
|
self.teeChosen[avId] = -1
|
|
|
|
def setHoleId(self, holeId):
|
|
self.holeId = holeId
|
|
self.holeInfo = GolfGlobals.HoleInfo[holeId]
|
|
|
|
def createBall(self, avId, index = None):
|
|
golfBallGeom, golfBall, odeGeom = self.createSphere(self.world, self.space, GolfGlobals.GOLF_BALL_DENSITY, GolfGlobals.GOLF_BALL_RADIUS, index)
|
|
startPos = self.teePositions[0]
|
|
if len(self.teePositions) > 1:
|
|
startPos = self.teePositions[1]
|
|
golfBall.setPosition(startPos)
|
|
golfBallGeom.hide()
|
|
if self.notify.getDebug():
|
|
self.notify.debug('golf ball body id')
|
|
golfBall.write()
|
|
self.notify.debug(' -')
|
|
golfBallGeom.setName('golfBallGeom%s' % avId)
|
|
self.ballDict[avId] = {'golfBall': golfBall,
|
|
'golfBallGeom': golfBallGeom,
|
|
'golfBallOdeGeom': odeGeom}
|
|
golfBall.disable()
|
|
shadow = self.dropShadowModel.copyTo(render)
|
|
shadow.setBin('shadow', 100)
|
|
shadow.setScale(0.09)
|
|
shadow.setDepthWrite(False)
|
|
shadow.setDepthTest(True)
|
|
self.ballShadowDict[avId] = shadow
|
|
shadow.hide()
|
|
|
|
def setGolfCourseDoId(self, golfCourseDoId):
|
|
self.golfCourseDoId = golfCourseDoId
|
|
self.golfCourse = base.cr.doId2do.get(self.golfCourseDoId)
|
|
if not self.golfCourse:
|
|
self.cr.relatedObjectMgr.abortRequest(self.golfCourseRequest)
|
|
self.golfCourseRequest = self.cr.relatedObjectMgr.requestObjects([self.golfCourseDoId], eachCallback=self.__gotGolfCourse)
|
|
else:
|
|
self.scoreBoard = self.golfCourse.scoreBoard
|
|
self.scoreBoard.hide()
|
|
|
|
def __gotGolfCourse(self, golfCourse):
|
|
self.golfCourseRequest = None
|
|
self.golfCourse = golfCourse
|
|
return
|
|
|
|
def __genText(self, text):
|
|
self.__textGen.setText(text)
|
|
return self.__textGen.generate()
|
|
|
|
def sendBox(self, pos0, pos1, pos2, quat0, quat1, quat2, quat3, anV0, anV1, anV2, lnV0, lnV1, lnV2):
|
|
self.swingBox.setPosition(pos0, pos1, pos2)
|
|
self.swingBox.setQuaternion(Quat(quat0, quat1, quat2, quat3))
|
|
self.swingBox.setAngularVel(anV0, anV1, anV2)
|
|
self.swingBox.setLinearVel(lnV0, lnV1, lnV2)
|
|
|
|
def hasCurGolferReachedMaxSwing(self):
|
|
strokes = self.golfCourse.getStrokesForCurHole(self.currentGolfer)
|
|
maxSwing = self.holeInfo['maxSwing']
|
|
retval = strokes >= maxSwing
|
|
if retval:
|
|
pass
|
|
return retval
|
|
|
|
def __getGolfPower(self, time):
|
|
elapsed = max(time - self.aimStart, 0.0)
|
|
t = elapsed / self.golfPowerSpeed
|
|
t = math.pow(t, self.golfPowerExponent)
|
|
power = int(t * 100) % 200
|
|
if power > 100:
|
|
power = 200 - power
|
|
return power
|
|
|
|
def __beginTossGolf(self):
|
|
if self.aimStart != None:
|
|
return
|
|
if not self.state == 'Aim':
|
|
return
|
|
if self.swingInfoSent:
|
|
return
|
|
self.localToonHitControl = True
|
|
time = globalClock.getFrameTime()
|
|
self.aimStart = time
|
|
messenger.send('wakeup')
|
|
self.scoreBoard.hide()
|
|
taskMgr.add(self.__updateGolfPower, self.golfPowerTaskName)
|
|
return
|
|
|
|
def __endTossGolf(self):
|
|
if self.aimStart == None:
|
|
return
|
|
if not self.state == 'Aim':
|
|
return
|
|
messenger.send('wakeup')
|
|
taskMgr.remove(self.golfPowerTaskName)
|
|
self.aimStart = None
|
|
self.sendSwingInfo()
|
|
self.resetPowerBar()
|
|
return
|
|
|
|
def __updateGolfPower(self, task):
|
|
if not self.powerBar:
|
|
print '### no power bar!!!'
|
|
return Task.done
|
|
newPower = self.__getGolfPower(globalClock.getFrameTime())
|
|
self.power = newPower
|
|
self.powerBar['value'] = newPower
|
|
self.powerBar['text'] = TTLocalizer.GolfPowerBarText % {'power': newPower}
|
|
return Task.cont
|
|
|
|
def golferChooseTee(self, avId):
|
|
self.readyCurrentGolfer(avId)
|
|
self.putAwayAllToons()
|
|
if self.needToDoFlyOver and self.doFlyOverMovie(avId):
|
|
pass
|
|
else:
|
|
if avId == localAvatar.doId:
|
|
self.setCamera2Ball()
|
|
if not self.state == 'ChooseTee':
|
|
self.request('ChooseTee')
|
|
else:
|
|
self.setCamera2Ball()
|
|
self.request('WatchTee')
|
|
self.takeOutToon(self.currentGolfer)
|
|
|
|
def setAvatarTempTee(self, avId, tempTee):
|
|
if self.state != 'WatchTee':
|
|
return
|
|
if avId != self.currentGolfer:
|
|
self.notify.warning('setAvatarTempTee avId=%s not equal to self.currentGolfer=%s' % (avId, self.currentGolfer))
|
|
return
|
|
self.changeTee(tempTee)
|
|
|
|
def setAvatarFinalTee(self, avId, finalTee):
|
|
if avId != self.currentGolfer:
|
|
self.notify.warning('setAvatarTempTee avId=%s not equal to self.currentGolfer=%s' % (avId, self.currentGolfer))
|
|
return
|
|
self.changeTee(finalTee)
|
|
|
|
def setTempAimHeading(self, avId, heading):
|
|
if avId != self.currentGolfer:
|
|
self.notify.warning('setAvatarTempTee avId=%s not equal to self.currentGolfer=%s' % (avId, self.currentGolfer))
|
|
return
|
|
if self.state != 'WatchAim':
|
|
return
|
|
if avId != localAvatar.doId:
|
|
self.ballFollow.setH(heading)
|
|
|
|
def stickToonToBall(self, avId):
|
|
av = base.cr.doId2do.get(avId)
|
|
if av:
|
|
av.reparentTo(self.ballFollowToonSpot)
|
|
av.setPos(0, 0, 0)
|
|
av.setH(0)
|
|
|
|
def putAwayToon(self, avId):
|
|
av = base.cr.doId2do.get(avId)
|
|
if av:
|
|
av.reparentTo(render)
|
|
av.setPos(0, 0, -1000)
|
|
av.setH(0)
|
|
|
|
def putAwayAllToons(self):
|
|
for avId in self.avIdList:
|
|
self.putAwayToon(avId)
|
|
|
|
def takeOutToon(self, avId):
|
|
self.stickToonToBall(avId)
|
|
self.fixCurrentGolferFeet()
|
|
self.attachClub(avId)
|
|
|
|
def showOnlyCurGolfer(self):
|
|
self.notify.debug('curGolfer = %s' % self.currentGolfer)
|
|
self.stickToonToBall(self.currentGolfer)
|
|
self.fixCurrentGolferFeet()
|
|
self.attachClub(self.currentGolfer)
|
|
for avId in self.avIdList:
|
|
if avId != self.currentGolfer:
|
|
self.putAwayToon(avId)
|
|
|
|
def tabKeyPressed(self):
|
|
doInterval = True
|
|
self.notify.debug('tab key pressed')
|
|
if not hasattr(self, 'ballFollow'):
|
|
return
|
|
if self.flyOverInterval and self.flyOverInterval.isPlaying():
|
|
return
|
|
if self.camInterval and self.camInterval.isPlaying():
|
|
self.camInterval.pause()
|
|
if base.camera.getParent() == self.ballFollow:
|
|
if doInterval:
|
|
curHpr = camera.getHpr(render)
|
|
angle = PythonUtil.closestDestAngle2(curHpr[0], 0)
|
|
self.camInterval = Sequence(Func(base.camera.wrtReparentTo, render), LerpPosHprInterval(base.camera, 2, self.camTopViewPos, self.camTopViewHpr))
|
|
self.camInterval.start()
|
|
else:
|
|
base.camera.reparentTo(render)
|
|
base.camera.setPos(self.camTopViewPos)
|
|
base.camera.setHpr(self.camTopViewHpr)
|
|
elif doInterval:
|
|
curHpr = camera.getHpr(self.ballFollow)
|
|
angle = PythonUtil.closestDestAngle2(curHpr[0], 0)
|
|
self.camInterval = Sequence(Func(base.camera.wrtReparentTo, self.ballFollow), LerpPosHprInterval(base.camera, 2, self.camPosBallFollow, self.camHprBallFollow))
|
|
self.camInterval.start()
|
|
else:
|
|
base.camera.reparentTo(self.ballFollow)
|
|
base.camera.setPos(self.camPosBallFollow)
|
|
base.camera.setHpr(self.camHprBallFollow)
|
|
|
|
def doFlyOverMovie(self, avId):
|
|
title = GolfGlobals.getCourseName(self.golfCourse.courseId) + ' :\n ' + GolfGlobals.getHoleName(self.holeId) + '\n' + TTLocalizer.GolfPar + ' : ' + '%s' % self.holeInfo['par']
|
|
self.titleLabel = DirectLabel(parent=aspect2d, relief=None, pos=(0, 0, 0.8), text_align=TextNode.ACenter, text=title, text_scale=0.12, text_font=ToontownGlobals.getSignFont(), text_fg=(1, 0.8, 0.4, 1))
|
|
self.titleLabel.setBin('opaque', 19)
|
|
self.titleLabel.hide()
|
|
self.needToDoFlyOver = False
|
|
bamFile = self.holeInfo['terrainModel']
|
|
fileName = bamFile.split('/')[-1]
|
|
dotIndex = fileName.find('.')
|
|
baseName = fileName[0:dotIndex]
|
|
camModelName = baseName + '_cammodel.bam'
|
|
cameraName = baseName + '_camera.bam'
|
|
path = bamFile[0:bamFile.find(fileName)]
|
|
camModelFullPath = path + camModelName
|
|
cameraAnimFullPath = path + cameraName
|
|
try:
|
|
self.flyOverActor = Actor.Actor(camModelFullPath, {'camera': cameraAnimFullPath})
|
|
except StandardError:
|
|
self.notify.debug("Couldn't find flyover %s" % camModelFullPath)
|
|
return False
|
|
|
|
base.transitions.noIris()
|
|
self.flyOverActor.reparentTo(render)
|
|
self.flyOverActor.setBlend(frameBlend=True)
|
|
flyOverJoint = self.flyOverActor.find('**/camera1')
|
|
children = flyOverJoint.getChildren()
|
|
numChild = children.getNumPaths()
|
|
for i in xrange(numChild):
|
|
childNodePath = children.getPath(i)
|
|
childNodePath.removeNode()
|
|
|
|
self.flyOverJoint = flyOverJoint
|
|
self.flyOverInterval = Sequence(Func(base.camera.reparentTo, flyOverJoint), Func(base.camera.clearTransform), Func(self.titleLabel.show), ActorInterval(self.flyOverActor, 'camera'), Func(base.camera.reparentTo, self.ballFollow), Func(base.camera.setPos, self.camPosBallFollow), Func(base.camera.setHpr, self.camHprBallFollow))
|
|
if avId == localAvatar.doId:
|
|
self.flyOverInterval.append(Func(self.setCamera2Ball))
|
|
self.flyOverInterval.append(Func(self.safeRequestToState, 'ChooseTee'))
|
|
else:
|
|
self.flyOverInterval.append(Func(self.setCamera2Ball))
|
|
self.flyOverInterval.append(Func(self.safeRequestToState, 'WatchTee'))
|
|
self.flyOverInterval.append(Func(self.titleLabel.hide))
|
|
self.flyOverInterval.append(Func(self.takeOutToon, avId))
|
|
self.flyOverInterval.start()
|
|
return True
|
|
|
|
def avExited(self, avId):
|
|
if self.state == 'Playback' and self.currentGolfer == avId:
|
|
pass
|
|
else:
|
|
self.ballDict[avId]['golfBallGeom'].hide()
|
|
|
|
def orientCameraRay(self):
|
|
pos = base.camera.getPos(self.terrainModel)
|
|
self.cameraRayNodePath.setPos(pos)
|
|
self.cameraRayNodePath.lookAt(self.ballFollow)
|
|
renderPos = self.cameraRayNodePath.getPos(render)
|
|
if renderPos != pos:
|
|
self.notify.debug('orientCamerRay this should not happen')
|
|
ballPos = self.ballFollow.getPos(self.terrainModel)
|
|
dirCam = Vec3(ballPos - pos)
|
|
dirCam.normalize()
|
|
self.cameraRay.set(pos, dirCam)
|
|
|
|
def performSwing(self, ball, power, dirX, dirY):
|
|
startTime = globalClock.getRealTime()
|
|
avId = base.localAvatar.doId
|
|
position = ball.getPosition()
|
|
x = position[0]
|
|
y = position[1]
|
|
z = position[2]
|
|
if avId not in self.golfCourse.drivingToons:
|
|
x = position[0]
|
|
y = position[1]
|
|
z = position[2]
|
|
self.swingTime = cycleTime
|
|
lift = 0
|
|
ball = self.ball
|
|
forceMove = 2500
|
|
if power > 50:
|
|
lift = 0
|
|
ball.enable()
|
|
ball.setPosition(x, y, z)
|
|
ball.setLinearVel(0.0, 0.0, 0.0)
|
|
ball.setAngularVel(0.0, 0.0, 0.0)
|
|
ball.addForce(Vec3(dirX * forceMove * power / 100.0, dirY * forceMove * power / 100.0, lift))
|
|
self.initRecord()
|
|
safety = 0
|
|
self.llv = None
|
|
self.record(ball)
|
|
while ball.isEnabled() and len(self.recording) < 2000:
|
|
self.preStep()
|
|
self.simulate()
|
|
self.postStep()
|
|
self.record(ball)
|
|
safety += 1
|
|
|
|
self.record(ball)
|
|
midTime = globalClock.getRealTime()
|
|
self.processRecording()
|
|
self.processAVRecording()
|
|
self.notify.debug('Recording End time %s cycle %s len %s avLen %s' % (self.timingSimTime,
|
|
self.getSimCycleTime(),
|
|
len(self.recording),
|
|
len(self.aVRecording)))
|
|
self.request('WaitPlayback')
|
|
length = len(self.recording) - 1
|
|
x = self.recording[length][1]
|
|
y = self.recording[length][2]
|
|
z = self.recording[length][3]
|
|
self.ballPos[avId] = Vec3(x, y, z)
|
|
endTime = globalClock.getRealTime()
|
|
diffTime = endTime - startTime
|
|
fpsTime = self.frame / diffTime
|
|
self.notify.debug('Time Start %s Mid %s End %s Diff %s Fps %s frames %s' % (startTime,
|
|
midTime,
|
|
endTime,
|
|
diffTime,
|
|
fpsTime,
|
|
self.frame))
|
|
self.ballMovie2Client(cycleTime, avId, self.recording, self.aVRecording, self.ballInHoleFrame, self.ballTouchedHoleFrame, self.ballFirstTouchedHoleFrame)
|
|
return
|
|
|
|
def handleBallHitNonGrass(self, c0, c1):
|
|
if not self.inPlayBack:
|
|
return
|
|
golfBallPos = self.curGolfBall().getPosition()
|
|
if self.lastBumpSfxPos == golfBallPos:
|
|
return
|
|
if GolfGlobals.HARD_COLLIDE_ID in [c0, c1]:
|
|
if not self.bumpHardSfx.status() == self.bumpHardSfx.PLAYING:
|
|
distance = (golfBallPos - self.lastBumpSfxPos).length()
|
|
if distance > 2.0:
|
|
base.playSfx(self.bumpHardSfx)
|
|
self.lastBumpSfxPos = golfBallPos
|
|
elif GolfGlobals.MOVER_COLLIDE_ID in [c0, c1]:
|
|
if not self.bumpMoverSfx.status() == self.bumpMoverSfx.PLAYING:
|
|
base.playSfx(self.bumpMoverSfx)
|
|
self.lastBumpSfxPos = golfBallPos
|
|
elif GolfGlobals.WINDMILL_BASE_COLLIDE_ID in [c0, c1]:
|
|
if not self.bumpWindmillSfx.status() == self.bumpWindmillSfx.PLAYING:
|
|
base.playSfx(self.bumpWindmillSfx)
|
|
self.lastBumpSfxPos = golfBallPos
|
|
|
|
def safeRequestToState(self, newState):
|
|
doingRequest = False
|
|
if self.state in self.defaultTransitions:
|
|
if newState in self.defaultTransitions[self.state]:
|
|
self.request(newState)
|
|
doingRequest = True
|
|
if not doingRequest:
|
|
self.notify.warning('ignoring transition from %s to %s' % (self.state, newState))
|
|
|
|
def doMagicWordHeading(self, heading):
|
|
if self.state == 'Aim':
|
|
self.aimMomentum = 0.0
|
|
self.ballFollow.setH(float(heading))
|
|
|
|
def _handleClientCleanup(self):
|
|
self.removePlayBackDelayDelete()
|
|
self.ignore('clientCleanup')
|