from panda3d.core import * from direct.distributed.ClockDelta import * from direct.interval.IntervalGlobal import * from direct.gui.DirectGui import * from direct.fsm import FSM from direct.distributed import DistributedSmoothNode from direct.interval.IntervalGlobal import * from toontown.toonbase.PythonUtil import clampScalar from otp.otpbase import OTPGlobals from otp.avatar import ShadowCaster from toontown.racing import Kart from toontown.racing.KartDNA import * from toontown.toonbase import ToontownGlobals from toontown.toonbase import TTLocalizer from toontown.effects.Drift import Drift from toontown.effects.Sparks import Sparks from direct.interval.ProjectileInterval import * from toontown.battle.BattleProps import * import random from direct.showbase.PythonUtil import randFloat from direct.task.Task import Task from toontown.nametag import NametagGlobals import math iceTurnFactor = 0.25 iceAccelFactor = 0.4 class DistributedVehicle(DistributedSmoothNode.DistributedSmoothNode, Kart.Kart, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedVehicle') cheatFactor = 1.0 proRacer = 0 physicsCalculationsPerSecond = 60 maxPhysicsDt = 1.0 physicsDt = 1.0 / float(physicsCalculationsPerSecond) maxPhysicsFrames = maxPhysicsDt * physicsCalculationsPerSecond maxSpeed = 200 * cheatFactor turnRatio = 1.0 / 0.025 * math.sqrt(cheatFactor) accelerationMult = 35 accelerationBase = 20 if proRacer: accelerationMult = 35 accelerationBase = 30 surfaceModifiers = {'asphalt': {'shake': 0.1, 'driftMin': 65, 'windResistance': 0.2, 'particleColor': Vec4(0.7, 0.7, 0.7, 1.0)}, 'gravel': {'shake': 0.2, 'driftMin': 65, 'windResistance': 0.2, 'particleColor': Vec4(0.53, 0.53, 0.53, 1.0)}, 'dirt': {'shake': 0.4, 'driftMin': 35, 'windResistance': 0.3, 'particleColor': Vec4(1.0, 1.0, 1.0, 1.0)}, 'grass': {'shake': 0.8, 'driftMin': 15, 'windResistance': 0.4, 'particleColor': Vec4(0.8, 0.42, 0.8, 1.0)}, 'ice': {'shake': 0.0, 'driftMin': 0, 'windResistance': 0.01, 'particleColor': Vec4(1.0, 1.0, 1.0, 1.0)}, '': {'shake': 0, 'driftMin': 1, 'windResistance': 0.2, 'particleColor': Vec4(1.0, 1.0, 1.0, 1.0)}} SFX_BaseDir = 'phase_6/audio/sfx/' SFX_WallHits = [SFX_BaseDir + 'KART_Hitting_Wood_Fence.ogg', SFX_BaseDir + 'KART_Hitting_Wood_Fence_1.ogg', SFX_BaseDir + 'KART_Hitting_Metal_Fence.ogg', SFX_BaseDir + 'KART_Hitting_Wall.ogg'] SFX_SkidLoop_Grass = SFX_BaseDir + 'KART_Skidding_On_Grass.ogg' SFX_SkidLoop_Asphalt = SFX_BaseDir + 'KART_Skidding_On_Asphalt.ogg' SFX_TurboStart = SFX_BaseDir + 'KART_turboStart.ogg' SFX_TurboLoop = SFX_BaseDir + 'KART_turboLoop.ogg' AvId2kart = {} @classmethod def getKartFromAvId(cls, avId): return cls.AvId2kart.get(avId) def __init__(self, cr): DistributedSmoothNode.DistributedSmoothNode.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedVehicle') Kart.Kart.__init__(self) if base.config.GetBool('want-racer', 0) == 1: DistributedVehicle.proRacer = 1 DistributedVehicle.accelerationMult = 35 DistributedVehicle.accelerationBase = 30 self.speedometer = None self.speedGauge = None self.leanAmount = 0 self.leftHeld = 0 self.stopped = False self.rightHeld = 0 self.canRace = False self.groundType = 'gravel' self.offGround = 0 self.turbo = False self.ownerId = 0 self.cameraTrack = None self.curSpeed = 0 self.acceleration = 0 self.imHitMult = 1 self.skidding = False self.hittingWall = 0 base.kart = self self.wipeOut = None self.gagMovie = None self.spinAnim = None self.wrongWay = False self.wallCollideTrack = None self.wheelMaxTurn = 1.0 self.wheelMinTurn = 0.15 self.speedMaxTurn = 90 self.speedMinTurn = 300 self.wheelTurnTime = 0.6 self.wheelReturnTime = 0.3 self.wheelFightTime = 0.2 self.wheelPosition = 0.0 self.outPutCounter = 0 self.proCameraHeading = 0 self.proCameraDummyNode = None self.cameraArmNode = None self.armSwingSpeedPerp = 0.2 self.armSwingSpeedPara = 0.7 self.cameraTightener = 3.0 self.cameraArmBase = 0 self.cameraArmExtend = 20 self.pieCount = 0 self.numPieChunks = 6 self.pieSlideSpeed = [] for piece in xrange(self.numPieChunks): self.pieSlideSpeed.append(randFloat(0.0, 0.2)) self.wantSmoke = ConfigVariableBool('want-kart-smoke', 1).getValue() self.wantSparks = ConfigVariableBool('want-kart-sparks', 1).getValue() self.__loadTextures() return def __loadTextures(self): self.pieSplatter = loader.loadModel('phase_6/models/karting/pie_splat_1.bam') def announceGenerate(self): DistributedSmoothNode.DistributedSmoothNode.announceGenerate(self) self.generateKart() self.name = self.uniqueName('vehicle') self.posHprBroadcastName = self.uniqueName('vehicleBroadcast') self.LODnode.forceSwitch(self.LODnode.getHighestSwitch()) self.cameraNode = NodePath('cameraNode') self.cameraNode.reparentTo(self) if self.proRacer: self.cameraArmNode = render.attachNewNode('cameraArm') self.cameraArmNode.reparentTo(self) self.cameraNode.reparentTo(self.cameraArmNode) self.proCameraDummyNode = render.attachNewNode('proCameraDummy') self.proCameraDummyNode.reparentTo(render) self.localVehicle = False if hasattr(base, 'localAvatar'): self.localVehicle = self.ownerId == base.localAvatar.doId if self.localVehicle: self.setupPhysics() self.setupParticles() self.__enableCollisions() self.forward = NodePath('forward') self.forward.setPos(0, 1, 0) self.wallHitsSfx = [] for wallHit in self.SFX_WallHits: self.wallHitsSfx.append(base.loadSfx(wallHit)) self.skidLoopAsphaltSfx = base.loadSfx(self.SFX_SkidLoop_Asphalt) self.skidLoopAsphaltSfx.setLoop() self.skidLoopGrassSfx = base.loadSfx(self.SFX_SkidLoop_Grass) self.skidLoopGrassSfx.setLoop() self.turboStartSfx = base.loadSfx(self.SFX_TurboStart) self.turboLoopSfx = base.loadSfx(self.SFX_TurboLoop) self.turboLoopSfx.setLoop() self.forward.reparentTo(self.geom[0]) self.anvil = globalPropPool.getProp('anvil') self.anvil.setScale(5) self.anvil.reparentTo(hidden) self.anvil.setColor(1, 1, 1, 1) self.anvil.setTransparency(1) self.reparentTo(render) def setupPhysics(self): self.__setupCollisions() self.physicsMgr = PhysicsManager() self.physicsEpoch = globalClock.getFrameTime() self.lastPhysicsFrame = 0 integrator = LinearEulerIntegrator() self.physicsMgr.attachLinearIntegrator(integrator) fn = ForceNode('windResistance') fnp = NodePath(fn) fnp.reparentTo(render) windResistance = LinearFrictionForce(0.2) fn.addForce(windResistance) self.physicsMgr.addLinearForce(windResistance) self.windResistance = windResistance fn = ForceNode('engine') fnp = NodePath(fn) fnp.reparentTo(self) engine = LinearVectorForce(0, 0, 0) fn.addForce(engine) self.physicsMgr.addLinearForce(engine) self.engine = engine def disable(self): DistributedVehicle.AvId2kart.pop(self.ownerId) self.finishMovies() self.request('Off') self.stopSkid() self.stopSmooth() if self.localVehicle: self.__disableCollisions() self.__undoCollisions() self.physicsMgr.clearLinearForces() self.detachNode() DistributedSmoothNode.DistributedSmoothNode.disable(self) taskMgr.remove('slidePies') def delete(self): self.stopSmooth() Kart.Kart.delete(self) DistributedSmoothNode.DistributedSmoothNode.delete(self) if self.localVehicle: self.ignoreAll() if hasattr(self, 'piePieces'): for piece in self.piePieces: del piece def getVelocity(self): return self.actorNode.getPhysicsObject().getVelocity() def __updateWallCollision(self, entry = None): vol = self.curSpeed / 160 for wallHit in self.wallHitsSfx: wallHit.setVolume(vol) def __wallCollisionStart(self, entry): self.entry = entry self.__wallCollisionStop() self.hittingWall = 1 hitToPlay = random.randrange(0, len(self.wallHitsSfx)) self.wallCollideTrack = Parallel(Func(self.wallHitsSfx[hitToPlay].play)) self.__updateWallCollision() self.wallCollideTrack.start() curSpeed = self.actorNode.getPhysicsObject().getVelocity().length() if self.wantSparks and curSpeed > 10: if entry.getSurfaceNormal(self)[0] < 0: self.fireSparkParticles('right') else: self.fireSparkParticles('left') def __wallCollisionStop(self, entry = None): self.hittingWall = 0 if self.wallCollideTrack: self.wallCollideTrack.pause() def __setupCollisions(self): self.cWallTrav = CollisionTraverser('KartWall') self.cWallTrav.setRespectPrevTransform(True) self.collisionNode = CollisionNode(self.uniqueName('vehicle')) self.collisionNode.setFromCollideMask(OTPGlobals.WallBitmask) self.collisionNode.setIntoCollideMask(ToontownGlobals.PieBitmask) cs = CollisionSphere(0, 0, 4, 4) self.collisionNode.addSolid(cs) self.collisionNodePath = NodePath(self.collisionNode) self.wallHandler = PhysicsCollisionHandler() self.wallHandler.setStaticFrictionCoef(0.0) self.wallHandler.setDynamicFrictionCoef(0.1) self.wallHandler.addCollider(self.collisionNodePath, self) self.wallHandler.setInPattern('enterWallCollision') self.wallHandler.setOutPattern('exitWallCollision') self.cWallTrav.addCollider(self.collisionNodePath, self.wallHandler) self.accept('enterWallCollision', self.__wallCollisionStart) self.accept('exitWallCollision', self.__wallCollisionStop) cRay = CollisionRay(0.0, 0.0, 40000.0, 0.0, 0.0, -1.0) cRayNode = CollisionNode(self.uniqueName('vehicle-FloorRay')) cRayNode.addSolid(cRay) cRayNode.setFromCollideMask(OTPGlobals.FloorBitmask) cRayNode.setIntoCollideMask(BitMask32.allOff()) self.cRayNodePath = self.attachNewNode(cRayNode) self.lifter = CollisionHandlerGravity() self.lifter.setGravity(32.174 * 3.0) self.lifter.addInPattern('floorCollision') self.lifter.addAgainPattern('floorCollision') self.lifter.setOffset(OTPGlobals.FloorOffset) self.lifter.setReach(40.0) self.lifter.addCollider(self.cRayNodePath, self) base.cTrav.addCollider(self.cRayNodePath, self.lifter) self.accept('floorCollision', self.__groundCollision) self.accept('imIn-banana', self.hitBanana) base.localAvatar.collisionsOff() def __undoCollisions(self): base.cTrav.removeCollider(self.cRayNodePath) base.localAvatar.collisionsOn() def __groundCollision(self, entry): ground = entry.getIntoNodePath() if ground.getNetTag('surface') == '': return self.groundType = ground.getNetTag('surface') def __enableCollisions(self): self.cQueue = [] self.cRays = NodePath('stickVehicleToFloor') self.cRays.reparentTo(self.geom[0]) for wheelNode in self.wheelBases: rayNode = CollisionNode(wheelNode.getName()) x = wheelNode.getX() y = wheelNode.getY() ray = CollisionRay(x, y, 40000.0, 0.0, 0.0, -1.0) rayNode.addSolid(ray) rayNode.setFromCollideMask(OTPGlobals.FloorBitmask) rayNode.setIntoCollideMask(BitMask32.allOff()) rayNodePath = self.cRays.attachNewNode(rayNode) cQueue = CollisionHandlerQueue() self.cWallTrav.addCollider(rayNodePath, cQueue) self.cQueue.append(cQueue) self.collisionNodePath.reparentTo(self) def setupLapCollisions(self): self.lapBit = BitMask32(32768) self.lapHandler = CollisionHandlerEvent() self.lapHandler.addInPattern('imIn-%in') self.cSphere = CollisionSphere(0, 0, 0, 3) self.lapNode = CollisionNode('lapChecker') self.lapNode.addSolid(self.cSphere) self.lapNode.setIntoCollideMask(BitMask32.allOff()) self.lapNode.setFromCollideMask(self.lapBit) self.lapNodePath = NodePath(self.lapNode) self.lapNodePath.reparentTo(self) self.cWallTrav.addCollider(self.lapNodePath, self.lapHandler) def __disableCollisions(self): self.ignore('imIn-startLine') self.ignore('imIn-quarterLine') self.ignore('imIn-midLine') def __handleCollisionSphereEnter(self, collEntry = None): self.d_requestControl() def setupParticles(self): if self.wantSmoke: self.setupDriftParticles() if self.wantSparks: self.setupSparkParticles() def updateParticles(self, leanAmount): if self.wantSmoke: self.updateDriftParticles(leanAmount) def cleanupParticles(self): if self.wantSmoke: self.cleanupDriftParticles() if self.wantSparks: self.cleanupSparkParticles() def setupDriftParticles(self): smokeMount = self.geom[0].attachNewNode('Smoke Effect') backLeft = smokeMount.attachNewNode('Back Left Smokemount') backLeft.setPos(self.geom[0].find('**/' + self.wheelData[self.LRWHEEL]['node']).getPos() + Vec3(-0.25, -1.0, -0.5)) backRight = smokeMount.attachNewNode('Back Right Smokemount') backRight.setPos(self.geom[0].find('**/' + self.wheelData[self.RRWHEEL]['node']).getPos() + Vec3(0.25, -1.0, -0.5)) driftEffects = (Drift(backLeft, backLeft), Drift(backRight, backRight)) for x in driftEffects: x.start() self.drifts = driftEffects self.driftSeq = Sequence(Func(backLeft.show), Func(backRight.show), Wait(1000000), Func(self.drifts[0].effect.getParticlesNamed('particles-1').getRenderer().setColor, Vec4(1.0, 1.0, 1.0, 1.0)), Func(self.drifts[1].effect.getParticlesNamed('particles-1').getRenderer().setColor, Vec4(1.0, 1.0, 1.0, 1.0)), Func(backLeft.hide), Func(backRight.hide)) self.driftSeqStarted = False self.driftParticleForces = [ x.effect.getParticlesNamed('particles-1').getLinearForce(0) for x in self.drifts ] self.smokeMount = smokeMount backLeft.hide() backRight.hide() def updateDriftParticles(self, leanAmount): for x in self.driftParticleForces: x.setAmplitude(leanAmount * 30) if self.skidding and not self.driftSeqStarted: self.driftSeqStarted = True self.driftSeq.start() elif not self.skidding and self.driftSeqStarted: self.driftSeqStarted = False self.driftSeq.finish() def cleanupDriftParticles(self): self.driftSeq.finish() for x in self.drifts: x.destroy() self.smokeMount.removeNode() del self.driftSeq del self.driftParticleForces del self.drifts del self.smokeMount def setupSparkParticles(self): bodyType = self.kartDNA[KartDNA.bodyType] endPts = KartDict[bodyType][7] self.sparkMount = self.geom[0].attachNewNode('Spark Effect') left = self.sparkMount.attachNewNode('Left Sparkmount') left.setPos((self.geom[0].find('**/' + self.wheelData[self.LFWHEEL]['node']).getPos() + self.geom[0].find('**/' + self.wheelData[self.LRWHEEL]['node']).getPos()) / 2.0 + Vec3(0.0, -1.0, 1.0)) left.setScale(0.5) right = self.sparkMount.attachNewNode('Right Sparkmount') right.setPos((self.geom[0].find('**/' + self.wheelData[self.RFWHEEL]['node']).getPos() + self.geom[0].find('**/' + self.wheelData[self.RRWHEEL]['node']).getPos()) / 2.0 + Vec3(0.0, -1.0, 1.0)) right.setScale(0.5) self.sparks = (Sparks(right, self.sparkMount), Sparks(left, self.sparkMount)) self.sparks[0].effect.getParticlesNamed('particles-1').getEmitter().setEndpoint1(endPts[0]) self.sparks[0].effect.getParticlesNamed('particles-1').getEmitter().setEndpoint2(endPts[1]) self.sparks[0].effect.getParticlesNamed('particles-1').getLinearForce(0).setAmplitude(-50) self.sparks[1].effect.getParticlesNamed('particles-1').getEmitter().setEndpoint1(Point3(-endPts[0][0], endPts[0][1], endPts[0][2])) self.sparks[1].effect.getParticlesNamed('particles-1').getEmitter().setEndpoint2(Point3(-endPts[1][0], endPts[1][1], endPts[1][2])) self.sparks[1].effect.getParticlesNamed('particles-1').getLinearForce(0).setAmplitude(50) def fireSparkParticles(self, side): spark = self.sparks[{'right': 0, 'left': 1}[side]] if not spark.effect.isEnabled(): spark.effect.getParticlesNamed('particles-1').setBirthRate(0.02) spark.start() taskMgr.doMethodLater(0.25, self.stopSparkParticles, 'sparkTimer-' + side, extraArgs=[side]) def stopSparkParticles(self, side = None): sides = {0: 'right', 1: 'left'} if side == None: for x in sides.keys(): self.sparks[x].effect.getParticlesNamed('particles-1').setBirthRate(1000) taskMgr.doMethodLater(0.75, self.sparks[x].stop, 'stopSparks-' + sides[x], extraArgs=[]) else: spark = self.sparks[{'right': 0, 'left': 1}[side]] spark.effect.getParticlesNamed('particles-1').setBirthRate(1000) taskMgr.doMethodLater(0.75, spark.stop, 'stopSparks-' + side, extraArgs=[]) return def cleanupSparkParticles(self): taskMgr.remove('sparkTimer-left') taskMgr.remove('sparkTimer-right') taskMgr.remove('stopSparks-left') taskMgr.remove('stopSparks-right') for x in self.sparks: x.destroy() self.sparkMount.removeNode() del self.sparks del self.sparkMount def setState(self, state, avId): self.notify.debug('SetState received: %s avId: %s' % (state, avId)) if state == 'C': self.demand('Controlled', avId) elif state == 'P': self.demand('Parked') else: self.notify.error('Invalid state from AI: %s' % state) def d_requestControl(self): self.sendUpdate('requestControl') def d_requestParked(self): self.sendUpdate('requestParked') def enterOff(self): pass def exitOff(self): pass def enterParked(self): pass def exitParked(self): pass def enterControlled(self, avId): self.avId = avId self.toon = base.cr.doId2do.get(avId, None) if self.toon: self.toon.stopSmooth() self.toon.stopPosHprBroadcast() for feet in self.toon.getPieces(('legs', 'feet')): feet.hide() self.toon.reparentTo(self.toonSeat) self.toon.dropShadow.hide() self.notify.debug('setting pos of toon%s' % self.toon.doId) self.toon.setPosHpr(0, 0, 0, 0, 0, 0) self.toon.loop('sit') if self.toon.doId == localAvatar.doId: self.notify.debug('calling send currentPosition') self.toon.sendCurrentPosition() self.doHeadScale(self.toon, 1.75) self.toon.setShear(0, 0, 0) NametagGlobals.setForceOnscreenChat(True) if self.localVehicle: camera.reparentTo(self.cameraNode) camera.setPosHpr(0, -33, 16, 0, -10, 0) self.physicsMgr.attachPhysicalNode(self.node()) self.__enableControlInterface() self.__createPieWindshield() self.startPosHprBroadcast() self.engineSfxTrack = self.generateEngineStartTrack() self.engineSfxTrack.start() else: self.startSmooth() taskName = 'updateNonlocalVehicle-%s' % avId self.updateNonLocalTask = taskMgr.add(self.__updateNonlocalVehicle, taskName) return def exitControlled(self): if self.localVehicle: self.stopPosHprBroadcast() self.__disableControlInterface() self.physicsMgr.removePhysicalNode(self.node()) self.cleanupParticles() camera.reparentTo(localAvatar) camera.setPos(localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.engineSfxTrack.finish() self.engineSfxTrack = self.generateEngineStopTrack() else: self.stopSmooth() taskMgr.remove(self.updateNonLocalTask) if self.toon and not self.toon.isDisabled() and not self.toon.isEmpty(): self.toon.dropShadow.show() self.doHeadScale(self.toon, None) self.toon.setPosHpr(self.geom[0], 0, 8, 0, 0, 0, 0) for feet in self.toon.getPieces(('legs', 'feet')): feet.show() self.toon.reparentTo(render) self.toon.loop('neutral') self.toon.startSmooth() NametagGlobals.setForceOnscreenChat(False) base.camLens.setMinFov(settings['fov']/(4./3.)) def doHeadScale(self, model, scale): if scale == None: scale = ToontownGlobals.toonHeadScales[model.style.getAnimal()] base.localAvatar.clearCheesyEffect() for hi in xrange(model.headParts.getNumPaths()): head = model.headParts[hi] head.setScale(scale) return def __createPieWindshield(self): self.piePieces = [] for piece in xrange(self.numPieChunks): self.piePieces.append(DirectLabel(relief=None, pos=(0.0, 0.0, 0.0), image=self.pieSplatter, image_scale=(0.5, 0.5, 0.5), text=' ', text_scale=0.18, text_fg=(1, 0, 1, 1), text_pos=(-0.0, 0.0, 0), text_font=ToontownGlobals.getSignFont(), textMayChange=1)) self.piePieces[piece].hide() return def showPieces(self): xRange = 0.3 for piece in self.piePieces: piece.setPos(randFloat(-xRange, xRange), randFloat(-0.1, 3.5), randFloat(-0.9, 0.9)) piece.setScale(randFloat(1.1, 2.0), 1, randFloat(1.1, 2.0)) piece.show() xRange += 2.5 / self.numPieChunks for piece in xrange(self.numPieChunks): self.pieSlideSpeed[piece] = randFloat(0.0, 0.2) def splatPie(self): self.showPieces() if self.pieCount == 0: self.pieCount = 15 taskMgr.doMethodLater(1, self.__countPies, ' ', extraArgs=[]) taskMgr.add(self.__slidePies, 'slidePies', priority=25) else: self.pieCount = 15 def __countPies(self): if self.pieCount > 0: taskMgr.doMethodLater(1, self.__countPies, ' ', extraArgs=[]) self.pieCount -= 1 else: for piece in self.piePieces: piece.hide() def __slidePies(self, optional = None): dt = globalClock.getDt() for piece in xrange(self.numPieChunks): self.pieSlideSpeed[piece] += randFloat(0.0, 0.25 * dt) pieSpeed = self.pieSlideSpeed[piece] * dt self.piePieces[piece].setPos(self.piePieces[piece].getPos()[0], self.piePieces[piece].getPos()[1] - pieSpeed, self.piePieces[piece].getPos()[2] - pieSpeed) if self.pieCount == 0: return Task.done else: return Task.cont def __enableControlInterface(self): if self.canRace: self.enableControls() taskMgr.remove('watchVehicleControls') taskMgr.add(self.__watchControls, 'watchVehicleControls', priority=25) if not self.speedometer: cm = CardMaker('speed') cm.setFrame(-0.5, 0.5, -0.5, 0.5) self.speedometerImages = base.a2dBottomRight.attachNewNode('SpeedometerImages') self.speedometerImages.setTransparency(True) self.speedometerImages.setPos(-0.1, 0.0, 0.03) self.speedometerImages.setScale(0.75) m = loader.loadModel('phase_6/models/karting/speedometer') if self.getBodyColor() == InvalidEntry: bodyColor = getDefaultColor() else: bodyColor = getAccessory(self.getBodyColor()) if self.getAccessoryColor() == InvalidEntry: accColor = getDefaultColor() else: accColor = getAccessory(self.getAccessoryColor()) self.speedometerImages.attachNewNode(m.find('**/*gauge').node()).setColorScale(1, 1, 1, 1) self.speedGauge = self.speedometerImages.attachNewNode(m.find('**/*spin').node()) self.speedGauge.setColor(1, 1, 1, 1) c = (Vec4(1, 1, 1, 1) + accColor) / 2.0 c.setW(1.0) self.speedometerImages.attachNewNode(m.find('**/*face').node()).setColorScale(c) c = (Vec4(2, 2, 2, 2) - accColor) / 2.0 c = (bodyColor + Vec4(1, 1, 1, 1)) / 2.0 c.setW(1.0) self.speedometerImages.attachNewNode(m.find('**/*tics').node()).setColorScale(c) c = (bodyColor + Vec4(1, 1, 1, 1)) / 2.0 c.setW(1.0) self.speedometerImages.attachNewNode(m.find('**/*ring').node()).setColorScale(c) self.speedometer = DirectLabel(relief=None, pos=(-0.1, 0.0, 0.03), text=str(0), text_scale=0.18, text_fg=bodyColor, text_pos=(-0.04, 0.02, 0), text_font=ToontownGlobals.getSignFont()) self.speedometer.reparentTo(base.a2dBottomRight) else: self.showSpeedometer() self.arrowVert = 0 self.arrowHorz = 0 return def showSpeedometer(self): if self.speedometer: self.speedometer.show() self.speedometerImages.show() def hideSpeedometer(self): if self.speedometer: self.speedometer.hide() self.speedometerImages.hide() def __disableControlInterface(self): self.hideSpeedometer() self.disableControls() self.stopSmooth() taskMgr.remove('watchVehicleControls') def __deleteControlInterface(self): if self.speedometer: self.speedometer.destroy() self.speedometer = None self.speedGauge = None self.speedometerImages.removeNode() self.speedometerImages = None return def setTurbo(self, setting): self.turbo = setting if self.turbo: self.turboLoopSfx.play() else: self.turboLoopSfx.stop() def interruptTurbo(self): self.__stopTurbo() if self.cameraTrack: self.cameraTrack.finish() self.cameraTrack = None return def startTurbo(self): newCameraPos = Point3(0, -25, 16) newCameraFov = 70 turboDuration = 3 startFov = settings['fov']/(4./3.) if self.cameraTrack: self.cameraTrack.pause() cameraZoomIn = Parallel(LerpPosInterval(camera, 2, newCameraPos), LerpFunc(base.camLens.setMinFov, fromData=startFov, toData=newCameraFov, duration=2)) cameraToNormal = Parallel(LerpPosInterval(camera, 1, Point3(0, -33, 16), newCameraPos), LerpFunc(base.camLens.setMinFov, fromData=newCameraFov, toData=startFov, duration=1)) self.cameraTrack = Sequence(Func(self.turboStartSfx.play), cameraZoomIn, Func(lambda : self.setTurbo(True)), Wait(turboDuration), Func(self.__stopTurbo), cameraToNormal) self.cameraTrack.start() def __stopTurbo(self, task = None): self.setTurbo(False) def __controlPressed(self): self.__throwGag() def __controlReleased(self): pass def __upArrow(self, pressed): if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): if pressed: self.arrowHorz = 1 self.rightHeld += 1 elif self.arrowHorz > 0: self.arrowHorz = 0 self.rightHeld = 0 def __leftArrow(self, pressed): if pressed: self.arrowHorz = -1 self.leftHeld += 1 elif self.arrowHorz < 0: self.arrowHorz = 0 self.leftHeld = 0 def __updateNonlocalVehicle(self, task = None): self.curSpeed = self.smoother.getSmoothForwardVelocity() rotSpeed = -1 * self.smoother.getSmoothRotationalVelocity() self.leanAmount = self.curSpeed * rotSpeed / 500.0 self.leanAmount = clampScalar(self.leanAmount, -10, 10) self.__animate() return Task.cont def __animate(self): speed = self.curSpeed self.spinWheels(speed / 10) enginePitch = clampScalar(speed / 120.0, 0.5, 15) self.kartLoopSfx.setPlayRate(enginePitch) if not self.localVehicle: dist = (self.getPos() - localAvatar.getPos()).length() if self.localVehicle: if self.lifter.isOnGround(): if self.offGround > 10: kart = self.geom[0].find('**/main*') bumpDown1 = kart.posInterval(0.1, Vec3(0, 0, -1)) bumpUp1 = kart.posInterval(0.15, Vec3(0, 0, 0)) bumpDown2 = kart.posInterval(0.5, Vec3(0, 0, -.4)) bumpUp2 = kart.posInterval(0.7, Vec3(0, 0, 0)) bumpSeq = Sequence(bumpDown1, bumpUp1, bumpDown2, bumpUp2) bumpSeq.start() self.offGround = 0 else: self.offGround += 1 if self.offGround == 0: modifier = self.surfaceModifiers[self.groundType]['shake'] * (speed / 50.0) else: modifier = 1 roll = self.leanAmount * 1.5 roll += (random.random() * 2 - 1) * modifier pitch = self.acceleration * -.005 pitch += (random.random() * 2 - 1) * modifier self.rollSuspension(roll) self.pitchSuspension(pitch) return Task.cont def __clampPosition(self): retVal = False if self.getX() < -3276: self.notify.debug('clamping X %d' % self.getX()) self.setX(-3276) retVal = True if self.getX() > 3276: self.notify.debug('clamping X %d' % self.getX()) self.setX(3276) retVal = True if self.getY() < -3276: self.notify.debug('clamping Y %d' % self.getY()) self.setY(-3276) retVal = True if self.getY() > 3276: self.notify.debug('clamping Y %d' % self.getY()) self.setY(3276) retVal = True if self.getZ() < -3276: self.notify.debug('clamping Z %d' % self.getZ()) self.setZ(-3276) retVal = True if self.getZ() > 3276: self.notify.debug('clamping Z %d' % self.getZ()) self.setZ(3276) retVal = True return retVal def amIClampingPosition(self): return self.getX() == -3276 or self.getX() == 3276 or self.getY() == -3276 or self.getY() == 3276 or self.getZ() == -3276 or self.getZ() == 3276 def __computeTurnRatio(self, speed): effectiveSpeed = speed if effectiveSpeed > self.speedMinTurn: effectiveSpeed = self.speedMinTurn if effectiveSpeed < self.speedMaxTurn: turnRatio = 1.0 * effectiveSpeed elif effectiveSpeed >= self.speedMaxTurn: turnRatio = 1.0 * (effectiveSpeed * (self.speedMaxTurn / speed)) def __updateWheelPos(self, dt, curSpeed): ratioIntoMax = (curSpeed - self.speedMinTurn) / (self.speedMaxTurn - self.speedMinTurn) if ratioIntoMax > 1.0: ratioIntoMax = 1.0 if ratioIntoMax < 0.0: ratioIntoMax = 0.0 maxWheelDeflection = self.wheelMaxTurn * ratioIntoMax + self.wheelMinTurn * (1.0 - ratioIntoMax) if self.wheelPosition * self.arrowHorz > 0: self.wheelPosition += self.arrowHorz * dt / self.wheelTurnTime else: self.wheelPosition += self.arrowHorz * dt / self.wheelFightTime if not self.arrowHorz: if self.wheelPosition > 0: self.wheelPosition -= dt / self.wheelReturnTime if self.wheelPosition < 0: self.wheelPosition = 0 else: self.wheelPosition += dt / self.wheelReturnTime if self.wheelPosition > 0: self.wheelPosition = 0 if abs(self.wheelPosition) >= maxWheelDeflection: if self.wheelPosition > 0: self.wheelPosition = maxWheelDeflection else: self.wheelPosition = -maxWheelDeflection def __watchControls(self, task): dt = globalClock.getDt() curVelocity = self.actorNode.getPhysicsObject().getVelocity() curSpeed = curVelocity.length() fvec = self.forward.getPos(render) - self.getPos(render) fvec.normalize() dotProduct = curVelocity.dot(fvec) goingBack = -1 if dotProduct < 0: goingBack = 1 if self.proRacer: self.__computeTurnRatio(curSpeed) self.__updateWheelPos(dt, curSpeed) newHForTurning = self.getH() if self.proRacer or not self.stopped and self.arrowHorz and curSpeed > 1: if self.proRacer: turnHelp = 0 if self.hittingWall or goingBack == 1: turnHelp = self.arrowHorz effectiveSpeed = curSpeed if effectiveSpeed > self.speedMinTurn: effectiveSpeed = self.speedMinTurn rotation = -goingBack * (self.wheelPosition * dt * self.turnRatio * -1.8 * curSpeed / 100 + turnHelp * dt * self.turnRatio * -1.2) self.outPutCounter += 1 if self.outPutCounter > 5: self.outPutCounter = 0 else: rotation = self.arrowHorz * dt * self.turnRatio * -1.2 oldH = self.getH() newH = (oldH + rotation) % 360 self.setH(newH) newHForTurning = newH if self.groundType == 'ice': newHForTurning = (oldH + rotation * iceTurnFactor) % 360 pitch = -self.getP() + 5 accelBase = self.accelerationBase pitch += accelBase pitch = clampScalar(pitch, accelBase - 5, accelBase + 5) self.accelerationMult = pitch * 2 if self.groundType == 'ice': self.accelerationMult *= iceAccelFactor if self.stopped: self.acceleration = 0 else: self.acceleration = self.arrowVert * self.accelerationMult * self.cheatFactor if self.proRacer: if self.skidding: self.acceleration = self.arrowVert * self.accelerationMult * self.cheatFactor * 0.5 if self.turbo: self.acceleration += self.accelerationMult * 1.5 self.engine.setVector(Vec3(0, self.acceleration, 0)) if self.groundType == 'ice': rotMat = Mat3.rotateMatNormaxis(newHForTurning, Vec3.up()) else: rotMat = Mat3.rotateMatNormaxis(self.getH(), Vec3.up()) curHeading = rotMat.xform(Vec3.forward()) push = (3 - self.getP()) * 0.02 curHeading.setZ(curHeading.getZ() - min(0.2, max(-.2, push))) onScreenDebug.append('vehicle curHeading = %s\n' % curHeading.pPrintValues()) onScreenDebug.append('vehicle H = %s newHForTurning=%f\n' % (self.getH(), newHForTurning)) windResistance = self.surfaceModifiers[self.groundType]['windResistance'] self.windResistance.setCoef(windResistance) physicsFrame = int((globalClock.getFrameTime() - self.physicsEpoch) * self.physicsCalculationsPerSecond) numFrames = min(physicsFrame - self.lastPhysicsFrame, self.maxPhysicsFrames) self.lastPhysicsFrame = physicsFrame leanIncrement = self.arrowHorz * self.physicsDt * self.turnRatio if self.stopped: leanIncrement = 0 driftMin = self.surfaceModifiers[self.groundType]['driftMin'] if self.proRacer: driftMin = self.surfaceModifiers[self.groundType]['driftMin'] * 0.2 if self.skidding: driftMin = self.surfaceModifiers[self.groundType]['driftMin'] for i in xrange(int(numFrames)): self.physicsMgr.doPhysics(self.physicsDt) curVelocity = self.actorNode.getPhysicsObject().getVelocity() idealVelocity = curHeading * curSpeed curVelocity *= self.imHitMult driftVal = abs(self.leanAmount) * 16 / self.cheatFactor + 15 / self.cheatFactor curVelocity = Vec3((curVelocity * driftVal + idealVelocity) / (driftVal + 1)) curSpeed = curVelocity.length() curVelocity.normalize() curVelocity *= min(curSpeed, 600) self.actorNode.getPhysicsObject().setVelocity(curVelocity) curSpeed = curVelocity.length() speedFactor = min(curSpeed, 150) / 162.0 self.leanAmount = (self.leanAmount + leanIncrement) * speedFactor self.leanAmount = clampScalar(self.leanAmount, -10, 10) self.cWallTrav.traverse(render) self.curSpeed = curSpeed if self.proRacer: self.turnWheels(self.wheelPosition * -45) else: self.turnWheels(self.arrowHorz * -10) self.__animate() if self.proRacer: speedProporation = 1.0 if curSpeed < self.speedMaxTurn: speedProporation = 0.0 else: speedProporation = (curSpeed - self.speedMaxTurn) / self.speedMinTurn cameraDist = self.cameraArmBase + self.cameraArmExtend * speedProporation cameraOffset = Point3(0, -cameraDist, 0) self.cameraNode.setPos(cameraOffset) behindPos = render.getRelativePoint(self, Point3(0, -30, 0)) self.proCameraDummyNode.setPos(render, behindPos) self.proCameraDummyNode.lookAt(self) self.cameraNode.lookAt(self) dir1 = self.proCameraDummyNode.getH() dir2 = self.proCameraHeading if dir1 > 180: dir1 -= 360 elif dir1 < -180: dir1 += 360 if dir2 > 180: dir2 -= 360 elif dir2 < -180: dir2 += 360 self.proCameraHeading = dir2 dif = dir1 - dir2 if dif > 180: dif -= 360 elif dif < -180: dif += 360 speedDif = abs(dif) if speedDif > 90: speedDif = 90 cameraTightener = 1.0 if curSpeed > self.speedMinTurn: cameraTightener = self.cameraTightener else: cameraTightener = 1.0 + curSpeed / self.speedMinTurn * (self.cameraTightener - 1.0) swingSpeedRatio = speedDif / 90 swingSpeed = self.armSwingSpeedPerp * swingSpeedRatio + self.armSwingSpeedPara * (1 - swingSpeedRatio) self.proCameraHeading += dif * cameraTightener * (dt / swingSpeed) self.cameraArmNode.setH(self.proCameraHeading - self.getH()) elif not self.stopped: self.cameraNode.setH(self.leanAmount) self.updateParticles(self.leanAmount) if (self.leanAmount > 8 or self.leanAmount < -8) and self.offGround <= 0: self.startSkid() else: self.stopSkid() if self.speedometer: self.speedometer['text'] = str(int(curSpeed / 3)) self.speedGauge.setR(min(110, max(0, curSpeed / 3 / 120 * 110))) if not self.stopped: self.stickCarToGround() if self.__clampPosition(): self.notify.debug('did a clampPosition on %d' % self.doId) return Task.cont def enableControls(self): self.canRace = True 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) def disableControls(self): self.arrowVert = 0 self.arrowHorz = 0 self.ignore('control') self.ignore('control-up') self.ignore('tab') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') def setInput(self, on): if localAvatar.doId == self.ownerId: if on: self.enableControls() else: self.disableControls() def shakeWheel(self, nWheel, floorNode): groundType = floorNode.getNetTag('surface') modifier = self.surfaceModifiers[groundType]['shake'] shakeFactor = (random.random() * 2 - 1) * modifier shakeFactor *= self.curSpeed / 200 node = self.wheelCenters[nWheel].find('*Wheel') node.setZ(shakeFactor) def stickCarToGround(self): posList = [] nWheels = len(self.wheelData) for nWheel in xrange(nWheels): cQueue = self.cQueue[nWheel] cQueue.sortEntries() if cQueue.getNumEntries() == 0: return entry = cQueue.getEntry(0) self.shakeWheel(nWheel, entry.getIntoNodePath()) pos = entry.getSurfacePoint(render) wheelPos = self.wheelBases[nWheel].getPos(render) pos = wheelPos - pos posList.append(pos) cQueue.clearEntries() rf = posList[0].getZ() lf = posList[1].getZ() rr = posList[2].getZ() lr = posList[3].getZ() right = (rf + rr) / 2 left = (lf + lr) / 2 rollVal = right - left rollVal = clampScalar(rollVal, -1, 1) curRoll = self.getR() newRoll = curRoll + rollVal * 2.0 self.setR(newRoll) if not self.stopped: camera.setR(-newRoll) front = (rf + lf) / 2 rear = (rr + lr) / 2 center = (front + rear) / 2 pitchVal = front - rear pitchVal = clampScalar(pitchVal, -1, 1) curPitch = self.getP() newPitch = curPitch - pitchVal * 2.0 self.setP((newPitch + curPitch) / 2.0) if self.proRacer: self.cameraNode.setP(-newPitch) elif not self.stopped: self.cameraNode.setP(-newPitch) def setBodyType(self, bodyType): self.kartDNA[KartDNA.bodyType] = bodyType def setBodyColor(self, bodyColor): self.kartDNA[KartDNA.bodyColor] = bodyColor def setAccessoryColor(self, accColor): self.kartDNA[KartDNA.accColor] = accColor def setEngineBlockType(self, ebType): self.kartDNA[KartDNA.ebType] = ebType def setSpoilerType(self, spType): self.kartDNA[KartDNA.spType] = spType def setFrontWheelWellType(self, fwwType): self.kartDNA[KartDNA.fwwType] = fwwType def setBackWheelWellType(self, bwwType): self.kartDNA[KartDNA.bwwType] = bwwType def setRimType(self, rimsType): self.kartDNA[KartDNA.rimsType] = rimsType def setDecalType(self, decalType): self.kartDNA[KartDNA.decalType] = decalType def setOwner(self, avId): self.ownerId = avId DistributedVehicle.AvId2kart[avId] = self def stopCar(self, level): self.imHitMult = level self.__stopTurbo() self.stopped = True def startCar(self): self.imHitMult = 1 self.stopped = False def hideAnvil(self): self.anvil.reparentTo(hidden) self.anvil.setAlphaScale(1) self.dropShadow.setScale(self.ShadowScale) def spinCar(self, spin): self.geom[0].setH(2 * spin) def playSpin(self, timeStamp): delta = -globalClockDelta.networkToLocalTime(timeStamp, globalClock.getFrameTime(), 16, 100) + globalClock.getFrameTime() self.spinAnim = LerpFunc(self.spinCar, fromData=0, toData=360, duration=min(1 - delta, 0)) self.spinAnim.start() def __throwGag(self): base.race.shootGag() def dropOnMe(self, timestamp): self.anvil.setScale(7, 9, 7) self.anvil.setPos(0, 0, 75) self.anvil.reparentTo(self) anvilDrop = ProjectileInterval(self.anvil, startPos=Point3(0, 0, 100), endPos=Point3(0, 0, 0), duration=1) shadowScale = self.dropShadow.scaleInterval(1, self.ShadowScale * 2) fadeOut = LerpFunc(self.anvil.setAlphaScale, fromData=1, toData=0, duration=0.5) flattenMe = self.geom[0].scaleInterval(0.08, Vec3(1, 1, 0.1)) unFlatten = Sequence(self.geom[0].scaleInterval(0.2, Vec3(1, 1, 2)), self.geom[0].scaleInterval(0.1, 1)) anvilSquish = Parallel(Parallel(anvilDrop, shadowScale), Sequence(Wait(0.92), flattenMe)) anvilStretchFade = Sequence(Parallel(self.anvil.scaleInterval(0.2, Vec3(7, 9, 5)), Func(self.lookUp)), fadeOut) self.gagMovie = Sequence(anvilSquish, Func(self.stopCar, 0.9), anvilStretchFade, Wait(0.5), Parallel(unFlatten, Func(self.lookNormal)), Func(self.startCar), Func(self.hideAnvil)) self.gagMovie.start() def lookUp(self): if self.toon and self.toon.headParts: headParts = self.toon.headParts for hi in xrange(headParts.getNumPaths()): head = headParts[hi] head.setP(90) def lookNormal(self): if self.toon and self.toon.headParts: headParts = self.toon.headParts for hi in xrange(headParts.getNumPaths()): head = headParts[hi] head.setP(0) def flattenMe(self): self.geom[0].setScale(3, 3, 0.1) def unFlattenMe(self): self.geom[0].setScale(2) def startSkid(self): if self.skidding == False: self.skidding = True self.skidLoopAsphaltSfx.play() def stopSkid(self): if self.skidding == True: self.skidding = False self.skidLoopAsphaltSfx.stop() self.skidLoopGrassSfx.stop() def updateSkid(self): if self.skidding: if self.groundType == 'grass': self.skidLoopGrassSfx.setVolume(1) self.skidLoopAsphaltSfx.setVolume(0) else: self.skidLoopGrassSfx.setVolume(0) self.skidLoopAsphaltSfx.setVolume(1) def dropOnHim(self, timestamp): self.anvil.setScale(10, 13, 10) self.anvil.setPos(0, 0, 75) self.anvil.reparentTo(self) anvilDrop = ProjectileInterval(self.anvil, startPos=Point3(0, 0, 100), endPos=Point3(0, 0, 0), duration=1) shadowScale = self.dropShadow.scaleInterval(1, self.ShadowScale * 4) fadeOut = LerpFunc(self.anvil.setAlphaScale, fromData=1, toData=0, duration=0.5) flattenMe = self.geom[0].scaleInterval(0.08, Vec3(1, 1, 0.1)) unFlatten = Sequence(self.geom[0].scaleInterval(0.2, Vec3(1, 1, 2)), self.geom[0].scaleInterval(0.1, 1)) anvilSquish = Parallel(Parallel(anvilDrop, shadowScale), Sequence(Wait(0.92), flattenMe)) anvilStretchFade = Sequence(Parallel(self.anvil.scaleInterval(0.2, Vec3(10, 13, 4)), Func(self.lookUp)), fadeOut) self.gagMovie = Sequence(anvilSquish, anvilStretchFade, Wait(0.5), Parallel(unFlatten, Func(self.lookNormal)), Func(self.hideAnvil)) self.gagMovie.start() def hitBanana(self): if self.wipeOut: self.wipeOut.pause() spinAnim = LerpFunc(self.spinCar, fromData=self.geom[0].getH(), toData=360, duration=1) else: spinAnim = LerpFunc(self.spinCar, fromData=0, toData=360, duration=1) self.wipeOut = Sequence(Func(self.stopCar, 0.99), spinAnim, Func(self.startCar)) self.wipeOut.start() def hitPie(self): print 'yar, got Me with pi!' self.splatPie() if self.wipeOut: self.wipeOut.pause() spinAnim = LerpFunc(self.spinCar, fromData=self.geom[0].getH(), toData=1080, duration=0.5) else: spinAnim = LerpFunc(self.spinCar, fromData=0, toData=1080, duration=0.5) self.wipeOut = Sequence(Func(self.stopCar, 0.99), spinAnim, Func(self.startCar)) self.wipeOut.start() def finishMovies(self): if self.gagMovie: self.gagMovie.finish() self.gagMovie = None if self.wipeOut: self.wipeOut.finish() self.wipeOut = None if self.spinAnim: self.spinAnim.finish() self.spinAnim = None return