Poodletooth-iLand/toontown/cogdominium/DistCogdoCrane.py

888 lines
33 KiB
Python
Raw Normal View History

2015-03-03 16:10:12 -06:00
from direct.distributed import DistributedObject
from direct.distributed.ClockDelta import *
from direct.fsm import FSM
from direct.gui.DirectGui import *
from direct.interval.IntervalGlobal import *
from direct.showbase import PythonUtil
from direct.showutil import Rope
from direct.task import Task
from pandac.PandaModules import *
import random
from otp.otpbase import OTPGlobals
from toontown.cogdominium import CogdoCraneGameConsts as GameConsts
from toontown.nametag import NametagGlobals
from toontown.toonbase import TTLocalizer
from toontown.toonbase import ToontownGlobals
class DistCogdoCrane(DistributedObject.DistributedObject, FSM.FSM):
notify = DirectNotifyGlobal.directNotify.newCategory('DistCogdoCrane')
firstMagnetBit = 21
craneMinY = 8
craneMaxY = 25
armMinH = -45
armMaxH = 45
shadowOffset = 7
emptySlideSpeed = 10
emptyRotateSpeed = 20
lookAtPoint = Point3(0.3, 0, 0.1)
lookAtUp = Vec3(0, -1, 0)
neutralStickHinge = VBase3(0, 90, 0)
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
FSM.FSM.__init__(self, 'DistCogdoCrane')
self.craneGame = None
self.index = None
self.avId = 0
self.cableLength = 20
self.numLinks = 3
self.initialArmPosition = (0, 20, 0)
self.slideSpeed = self.emptySlideSpeed
self.rotateSpeed = self.emptyRotateSpeed
self.changeSeq = 0
self.lastChangeSeq = 0
self.moveSound = None
self.links = []
self.activeLinks = []
self.collisions = NodePathCollection()
self.physicsActivated = 0
self.snifferActivated = 0
self.magnetOn = 0
self.root = NodePath('root')
self.hinge = self.root.attachNewNode('hinge')
self.hinge.setPos(0, -17.6, 38.5)
self.controls = self.root.attachNewNode('controls')
self.controls.setPos(0, -4.9, 0)
self.arm = self.hinge.attachNewNode('arm')
self.crane = self.arm.attachNewNode('crane')
self.cable = self.hinge.attachNewNode('cable')
self.topLink = self.crane.attachNewNode('topLink')
self.topLink.setPos(0, 0, -1)
self.shadow = None
self.p0 = Point3(0, 0, 0)
self.v1 = Vec3(1, 1, 1)
self.armSmoother = SmoothMover()
self.armSmoother.setSmoothMode(SmoothMover.SMOn)
self.linkSmoothers = []
self.smoothStarted = 0
self.__broadcastPeriod = 0.2
self.cable.node().setFinal(1)
self.crane.setPos(*self.initialArmPosition)
self.heldObject = None
self.craneAdviceLabel = None
self.magnetAdviceLabel = None
self.atLimitSfx = base.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.ogg')
self.magnetOnSfx = base.loadSfx('phase_10/audio/sfx/CBHQ_CFO_magnet_on.ogg')
self.magnetLoopSfx = base.loadSfx('phase_10/audio/sfx/CBHQ_CFO_magnet_loop.ogg')
self.magnetSoundInterval = Parallel(SoundInterval(self.magnetOnSfx), Sequence(Wait(0.5), Func(base.playSfx, self.magnetLoopSfx, looping=1)))
self.craneMoveSfx = base.loadSfx('phase_9/audio/sfx/CHQ_FACT_elevator_up_down.ogg')
self.fadeTrack = None
return
def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self)
self.name = 'crane-%s' % self.doId
self.root.setName(self.name)
self.root.setPosHpr(*GameConsts.CranePosHprs[self.index])
self.rotateLinkName = self.uniqueName('rotateLink')
self.snifferEvent = self.uniqueName('sniffer')
self.triggerName = self.uniqueName('trigger')
self.triggerEvent = 'enter%s' % self.triggerName
self.shadowName = self.uniqueName('shadow')
self.flickerName = self.uniqueName('flicker')
self.smoothName = self.uniqueName('craneSmooth')
self.posHprBroadcastName = self.uniqueName('craneBroadcast')
self.craneAdviceName = self.uniqueName('craneAdvice')
self.magnetAdviceName = self.uniqueName('magnetAdvice')
self.controlModel = self.craneGame.controls.copyTo(self.controls)
self.cc = NodePath('cc')
column = self.controlModel.find('**/column')
column.getChildren().reparentTo(self.cc)
self.cc.reparentTo(column)
self.stickHinge = self.cc.attachNewNode('stickHinge')
self.stick = self.craneGame.stick.copyTo(self.stickHinge)
self.stickHinge.setHpr(self.neutralStickHinge)
self.stick.setHpr(0, -90, 0)
self.stick.flattenLight()
self.bottom = self.controlModel.find('**/bottom')
self.bottom.wrtReparentTo(self.cc)
self.bottomPos = self.bottom.getPos()
cs = CollisionSphere(0, -5, -2, 3)
cs.setTangible(0)
cn = CollisionNode(self.triggerName)
cn.addSolid(cs)
cn.setIntoCollideMask(OTPGlobals.WallBitmask)
self.trigger = self.root.attachNewNode(cn)
self.trigger.stash()
cs = CollisionTube(0, 2.7, 0, 0, 2.7, 3, 1.2)
cn = CollisionNode('tube')
cn.addSolid(cs)
cn.setIntoCollideMask(OTPGlobals.WallBitmask)
self.tube = self.controlModel.attachNewNode(cn)
cs = CollisionSphere(0, 0, 2, 3)
cn = CollisionNode('safetyBubble')
cn.addSolid(cs)
cn.setIntoCollideMask(ToontownGlobals.PieBitmask)
self.controls.attachNewNode(cn)
arm = self.craneGame.craneArm.copyTo(self.crane)
self.craneGame.cranes[self.index] = self
def disable(self):
DistributedObject.DistributedObject.disable(self)
del self.craneGame.cranes[self.index]
self.cleanup()
def cleanup(self):
if self.state != 'Off':
self.demand('Off')
self.craneGame = None
return
def accomodateToon(self, toon):
origScale = self.controlModel.getSz()
origCcPos = self.cc.getPos()
origBottomPos = self.bottom.getPos()
origStickHingeHpr = self.stickHinge.getHpr()
scale = toon.getGeomNode().getChild(0).getSz(render)
self.controlModel.setScale(scale)
self.cc.setPos(0, 0, 0)
toon.setPosHpr(self.controls, 0, 0, 0, 0, 0, 0)
toon.pose('leverNeutral', 0)
toon.update()
pos = toon.rightHand.getPos(self.cc)
self.cc.setPos(pos[0], pos[1], pos[2] - 1)
self.bottom.setZ(toon, 0.0)
self.bottom.setPos(self.bottomPos[0], self.bottomPos[1], self.bottom.getZ())
self.stickHinge.lookAt(toon.rightHand, self.lookAtPoint, self.lookAtUp)
lerpTime = 0.5
return Parallel(self.controlModel.scaleInterval(lerpTime, scale, origScale, blendType='easeInOut'), self.cc.posInterval(lerpTime, self.cc.getPos(), origCcPos, blendType='easeInOut'), self.bottom.posInterval(lerpTime, self.bottom.getPos(), origBottomPos, blendType='easeInOut'), self.stickHinge.quatInterval(lerpTime, self.stickHinge.getHpr(), origStickHingeHpr, blendType='easeInOut'))
def getRestoreScaleInterval(self):
lerpTime = 1
return Parallel(self.controlModel.scaleInterval(lerpTime, 1, blendType='easeInOut'), self.cc.posInterval(lerpTime, Point3(0, 0, 0), blendType='easeInOut'), self.bottom.posInterval(lerpTime, self.bottomPos, blendType='easeInOut'), self.stickHinge.quatInterval(lerpTime, self.neutralStickHinge, blendType='easeInOut'))
def makeToonGrabInterval(self, toon):
origPos = toon.getPos()
origHpr = toon.getHpr()
a = self.accomodateToon(toon)
newPos = toon.getPos()
newHpr = toon.getHpr()
origHpr.setX(PythonUtil.fitSrcAngle2Dest(origHpr[0], newHpr[0]))
toon.setPosHpr(origPos, origHpr)
walkTime = 0.2
reach = ActorInterval(toon, 'leverReach')
if reach.getDuration() < walkTime:
reach = Sequence(ActorInterval(toon, 'walk', loop=1, duration=walkTime - reach.getDuration()), reach)
i = Sequence(Parallel(toon.posInterval(walkTime, newPos, origPos), toon.hprInterval(walkTime, newHpr, origHpr), reach), Func(self.startWatchJoystick, toon))
i = Parallel(i, a)
return i
def __toonPlayWithCallback(self, animName, numFrames):
duration = numFrames / 24.0
self.toon.play(animName)
taskMgr.doMethodLater(duration, self.__toonPlayCallback, self.uniqueName('toonPlay'))
def __toonPlayCallback(self, task):
if self.changeSeq == self.lastChangeSeq:
self.__toonPlayWithCallback('leverNeutral', 40)
else:
self.__toonPlayWithCallback('leverPull', 40)
self.lastChangeSeq = self.changeSeq
def startWatchJoystick(self, toon):
self.toon = toon
taskMgr.add(self.__watchJoystick, self.uniqueName('watchJoystick'))
self.__toonPlayWithCallback('leverNeutral', 40)
self.accept(toon.uniqueName('disable'), self.__handleUnexpectedExit, extraArgs=[toon.doId])
def stopWatchJoystick(self):
taskMgr.remove(self.uniqueName('toonPlay'))
taskMgr.remove(self.uniqueName('watchJoystick'))
if self.toon:
self.ignore(self.toon.uniqueName('disable'))
self.toon = None
return
def __watchJoystick(self, task):
self.toon.setPosHpr(self.controls, 0, 0, 0, 0, 0, 0)
self.toon.update()
self.stickHinge.lookAt(self.toon.rightHand, self.lookAtPoint, self.lookAtUp)
return Task.cont
def __handleUnexpectedExit(self, toonId):
self.notify.warning('%s: unexpected exit for %s' % (self.doId, toonId))
if self.toon and self.toon.doId == toonId:
self.stopWatchJoystick()
def __activatePhysics(self):
if not self.physicsActivated:
for an, anp, cnp in self.activeLinks:
self.craneGame.physicsMgr.attachPhysicalNode(an)
base.cTrav.addCollider(cnp, self.handler)
self.collisions.unstash()
self.physicsActivated = 1
def __deactivatePhysics(self):
if self.physicsActivated:
for an, anp, cnp in self.activeLinks:
self.craneGame.physicsMgr.removePhysicalNode(an)
base.cTrav.removeCollider(cnp)
self.collisions.stash()
self.physicsActivated = 0
def __straightenCable(self):
for linkNum in xrange(self.numLinks):
an, anp, cnp = self.activeLinks[linkNum]
an.getPhysicsObject().setVelocity(0, 0, 0)
z = float(linkNum + 1) / float(self.numLinks) * self.cableLength
anp.setPos(self.crane.getPos(self.cable))
anp.setZ(-z)
def setCableLength(self, length):
self.cableLength = length
linkWidth = float(length) / float(self.numLinks)
self.shell.setRadius(linkWidth + 1)
def setupCable(self):
activated = self.physicsActivated
self.clearCable()
self.handler = PhysicsCollisionHandler()
self.handler.setStaticFrictionCoef(0.1)
self.handler.setDynamicFrictionCoef(GameConsts.Settings.EmptyFrictionCoef.get())
linkWidth = float(self.cableLength) / float(self.numLinks)
self.shell = CollisionInvSphere(0, 0, 0, linkWidth + 1)
self.links = []
self.links.append((self.topLink, Point3(0, 0, 0)))
anchor = self.topLink
for linkNum in xrange(self.numLinks):
anchor = self.__makeLink(anchor, linkNum)
self.collisions.stash()
self.bottomLink = self.links[-1][0]
self.middleLink = self.links[-2][0]
self.magnet = self.bottomLink.attachNewNode('magnet')
self.wiggleMagnet = self.magnet.attachNewNode('wiggleMagnet')
taskMgr.add(self.__rotateMagnet, self.rotateLinkName)
magnetModel = self.craneGame.magnet.copyTo(self.wiggleMagnet)
magnetModel.setHpr(90, 45, 90)
self.gripper = magnetModel.attachNewNode('gripper')
self.gripper.setPos(0, 0, -4)
cn = CollisionNode('sniffer')
self.sniffer = magnetModel.attachNewNode(cn)
self.sniffer.stash()
cs = CollisionSphere(0, 0, -10, 6)
cs.setTangible(0)
cn.addSolid(cs)
cn.setIntoCollideMask(BitMask32(0))
cn.setFromCollideMask(ToontownGlobals.CashbotBossObjectBitmask)
self.snifferHandler = CollisionHandlerEvent()
self.snifferHandler.addInPattern(self.snifferEvent)
self.snifferHandler.addAgainPattern(self.snifferEvent)
rope = self.makeSpline()
rope.reparentTo(self.cable)
rope.setTexture(self.craneGame.cableTex)
ts = TextureStage.getDefault()
rope.setTexScale(ts, 0.15, 0.13)
rope.setTexOffset(ts, 0.83, 0.01)
if activated:
self.__activatePhysics()
def clearCable(self):
self.__deactivatePhysics()
taskMgr.remove(self.rotateLinkName)
self.links = []
self.activeLinks = []
self.linkSmoothers = []
self.collisions.clear()
self.cable.getChildren().detach()
self.topLink.getChildren().detach()
self.gripper = None
return
def makeSpline(self):
rope = Rope.Rope()
rope.setup(min(len(self.links), 4), self.links)
rope.curve.normalizeKnots()
rn = rope.ropeNode
rn.setRenderMode(RopeNode.RMTube)
rn.setNumSlices(3)
rn.setTubeUp(Vec3(0, -1, 0))
rn.setUvMode(RopeNode.UVParametric)
rn.setUvDirection(1)
rn.setThickness(0.5)
return rope
def startShadow(self):
self.shadow = self.craneGame.geomRoot.attachNewNode('%s-shadow' % self.name)
self.shadow.setColor(1, 1, 1, 0.3)
self.shadow.setDepthWrite(0)
self.shadow.setTransparency(1)
self.shadow.setBin('shadow', 0)
self.shadow.node().setFinal(1)
self.magnetShadow = loader.loadModel('phase_3/models/props/drop_shadow')
self.magnetShadow.reparentTo(self.shadow)
self.craneShadow = loader.loadModel('phase_3/models/props/square_drop_shadow')
self.craneShadow.setScale(0.5, 4, 1)
self.craneShadow.setPos(0, -12, 0)
self.craneShadow.flattenLight()
self.craneShadow.reparentTo(self.shadow)
taskMgr.add(self.__followShadow, self.shadowName)
rope = self.makeSpline()
rope.reparentTo(self.shadow)
rope.setColor(1, 1, 1, 0.2)
tex = self.craneShadow.findTexture('*')
rope.setTexture(tex)
rn = rope.ropeNode
rn.setRenderMode(RopeNode.RMTape)
rn.setNumSubdiv(6)
rn.setThickness(0.8)
rn.setTubeUp(Vec3(0, 0, 1))
rn.setMatrix(Mat4.translateMat(0, 0, self.shadowOffset) * Mat4.scaleMat(1, 1, 0.01))
def stopShadow(self):
if self.shadow:
self.shadow.removeNode()
self.shadow = None
self.magnetShadow = None
self.craneShadow = None
taskMgr.remove(self.shadowName)
return
def __followShadow(self, task):
p = self.magnet.getPos(self.craneGame.geomRoot)
self.magnetShadow.setPos(p[0], p[1], self.shadowOffset)
self.craneShadow.setPosHpr(self.crane, 0, 0, 0, 0, 0, 0)
self.craneShadow.setZ(self.shadowOffset)
return Task.cont
def __makeLink(self, anchor, linkNum):
an = ActorNode('link%s' % linkNum)
an.getPhysicsObject().setMass(GameConsts.Settings.RopeLinkMass.get())
anp = NodePath(an)
cn = CollisionNode('cn')
sphere = CollisionSphere(0, 0, 0, 1)
cn.addSolid(sphere)
cnp = anp.attachNewNode(cn)
self.handler.addCollider(cnp, anp)
self.activeLinks.append((an, anp, cnp))
self.linkSmoothers.append(SmoothMover())
anp.reparentTo(self.cable)
z = float(linkNum + 1) / float(self.numLinks) * self.cableLength
anp.setPos(self.crane.getPos())
anp.setZ(-z)
mask = BitMask32.bit(self.firstMagnetBit + linkNum)
cn.setFromCollideMask(mask)
cn.setIntoCollideMask(BitMask32(0))
shellNode = CollisionNode('shell%s' % linkNum)
shellNode.addSolid(self.shell)
shellNP = anchor.attachNewNode(shellNode)
shellNode.setIntoCollideMask(mask)
self.collisions.addPath(shellNP)
self.collisions.addPath(cnp)
self.links.append((anp, Point3(0, 0, 0)))
return anp
def __rotateMagnet(self, task):
self.magnet.lookAt(self.middleLink, self.p0, self.v1)
return Task.cont
def __enableControlInterface(self):
gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui')
self.accept('control', self.__controlPressed)
self.accept('control-up', self.__controlReleased)
self.accept('InputState-forward', self.__upArrow)
self.accept('InputState-reverse', self.__downArrow)
self.accept('InputState-turnLeft', self.__leftArrow)
self.accept('InputState-turnRight', self.__rightArrow)
taskMgr.add(self.__watchControls, 'watchCraneControls')
taskMgr.doMethodLater(5, self.__displayCraneAdvice, self.craneAdviceName)
taskMgr.doMethodLater(10, self.__displayMagnetAdvice, self.magnetAdviceName)
NametagGlobals.setForceOnscreenChat(True)
self.arrowVert = 0
self.arrowHorz = 0
def __disableControlInterface(self):
self.__turnOffMagnet()
self.__cleanupCraneAdvice()
self.__cleanupMagnetAdvice()
self.ignore('escape')
self.ignore('control')
self.ignore('control-up')
self.ignore('InputState-forward')
self.ignore('InputState-reverse')
self.ignore('InputState-turnLeft')
self.ignore('InputState-turnRight')
self.arrowVert = 0
self.arrowHorz = 0
NametagGlobals.setForceOnscreenChat(False)
taskMgr.remove('watchCraneControls')
self.__setMoveSound(None)
return
def __displayCraneAdvice(self, task):
if self.craneAdviceLabel == None:
self.craneAdviceLabel = DirectLabel(text=TTLocalizer.CashbotCraneAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1)
return
def __cleanupCraneAdvice(self):
if self.craneAdviceLabel:
self.craneAdviceLabel.destroy()
self.craneAdviceLabel = None
taskMgr.remove(self.craneAdviceName)
return
def __displayMagnetAdvice(self, task):
if self.magnetAdviceLabel == None:
self.magnetAdviceLabel = DirectLabel(text=TTLocalizer.CashbotMagnetAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.55), scale=0.1)
return
def __cleanupMagnetAdvice(self):
if self.magnetAdviceLabel:
self.magnetAdviceLabel.destroy()
self.magnetAdviceLabel = None
taskMgr.remove(self.magnetAdviceName)
return
def __watchControls(self, task):
if self.arrowHorz or self.arrowVert:
self.__moveCraneArcHinge(self.arrowHorz, self.arrowVert)
else:
self.__setMoveSound(None)
return Task.cont
def __incrementChangeSeq(self):
self.changeSeq = self.changeSeq + 1 & 255
def __controlPressed(self):
self.__cleanupMagnetAdvice()
self.__turnOnMagnet()
def __controlReleased(self):
self.__turnOffMagnet()
def __turnOnMagnet(self):
if not self.magnetOn:
self.__incrementChangeSeq()
self.magnetOn = 1
if not self.heldObject:
self.__activateSniffer()
def __turnOffMagnet(self):
if self.magnetOn:
self.magnetOn = 0
self.__deactivateSniffer()
self.releaseObject()
def __upArrow(self, pressed):
self.__incrementChangeSeq()
self.__cleanupCraneAdvice()
if pressed:
self.arrowVert = 1
elif self.arrowVert > 0:
self.arrowVert = 0
def __downArrow(self, pressed):
self.__incrementChangeSeq()
self.__cleanupCraneAdvice()
if pressed:
self.arrowVert = -1
elif self.arrowVert < 0:
self.arrowVert = 0
def __rightArrow(self, pressed):
self.__incrementChangeSeq()
self.__cleanupCraneAdvice()
if pressed:
self.arrowHorz = 1
elif self.arrowHorz > 0:
self.arrowHorz = 0
def __leftArrow(self, pressed):
self.__incrementChangeSeq()
self.__cleanupCraneAdvice()
if pressed:
self.arrowHorz = -1
elif self.arrowHorz < 0:
self.arrowHorz = 0
def __moveCraneArcHinge(self, xd, yd):
dt = globalClock.getDt()
h = self.arm.getH() - xd * self.rotateSpeed * dt
limitH = max(min(h, self.armMaxH), self.armMinH)
self.arm.setH(limitH)
y = self.crane.getY() + yd * self.slideSpeed * dt
limitY = max(min(y, self.craneMaxY), self.craneMinY)
atLimit = (limitH != h or limitY != y)
if atLimit:
now = globalClock.getFrameTime()
x = math.sin(now * 79) * 0.05
z = math.sin(now * 70) * 0.02
self.crane.setPos(x, limitY, z)
self.__setMoveSound(self.atLimitSfx)
else:
self.crane.setPos(0, limitY, 0)
self.__setMoveSound(self.craneMoveSfx)
def __setMoveSound(self, sfx):
if sfx != self.moveSound:
if self.moveSound:
self.moveSound.stop()
self.moveSound = sfx
if self.moveSound:
base.playSfx(self.moveSound, looping=1, volume=0.5)
def __activateSniffer(self):
if not self.snifferActivated:
self.sniffer.unstash()
base.cTrav.addCollider(self.sniffer, self.snifferHandler)
self.accept(self.snifferEvent, self.__sniffedSomething)
self.startFlicker()
self.snifferActivated = 1
def __deactivateSniffer(self):
if self.snifferActivated:
base.cTrav.removeCollider(self.sniffer)
self.sniffer.stash()
self.ignore(self.snifferEvent)
self.stopFlicker()
self.snifferActivated = 0
def startFlicker(self):
self.magnetSoundInterval.start()
self.lightning = []
for i in xrange(4):
t = float(i) / 3.0 - 0.5
l = self.craneGame.lightning.copyTo(self.gripper)
l.setScale(random.choice([1, -1]), 1, 5)
l.setZ(random.uniform(-5, -5.5))
l.flattenLight()
l.setTwoSided(1)
l.setBillboardAxis()
l.setScale(random.uniform(0.5, 1.0))
if t < 0:
l.setX(t - 0.7)
else:
l.setX(t + 0.7)
l.setR(-20 * t)
l.setP(random.uniform(-20, 20))
self.lightning.append(l)
taskMgr.add(self.__flickerLightning, self.flickerName)
def stopFlicker(self):
self.magnetSoundInterval.finish()
self.magnetLoopSfx.stop()
taskMgr.remove(self.flickerName)
for l in self.lightning:
l.detachNode()
self.lightning = None
return
def __flickerLightning(self, task):
for l in self.lightning:
if random.random() < 0.5:
l.hide()
else:
l.show()
return Task.cont
def __sniffedSomething(self, entry):
np = entry.getIntoNodePath()
doId = int(np.getNetTag('object'))
obj = base.cr.doId2do.get(doId)
if obj and obj.state != 'LocalDropped' and (obj.state != 'Dropped' or obj.craneId != self.doId):
obj.d_requestGrab()
obj.demand('LocalGrabbed', localAvatar.doId, self.doId)
def grabObject(self, obj):
if self.state == 'Off':
return
if self.heldObject != None:
self.releaseObject()
self.__deactivateSniffer()
obj.wrtReparentTo(self.gripper)
if obj.lerpInterval:
obj.lerpInterval.finish()
obj.lerpInterval = Parallel(obj.posInterval(ToontownGlobals.CashbotBossToMagnetTime, Point3(*obj.grabPos)), obj.quatInterval(ToontownGlobals.CashbotBossToMagnetTime, VBase3(obj.getH(), 0, 0)), obj.toMagnetSoundInterval)
obj.lerpInterval.start()
self.heldObject = obj
self.handler.setDynamicFrictionCoef(obj.craneFrictionCoef)
self.slideSpeed = obj.craneSlideSpeed
self.rotateSpeed = obj.craneRotateSpeed
if self.avId == localAvatar.doId and not self.magnetOn:
self.releaseObject()
return
def dropObject(self, obj):
if obj.lerpInterval:
obj.lerpInterval.finish()
obj.wrtReparentTo(render)
obj.lerpInterval = Parallel(obj.quatInterval(ToontownGlobals.CashbotBossFromMagnetTime, VBase3(obj.getH(), 0, 0), blendType='easeOut'))
obj.lerpInterval.start()
p1 = self.bottomLink.node().getPhysicsObject()
v = render.getRelativeVector(self.bottomLink, p1.getVelocity())
obj.physicsObject.setVelocity(v * 1.5)
if self.heldObject == obj:
self.heldObject = None
self.handler.setDynamicFrictionCoef(GameConsts.Settings.EmptyFrictionCoef.get())
self.slideSpeed = self.emptySlideSpeed
self.rotateSpeed = self.emptyRotateSpeed
return
def releaseObject(self):
if self.heldObject:
obj = self.heldObject
obj.d_requestDrop()
if obj.state == 'Grabbed':
obj.demand('LocalDropped', localAvatar.doId, self.doId)
def __hitTrigger(self, event):
pass
def setCraneGameId(self, craneGameId):
self.craneGameId = craneGameId
self.craneGame = base.cr.doId2do[craneGameId]
def setIndex(self, index):
self.index = index
def setState(self, state, avId):
if state == 'C':
self.demand('Controlled', avId)
elif state == 'F':
self.demand('Free')
else:
self.notify.error('Invalid state from AI: %s' % state)
def d_requestControl(self):
self.sendUpdate('requestControl')
def d_requestFree(self):
self.sendUpdate('requestFree')
def b_clearSmoothing(self):
self.d_clearSmoothing()
self.clearSmoothing()
def d_clearSmoothing(self):
self.sendUpdate('clearSmoothing', [0])
def clearSmoothing(self, bogus = None):
self.armSmoother.clearPositions(1)
for smoother in self.linkSmoothers:
smoother.clearPositions(1)
def reloadPosition(self):
self.armSmoother.clearPositions(0)
self.armSmoother.setPos(self.crane.getPos())
self.armSmoother.setHpr(self.arm.getHpr())
self.armSmoother.setPhonyTimestamp()
for linkNum in xrange(self.numLinks):
smoother = self.linkSmoothers[linkNum]
an, anp, cnp = self.activeLinks[linkNum]
smoother.clearPositions(0)
smoother.setPos(anp.getPos())
smoother.setPhonyTimestamp()
def doSmoothTask(self, task):
self.armSmoother.computeAndApplySmoothPosHpr(self.crane, self.arm)
for linkNum in xrange(self.numLinks):
smoother = self.linkSmoothers[linkNum]
anp = self.activeLinks[linkNum][1]
smoother.computeAndApplySmoothPos(anp)
return Task.cont
def startSmooth(self):
if not self.smoothStarted:
taskName = self.smoothName
taskMgr.remove(taskName)
self.reloadPosition()
taskMgr.add(self.doSmoothTask, taskName)
self.smoothStarted = 1
def stopSmooth(self):
if self.smoothStarted:
taskName = self.smoothName
taskMgr.remove(taskName)
self.forceToTruePosition()
self.smoothStarted = 0
def forceToTruePosition(self):
if self.armSmoother.getLatestPosition():
self.armSmoother.applySmoothPos(self.crane)
self.armSmoother.applySmoothHpr(self.arm)
self.armSmoother.clearPositions(1)
for linkNum in xrange(self.numLinks):
smoother = self.linkSmoothers[linkNum]
an, anp, cnp = self.activeLinks[linkNum]
if smoother.getLatestPosition():
smoother.applySmoothPos(anp)
smoother.clearPositions(1)
def setCablePos(self, changeSeq, y, h, links, timestamp):
self.changeSeq = changeSeq
if self.smoothStarted:
now = globalClock.getFrameTime()
local = globalClockDelta.networkToLocalTime(timestamp, now)
self.armSmoother.setY(y)
self.armSmoother.setH(h)
self.armSmoother.setTimestamp(local)
self.armSmoother.markPosition()
for linkNum in xrange(self.numLinks):
smoother = self.linkSmoothers[linkNum]
lp = links[linkNum]
smoother.setPos(*lp)
smoother.setTimestamp(local)
smoother.markPosition()
else:
self.crane.setY(y)
self.arm.setH(h)
def d_sendCablePos(self):
timestamp = globalClockDelta.getFrameNetworkTime()
links = []
for linkNum in xrange(self.numLinks):
an, anp, cnp = self.activeLinks[linkNum]
p = anp.getPos()
links.append((p[0], p[1], p[2]))
self.sendUpdate('setCablePos', [self.changeSeq,
self.crane.getY(),
self.arm.getH(),
links,
timestamp])
def stopPosHprBroadcast(self):
taskName = self.posHprBroadcastName
taskMgr.remove(taskName)
def startPosHprBroadcast(self):
taskName = self.posHprBroadcastName
self.b_clearSmoothing()
self.d_sendCablePos()
taskMgr.remove(taskName)
taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName)
def __posHprBroadcast(self, task):
self.d_sendCablePos()
taskName = self.posHprBroadcastName
taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName)
return Task.done
def enterOff(self):
self.clearCable()
self.root.detachNode()
def exitOff(self):
if self.craneGame:
self.setupCable()
self.root.reparentTo(render)
def enterControlled(self, avId):
self.avId = avId
toon = base.cr.doId2do.get(avId)
if not toon:
return
self.grabTrack = self.makeToonGrabInterval(toon)
if avId == localAvatar.doId:
self.craneGame.toCraneMode()
camera.reparentTo(self.hinge)
camera.setPosHpr(0, -20, -5, 0, -20, 0)
self.tube.stash()
localAvatar.setPosHpr(self.controls, 0, 0, 0, 0, 0, 0)
localAvatar.sendCurrentPosition()
self.__activatePhysics()
self.__enableControlInterface()
self.startPosHprBroadcast()
self.startShadow()
else:
self.startSmooth()
toon.stopSmooth()
self.grabTrack = Sequence(self.grabTrack, Func(toon.startSmooth))
self.grabTrack.start()
def exitControlled(self):
self.grabTrack.finish()
del self.grabTrack
if self.toon and not self.toon.isDisabled():
self.toon.loop('neutral')
self.toon.startSmooth()
self.stopWatchJoystick()
self.stopPosHprBroadcast()
self.stopShadow()
self.stopSmooth()
if self.avId == localAvatar.doId:
self.__disableControlInterface()
self.__deactivatePhysics()
self.tube.unstash()
camera.reparentTo(base.localAvatar)
camera.setPos(base.localAvatar.cameraPositions[0][0])
camera.setHpr(0, 0, 0)
self.__straightenCable()
def enterFree(self):
if self.fadeTrack:
self.fadeTrack.finish()
self.fadeTrack = None
self.restoreScaleTrack = Sequence(Wait(6), self.getRestoreScaleInterval())
self.restoreScaleTrack.start()
if self.avId == localAvatar.doId:
self.controlModel.setAlphaScale(0.3)
self.controlModel.setTransparency(1)
taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName)
self.fadeTrack = Sequence(Func(self.controlModel.setTransparency, 1), self.controlModel.colorScaleInterval(0.2, VBase4(1, 1, 1, 0.3)))
self.fadeTrack.start()
else:
self.trigger.unstash()
self.accept(self.triggerEvent, self.__hitTrigger)
self.avId = 0
return
def __allowDetect(self, task):
if self.fadeTrack:
self.fadeTrack.finish()
self.fadeTrack = Sequence(self.controlModel.colorScaleInterval(0.2, VBase4(1, 1, 1, 1)), Func(self.controlModel.clearColorScale), Func(self.controlModel.clearTransparency))
self.fadeTrack.start()
self.trigger.unstash()
self.accept(self.triggerEvent, self.__hitTrigger)
def exitFree(self):
if self.fadeTrack:
self.fadeTrack.finish()
self.fadeTrack = None
self.restoreScaleTrack.pause()
del self.restoreScaleTrack
taskMgr.remove(self.triggerName)
self.controlModel.clearColorScale()
self.controlModel.clearTransparency()
self.trigger.stash()
self.ignore(self.triggerEvent)
return
def enterMovie(self):
self.__activatePhysics()
def exitMovie(self):
self.__deactivatePhysics()
self.__straightenCable()
if __dev__:
def _handleEmptyFrictionCoefChanged(self, coef):
self.handler.setDynamicFrictionCoef(coef)
def _handleRopeLinkMassChanged(self, mass):
for an, anp, cnp in self.activeLinks:
an.getPhysicsObject().setMass(mass)
def _handleMagnetMassChanged(self, mass):
pass