toontown-just-works/toontown/coghq/DistributedCashbotBossCrane.py

913 lines
34 KiB
Python
Raw Permalink Normal View History

2024-07-07 18:08:39 -05:00
from direct.gui.DirectGui import *
from panda3d.core import *
from direct.interval.IntervalGlobal import *
from direct.distributed.ClockDelta import *
from direct.fsm import FSM
from direct.distributed import DistributedObject
from direct.showutil import Rope
from direct.showbase import PythonUtil
from direct.task import Task
from toontown.toonbase import ToontownGlobals
from toontown.toonbase import TTLocalizer
from otp.otpbase import OTPGlobals
from otp.nametag import NametagGlobals
import random
class DistributedCashbotBossCrane(DistributedObject.DistributedObject, FSM.FSM):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedCashbotBossCrane')
firstMagnetBit = 21
craneMinY = 8
craneMaxY = 25
armMinH = -45
armMaxH = 45
shadowOffset = 1
emptyFrictionCoef = 0.1
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, 'DistributedCashbotBossCrane')
self.boss = 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.closeButton = 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(*ToontownGlobals.CashbotBossCranePosHprs[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.boss.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.boss.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.boss.craneArm.copyTo(self.crane)
self.boss.cranes[self.index] = self
def disable(self):
DistributedObject.DistributedObject.disable(self)
del self.boss.cranes[self.index]
self.cleanup()
def cleanup(self):
if self.state != 'Off':
self.demand('Off')
self.boss = 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.boss.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.boss.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(self.emptyFrictionCoef)
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.boss.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.boss.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.boss.geom.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.boss.geom)
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)
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.closeButton = DirectButton(
parent=base.a2dBottomRight,
image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'),
gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')),
relief=None, scale=2, text=TTLocalizer.CashbotCraneLeave, text_scale=0.04,
text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(-0.25, 0, 0.175),
command=self.__exitCrane)
self.accept('escape', self.__exitCrane)
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.setOnscreenChatForced(1)
self.arrowVert = 0
self.arrowHorz = 0
return
def __disableControlInterface(self):
self.__turnOffMagnet()
if self.closeButton:
self.closeButton.destroy()
self.closeButton = None
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.setOnscreenChatForced(0)
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 __exitCrane(self):
if self.closeButton:
self.closeButton.destroy()
self.closeButton = DirectLabel(
parent=base.a2dBottomRight, relief=None,
text=TTLocalizer.CashbotCraneLeaving, pos=(-0.25, 0, 0.125),
text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1))
self.__cleanupCraneAdvice()
self.__cleanupMagnetAdvice()
self.d_requestFree()
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.boss.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()
if np.hasNetTag('object'):
doId = int(np.getNetTag('object'))
else:
self.notify.warning("%s missing 'object' tag" % np)
return
self.notify.debug('__sniffedSomething %d' % doId)
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(self.emptyFrictionCoef)
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):
self.d_requestControl()
def setBossCogId(self, bossCogId):
self.bossCogId = bossCogId
self.boss = base.cr.doId2do[bossCogId]
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:
if len(links) > self.numLinks:
self.notify.warning('Links passed in is greater than total number of links')
return
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.boss:
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.boss.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()
self.accept('exitCrane', self.__exitCrane)
else:
self.startSmooth()
toon.stopSmooth()
self.grabTrack = Sequence(self.grabTrack, Func(toon.startSmooth))
self.grabTrack.start()
def exitControlled(self):
self.ignore('exitCrane')
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)
if self.cr:
place = self.cr.playGame.getPlace()
if place and hasattr(place, 'fsm'):
if place.fsm.getCurrentState().getName() == 'crane':
place.setState('finalBattle')
self.boss.toFinalBattleMode()
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()