from direct.interval.IntervalGlobal import * from direct.distributed.ClockDelta import * from direct.task.Task import Task from direct.distributed import DistributedObject from direct.directnotify import DirectNotifyGlobal from panda3d.core import CollisionSphere, CollisionNode from toontown.toonbase import ToontownGlobals from toontown.estate import DistributedCannon from toontown.estate import CannonGlobals from direct.gui.DirectGui import * from panda3d.core import * from panda3d.otp import * from toontown.toon import NPCToons from toontown.toon import ToonHead from toontown.toonbase import TTLocalizer from toontown.minigame import Trajectory from toontown.effects import DustCloud GROUND_PLANE_MIN = -15 CANNON_ROTATION_MIN = -55 CANNON_ROTATION_MAX = 50 CANNON_ROTATION_VEL = 15.0 CANNON_ANGLE_MIN = 10 CANNON_ANGLE_MAX = 85 CANNON_ANGLE_VEL = 15.0 INITIAL_VELOCITY = 80 CANNON_MOVE_UPDATE_FREQ = 0.5 CAMERA_PULLBACK_MIN = 20 CAMERA_PULLBACK_MAX = 40 class DistributedLawbotCannon(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLawbotCannon') LOCAL_CANNON_MOVE_TASK = 'localCannonMoveTask' FIRE_KEY = 'control' UP_KEY = 'arrow_up' DOWN_KEY = 'arrow_down' LEFT_KEY = 'arrow_left' RIGHT_KEY = 'arrow_right' HIT_GROUND = 0 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.index = None self.avId = 0 self.av = None self.localToonShooting = 0 self.cannonsActive = 0 self.cannonLocation = None self.cannonPostion = None self.cannon = None self.madeGui = 0 self.jurorToon = None self.toonModel = None self.toonHead = None self.toonScale = None self.dustCloud = None self.hitBumper = 0 self.hitTarget = 0 self.lastPos = Vec3(0, 0, 0) self.lastVel = Vec3(0, 0, 0) self.vel = Vec3(0, 0, 0) self.landingPos = Vec3(0, 0, 0) self.t = 0 self.lastT = 0 self.deltaT = 0 self.hitTrack = None self.flyColNode = None self.flyColNodePath = None self.localAvId = base.localAvatar.doId self.model_Created = 0 return def disable(self): taskMgr.remove(self.uniqueName('fireCannon')) taskMgr.remove(self.uniqueName('shootTask')) self.__stopFlyTask(self.avId) taskMgr.remove(self.uniqueName('flyTask')) self.ignoreAll() self.setMovie(CannonGlobals.CANNON_MOVIE_CLEAR, 0, 0) self.nodePath.detachNode() self.__unmakeGui() if self.hitTrack: self.hitTrack.finish() del self.hitTrack self.hitTrack = None DistributedObject.DistributedObject.disable(self) return def delete(self): self.offstage() self.unload() DistributedObject.DistributedObject.delete(self) def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.boss.cannons[self.index] = self def generateInit(self): DistributedObject.DistributedObject.generateInit(self) self.nodePath = NodePath(self.uniqueName('Cannon')) self.load() self.activateCannons() def setPosHpr(self, x, y, z, h, p, r): self.nodePath.setPosHpr(x, y, z, h, p, r) def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] def getSphereRadius(self): return 1.5 def getParentNodePath(self): return render def setIndex(self, index): self.index = index def load(self): self.cannon = loader.loadModel('phase_4/models/minigames/toon_cannon') self.collSphere = CollisionSphere(0, 0, 0, self.getSphereRadius()) self.dustCloud = DustCloud.DustCloud(render) self.dustCloud.setBillboardPointEye() self.collSphere.setTangible(1) self.collNode = CollisionNode(self.uniqueName('CannonSphere')) self.collNode.setCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.nodePath.attachNewNode(self.collNode) self.cannon.reparentTo(self.nodePath) self.kartColNode = CollisionNode(self.uniqueName('KartColNode')) self.kartNode = self.nodePath.attachNewNode(self.kartColNode) self.sndCannonMove = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.ogg') self.sndCannonFire = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_fire_alt.ogg') self.sndHitGround = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg') self.sndHitChair = base.loader.loadSfx('phase_11/audio/sfx/LB_toon_jury.ogg') self.cannon.hide() self.flashingLabel = None return def unload(self): if self.cannon: self.cannon.removeNode() del self.cannon if self.dustCloud != None: self.dustCloud.destroy() del self.dustCloud del self.sndCannonMove del self.sndCannonFire del self.sndHitGround del self.sndHitChair if self.av: self.__resetToon(self.av) self.av.loop('neutral') self.av.setPlayRate(1.0, 'run') if self.toonHead != None: self.toonHead.stopBlink() self.toonHead.stopLookAroundNow() self.toonHead.delete() del self.toonHead if self.toonModel != None: self.toonModel.removeNode() del self.toonModel if self.jurorToon != None: self.jurorToon.delete() del self.jurorToon del self.toonScale return def activateCannons(self): if not self.cannonsActive: self.cannonsActive = 1 self.onstage() self.nodePath.reparentTo(self.getParentNodePath()) self.accept(self.uniqueName('enterCannonSphere'), self.__handleEnterSphere) def onstage(self): self.__createCannon() self.cannon.reparentTo(self.nodePath) self.dustCloud.reparentTo(render) def offstage(self): if self.cannon: self.cannon.reparentTo(hidden) if self.dustCloud: self.dustCloud.reparentTo(hidden) self.dustCloud.stop() def __createCannon(self): self.barrel = self.cannon.find('**/cannon') self.cannonLocation = Point3(0, 0, 0.025) self.cannonPosition = [0, CANNON_ANGLE_MIN] self.cannon.setPos(self.cannonLocation) self.__updateCannonPosition(self.avId) def updateCannonPosition(self, avId, zRot, angle): if avId != self.localAvId: self.cannonPosition = [zRot, angle] self.__updateCannonPosition(avId) def __updateCannonPosition(self, avId): self.cannon.setHpr(self.cannonPosition[0], 0.0, 0.0) self.barrel.setHpr(0.0, self.cannonPosition[1], 0.0) maxP = 90 newP = self.barrel.getP() yScale = 1 - 0.5 * float(newP) / maxP shadow = self.cannon.find('**/square_drop_shadow') shadow.setScale(1, yScale, 1) def __handleEnterSphere(self, collEntry): self.d_requestEnter() def d_requestEnter(self): self.sendUpdate('requestEnter', []) def setMovie(self, mode, avId, extraInfo): wasLocalToon = self.localToonShooting self.avId = avId if mode == CannonGlobals.CANNON_MOVIE_CLEAR: self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_LANDED: self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_FORCE_EXIT: self.exitCannon(self.avId) self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_LOAD: if self.avId == base.localAvatar.doId: self.cannonBallsLeft = extraInfo base.cr.playGame.getPlace().setState('crane') base.localAvatar.setTeleportAvailable(0) self.localToonShooting = 1 self.__makeGui() camera.reparentTo(self.barrel) camera.setPos(0.5, -2, 2.5) camera.setHpr(0, 0, 0) self.boss.toonEnteredCannon(self.avId, self.index) if self.avId in self.cr.doId2do: self.av = self.cr.doId2do[self.avId] self.acceptOnce(self.av.uniqueName('disable'), self.__avatarGone) self.av.loop('neutral') self.av.stopSmooth() self.__destroyToonModels() self.__createToonModels() self.av.setPosHpr(3, 0, 0, 90, 0, 0) self.av.reparentTo(self.cannon) else: self.notify.warning('Unknown avatar %d in cannon %d' % (self.avId, self.doId)) else: self.notify.warning('unhandled case, mode = %d' % mode) def __avatarGone(self): self.setMovie(CannonGlobals.CANNON_MOVIE_CLEAR, 0, 0) def __makeGui(self): if self.madeGui: return NametagGlobals.setMasterArrowsOn(0) guiModel = 'phase_4/models/gui/cannon_game_gui' cannonGui = loader.loadModel(guiModel) self.aimPad = DirectFrame(image=cannonGui.find('**/CannonFire_PAD'), relief=None, pos=(0.7, 0, -0.553333), scale=0.8) cannonGui.removeNode() self.fireButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Fire_Btn_UP'), (guiModel, '**/Fire_Btn_DN'), (guiModel, '**/Fire_Btn_RLVR')), relief=None, pos=(0.0115741, 0, 0.00505051), scale=1.0, command=self.__firePressed) self.upButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0115741, 0, 0.221717)) self.downButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0136112, 0, -0.210101), image_hpr=(0, 0, 180)) self.leftButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(-0.199352, 0, -0.000505269), image_hpr=(0, 0, -90)) self.rightButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.219167, 0, -0.00101024), image_hpr=(0, 0, 90)) guiClose = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') cannonBallText = '%d/%d' % (self.cannonBallsLeft, ToontownGlobals.LawbotBossCannonBallMax) self.cannonBallLabel = DirectLabel(parent=self.aimPad, text=cannonBallText, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0.475, 0.0, -0.35), scale=0.25) if self.cannonBallsLeft < 5: if self.flashingLabel: self.flashingLabel.stop() flashingTrack = Sequence() for i in range(10): flashingTrack.append(LerpColorScaleInterval(self.cannonBallLabel, 0.5, VBase4(1, 0, 0, 1))) flashingTrack.append(LerpColorScaleInterval(self.cannonBallLabel, 0.5, VBase4(1, 1, 1, 1))) self.flashingLabel = flashingTrack self.flashingLabel.start() self.aimPad.setColor(1, 1, 1, 0.9) def bindButton(button, upHandler, downHandler): button.bind(DGG.B1PRESS, lambda x, handler = upHandler: handler()) button.bind(DGG.B1RELEASE, lambda x, handler = downHandler: handler()) bindButton(self.upButton, self.__upPressed, self.__upReleased) bindButton(self.downButton, self.__downPressed, self.__downReleased) bindButton(self.leftButton, self.__leftPressed, self.__leftReleased) bindButton(self.rightButton, self.__rightPressed, self.__rightReleased) self.__enableAimInterface() self.madeGui = 1 return def __unmakeGui(self): self.notify.debug('__unmakeGui') if not self.madeGui: return if self.flashingLabel: self.flashingLabel.finish() self.flashingLabel = None NametagGlobals.setMasterArrowsOn(1) self.__disableAimInterface() self.upButton.unbind(DGG.B1PRESS) self.upButton.unbind(DGG.B1RELEASE) self.downButton.unbind(DGG.B1PRESS) self.downButton.unbind(DGG.B1RELEASE) self.leftButton.unbind(DGG.B1PRESS) self.leftButton.unbind(DGG.B1RELEASE) self.rightButton.unbind(DGG.B1PRESS) self.rightButton.unbind(DGG.B1RELEASE) self.aimPad.destroy() del self.aimPad del self.fireButton del self.upButton del self.downButton del self.leftButton del self.rightButton self.madeGui = 0 return def __enableAimInterface(self): self.aimPad.show() self.accept(self.FIRE_KEY, self.__fireKeyPressed) self.accept(self.UP_KEY, self.__upKeyPressed) self.accept(self.DOWN_KEY, self.__downKeyPressed) self.accept(self.LEFT_KEY, self.__leftKeyPressed) self.accept(self.RIGHT_KEY, self.__rightKeyPressed) self.__spawnLocalCannonMoveTask() def __disableAimInterface(self): self.aimPad.hide() self.ignore(self.FIRE_KEY) self.ignore(self.UP_KEY) self.ignore(self.DOWN_KEY) self.ignore(self.LEFT_KEY) self.ignore(self.RIGHT_KEY) self.ignore(self.FIRE_KEY + '-up') self.ignore(self.UP_KEY + '-up') self.ignore(self.DOWN_KEY + '-up') self.ignore(self.LEFT_KEY + '-up') self.ignore(self.RIGHT_KEY + '-up') self.__killLocalCannonMoveTask() def __fireKeyPressed(self): self.ignore(self.FIRE_KEY) self.accept(self.FIRE_KEY + '-up', self.__fireKeyReleased) self.__firePressed() def __upKeyPressed(self): self.ignore(self.UP_KEY) self.accept(self.UP_KEY + '-up', self.__upKeyReleased) self.__upPressed() def __downKeyPressed(self): self.ignore(self.DOWN_KEY) self.accept(self.DOWN_KEY + '-up', self.__downKeyReleased) self.__downPressed() def __leftKeyPressed(self): self.ignore(self.LEFT_KEY) self.accept(self.LEFT_KEY + '-up', self.__leftKeyReleased) self.__leftPressed() def __rightKeyPressed(self): self.ignore(self.RIGHT_KEY) self.accept(self.RIGHT_KEY + '-up', self.__rightKeyReleased) self.__rightPressed() def __fireKeyReleased(self): self.ignore(self.FIRE_KEY + '-up') self.accept(self.FIRE_KEY, self.__fireKeyPressed) def __leftKeyReleased(self): self.ignore(self.LEFT_KEY + '-up') self.accept(self.LEFT_KEY, self.__leftKeyPressed) self.__leftReleased() def __rightKeyReleased(self): self.ignore(self.RIGHT_KEY + '-up') self.accept(self.RIGHT_KEY, self.__rightKeyPressed) self.__rightReleased() def __upKeyReleased(self): self.ignore(self.UP_KEY + '-up') self.accept(self.UP_KEY, self.__upKeyPressed) self.__upReleased() def __downKeyReleased(self): self.ignore(self.DOWN_KEY + '-up') self.accept(self.DOWN_KEY, self.__downKeyPressed) self.__downReleased() def __leaveCannon(self): self.notify.debug('__leaveCannon') self.sendUpdate('requestLeave') def __firePressed(self): self.notify.debug('fire pressed') if not self.boss.state == 'BattleTwo': self.notify.debug('boss is in state=%s, not firing' % self.boss.state) return self.__broadcastLocalCannonPosition() self.__unmakeGui() self.sendUpdate('setCannonLit', [self.cannonPosition[0], self.cannonPosition[1]]) def __upPressed(self): self.notify.debug('up pressed') self.upPressed = self.__enterControlActive(self.upPressed) def __downPressed(self): self.notify.debug('down pressed') self.downPressed = self.__enterControlActive(self.downPressed) def __leftPressed(self): self.notify.debug('left pressed') self.leftPressed = self.__enterControlActive(self.leftPressed) def __rightPressed(self): self.notify.debug('right pressed') self.rightPressed = self.__enterControlActive(self.rightPressed) def __upReleased(self): self.notify.debug('up released') self.upPressed = self.__exitControlActive(self.upPressed) def __downReleased(self): self.notify.debug('down released') self.downPressed = self.__exitControlActive(self.downPressed) def __leftReleased(self): self.notify.debug('left released') self.leftPressed = self.__exitControlActive(self.leftPressed) def __rightReleased(self): self.notify.debug('right released') self.rightPressed = self.__exitControlActive(self.rightPressed) def __enterControlActive(self, control): return control + 1 def __exitControlActive(self, control): return max(0, control - 1) def __spawnLocalCannonMoveTask(self): self.leftPressed = 0 self.rightPressed = 0 self.upPressed = 0 self.downPressed = 0 self.cannonMoving = 0 task = Task(self.__localCannonMoveTask) task.lastPositionBroadcastTime = 0.0 taskMgr.add(task, self.LOCAL_CANNON_MOVE_TASK) def __killLocalCannonMoveTask(self): taskMgr.remove(self.LOCAL_CANNON_MOVE_TASK) if self.cannonMoving: self.sndCannonMove.stop() def __localCannonMoveTask(self, task): pos = self.cannonPosition oldRot = pos[0] oldAng = pos[1] rotVel = 0 if self.leftPressed: rotVel += CANNON_ROTATION_VEL if self.rightPressed: rotVel -= CANNON_ROTATION_VEL pos[0] += rotVel * globalClock.getDt() if pos[0] < CANNON_ROTATION_MIN: pos[0] = CANNON_ROTATION_MIN elif pos[0] > CANNON_ROTATION_MAX: pos[0] = CANNON_ROTATION_MAX angVel = 0 if self.upPressed: angVel += CANNON_ANGLE_VEL if self.downPressed: angVel -= CANNON_ANGLE_VEL pos[1] += angVel * globalClock.getDt() if pos[1] < CANNON_ANGLE_MIN: pos[1] = CANNON_ANGLE_MIN elif pos[1] > CANNON_ANGLE_MAX: pos[1] = CANNON_ANGLE_MAX if oldRot != pos[0] or oldAng != pos[1]: if self.cannonMoving == 0: self.cannonMoving = 1 base.playSfx(self.sndCannonMove, looping=1) self.__updateCannonPosition(self.localAvId) if task.time - task.lastPositionBroadcastTime > CANNON_MOVE_UPDATE_FREQ: task.lastPositionBroadcastTime = task.time self.__broadcastLocalCannonPosition() elif self.cannonMoving: self.cannonMoving = 0 self.sndCannonMove.stop() self.__broadcastLocalCannonPosition() return Task.cont def __broadcastLocalCannonPosition(self): self.sendUpdate('setCannonPosition', [self.cannonPosition[0], self.cannonPosition[1]]) def __updateCannonPosition(self, avId): self.cannon.setHpr(self.cannonPosition[0], 0.0, 0.0) self.barrel.setHpr(0.0, self.cannonPosition[1], 0.0) maxP = 90 newP = self.barrel.getP() yScale = 1 - 0.5 * float(newP) / maxP shadow = self.cannon.find('**/square_drop_shadow') shadow.setScale(1, yScale, 1) def __createToonModels(self): self.model_Created = 1 self.jurorToon = NPCToons.createLocalNPC(ToontownGlobals.LawbotBossBaseJurorNpcId + self.index) self.toonScale = self.jurorToon.getScale() jurorToonParent = render.attachNewNode('toonOriginChange') self.jurorToon.wrtReparentTo(jurorToonParent) self.jurorToon.setPosHpr(0, 0, -(self.jurorToon.getHeight() / 2.0), 0, -90, 0) self.toonModel = jurorToonParent self.toonHead = ToonHead.ToonHead() self.toonHead.setupHead(self.jurorToon.style) self.toonHead.reparentTo(hidden) self.__loadToonInCannon() def __destroyToonModels(self): if (0): self.av.dropShadow.show() if self.dropShadow != None: self.dropShadow.removeNode() self.dropShadow = None self.hitBumper = 0 self.hitTarget = 0 self.angularVel = 0 self.vel = Vec3(0, 0, 0) self.lastVel = Vec3(0, 0, 0) self.lastPos = Vec3(0, 0, 0) self.landingPos = Vec3(0, 0, 0) self.t = 0 self.lastT = 0 self.deltaT = 0 self.av = None self.lastWakeTime = 0 self.localToonShooting = 0 if self.toonHead != None: self.toonHead.reparentTo(hidden) self.toonHead.stopBlink() self.toonHead.stopLookAroundNow() self.toonHead = None if self.toonModel != None: self.toonModel.removeNode() self.toonModel = None if self.jurorToon != None: self.jurorToon.delete() self.jurorToon = None self.model_Created = 0 return def __loadToonInCannon(self): self.toonModel.reparentTo(hidden) self.toonHead.startBlink() self.toonHead.startLookAround() self.toonHead.reparentTo(self.barrel) self.toonHead.setPosHpr(0, 6, 0, 0, -45, 0) sc = self.toonScale self.toonHead.setScale(render, sc[0], sc[1], sc[2]) def exitCannon(self, avId): self.__unmakeGui() if self.avId == avId: self.av.reparentTo(render) self.__resetToonToCannon(self.av) def __resetToonToCannon(self, avatar): pos = None if not avatar: if self.avId: avatar = base.cr.doId2do.get(self.avId, None) if avatar: if hasattr(self, 'cannon') and self.cannon: avatar.reparentTo(self.cannon) avatar.setPosHpr(3, 0, 0, 90, 0, 0) avatar.wrtReparentTo(render) self.__resetToon(avatar) return def __resetToon(self, avatar, pos = None): if avatar: self.__stopCollisionHandler(avatar) self.__setToonUpright(avatar, pos) if self.localToonShooting: self.notify.debug('toon setting position to %s' % pos) if pos: base.localAvatar.setPos(pos) camera.reparentTo(avatar) camera.setPos(self.av.cameraPositions[0][0]) place = base.cr.playGame.getPlace() if place: place.setState('finalBattle') self.b_setLanded() def __stopCollisionHandler(self, avatar): if avatar: avatar.loop('neutral') if self.flyColNode: self.flyColNode = None if avatar == base.localAvatar: avatar.collisionsOn() self.flyColSphere = None if self.flyColNodePath: base.cTrav.removeCollider(self.flyColNodePath) self.flyColNodePath.removeNode() self.flyColNodePath = None self.handler = None return def __setToonUpright(self, avatar, pos = None): if avatar: if not pos: pos = avatar.getPos(render) avatar.setPos(render, pos) avatar.loop('neutral') def b_setLanded(self): self.d_setLanded() def d_setLanded(self): if self.localToonShooting: self.sendUpdate('setLanded', []) def setLanded(self): self.removeAvFromCannon() def removeAvFromCannon(self): if self.av != None: self.__stopCollisionHandler(self.av) self.av.resetLOD() place = base.cr.playGame.getPlace() if self.av == base.localAvatar: if place: place.setState('finalBattle') self.av.loop('neutral') self.av.setPlayRate(1.0, 'run') if self.av.getParent().getName() == 'toonOriginChange': self.av.wrtReparentTo(render) self.__setToonUpright(self.av) if self.av == base.localAvatar: self.av.startPosHprBroadcast() self.av.startSmooth() self.av.setScale(1, 1, 1) self.ignore(self.av.uniqueName('disable')) self.__destroyToonModels() return def setCannonWillFire(self, avId, fireTime, zRot, angle, timestamp): self.notify.debug('setCannonWillFire: ' + str(avId) + ': zRot=' + str(zRot) + ', angle=' + str(angle) + ', time=' + str(fireTime)) if not self.model_Created: self.notify.warning("We walked into the zone mid-flight, so we won't see it") return self.cannonPosition[0] = zRot self.cannonPosition[1] = angle self.__updateCannonPosition(avId) task = Task(self.__fireCannonTask) task.avId = avId ts = globalClockDelta.localElapsedTime(timestamp) task.fireTime = fireTime - ts if task.fireTime < 0.0: task.fireTime = 0.0 taskMgr.add(task, self.taskName('fireCannon')) def __fireCannonTask(self, task): launchTime = task.fireTime avId = task.avId if self.toonHead == None or not self.boss.state == 'BattleTwo': return Task.done startPos, startHpr, startVel, trajectory, timeOfImpact, hitWhat = self.__calcFlightResults(avId, launchTime) self.notify.debug('start position: ' + str(startPos)) self.notify.debug('start velocity: ' + str(startVel)) self.notify.debug('time of launch: ' + str(launchTime)) self.notify.debug('time of impact: ' + str(timeOfImpact)) self.notify.debug('location of impact: ' + str(trajectory.getPos(timeOfImpact))) head = self.toonHead head.stopBlink() head.stopLookAroundNow() head.reparentTo(hidden) juror = self.toonModel juror.reparentTo(render) juror.setPos(startPos) barrelHpr = self.barrel.getHpr(render) juror.setHpr(startHpr) self.jurorToon.loop('swim') self.jurorToon.setPosHpr(0, 0, -(self.jurorToon.getHeight() / 2.0), 0, 0, 0) info = {} info['avId'] = avId info['trajectory'] = trajectory info['launchTime'] = launchTime info['timeOfImpact'] = timeOfImpact info['hitWhat'] = hitWhat info['toon'] = self.toonModel info['hRot'] = self.cannonPosition[0] info['haveWhistled'] = 0 info['maxCamPullback'] = CAMERA_PULLBACK_MIN if self.localToonShooting: camera.reparentTo(juror) camera.setP(45.0) camera.setZ(-10.0) self.flyColSphere = CollisionSphere(0, 0, self.av.getHeight() / 2.0, 1.0) self.flyColNode = CollisionNode(self.uniqueName('flySphere')) self.flyColNode.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.FloorBitmask | ToontownGlobals.PieBitmask) self.flyColNode.addSolid(self.flyColSphere) self.flyColNodePath = self.jurorToon.attachNewNode(self.flyColNode) self.flyColNodePath.setColor(1, 0, 0, 1) self.handler = CollisionHandlerEvent() self.handler.setInPattern(self.uniqueName('cannonHit')) base.cTrav.addCollider(self.flyColNodePath, self.handler) self.accept(self.uniqueName('cannonHit'), self.__handleCannonHit) shootTask = Task(self.__shootTask, self.taskName('shootTask')) flyTask = Task(self.__flyTask, self.taskName('flyTask')) shootTask.info = info flyTask.info = info seqTask = Task.sequence(shootTask, flyTask) taskMgr.add(seqTask, self.taskName('flyingToon') + '-' + str(avId)) self.acceptOnce(self.uniqueName('stopFlyTask'), self.__stopFlyTask) return Task.done def __toRadians(self, angle): return angle * 2.0 * math.pi / 360.0 def __toDegrees(self, angle): return angle * 360.0 / (2.0 * math.pi) def __calcFlightResults(self, avId, launchTime): head = self.toonHead startPos = head.getPos(render) startHpr = head.getHpr(render) hpr = self.barrel.getHpr(render) rotation = self.__toRadians(hpr[0]) angle = self.__toRadians(hpr[1]) horizVel = INITIAL_VELOCITY * math.cos(angle) xVel = horizVel * -math.sin(rotation) yVel = horizVel * math.cos(rotation) zVel = INITIAL_VELOCITY * math.sin(angle) startVel = Vec3(xVel, yVel, zVel) trajectory = Trajectory.Trajectory(launchTime, startPos, startVel) self.trajectory = trajectory timeOfImpact, hitWhat = self.__calcToonImpact(trajectory) return startPos, startHpr, startVel, trajectory, 3 * timeOfImpact, hitWhat def __calcToonImpact(self, trajectory): t_groundImpact = trajectory.checkCollisionWithGround(GROUND_PLANE_MIN) if t_groundImpact >= trajectory.getStartTime(): return (t_groundImpact, self.HIT_GROUND) else: self.notify.error('__calcToonImpact: toon never impacts ground?') return (0.0, self.HIT_GROUND) def __handleCannonHit(self, collisionEntry): if self.av == None or self.flyColNode == None: return interPt = collisionEntry.getSurfacePoint(render) hitNode = collisionEntry.getIntoNode().getName() fromNodePath = collisionEntry.getFromNodePath() intoNodePath = collisionEntry.getIntoNodePath() ignoredHits = ['NearBoss'] for nodeName in ignoredHits: if hitNode == nodeName: return self.__stopFlyTask(self.avId) self.__stopCollisionHandler(self.jurorToon) if self.localToonShooting: camera.wrtReparentTo(render) pos = interPt hpr = self.jurorToon.getHpr() track = Sequence() if self.localToonShooting: pass chairlist = ['trigger-chair'] for index in range(len(ToontownGlobals.LawbotBossChairPosHprs)): chairlist.append('Chair-%s' % index) if hitNode in chairlist: track.append(Func(self.__hitChair, self.jurorToon, pos)) track.append(Wait(1.0)) track.append(Func(self.__setToonUpright, self.av)) if self.av == base.localAvatar: strs = hitNode.split('-') chairNum = int(strs[1]) self.boss.sendUpdate('hitChair', [chairNum, self.index]) else: track.append(Func(self.__hitGround, self.jurorToon, pos)) track.append(Wait(1.0)) track.append(Func(self.__setToonUpright, self.av)) track.append(Func(self.b_setLanded)) if self.localToonShooting: pass if self.hitTrack: self.hitTrack.finish() self.hitTrack = track self.hitTrack.start() return def enterCannonHit(self, collisionEntry): pass def __shootTask(self, task): base.playSfx(self.sndCannonFire) return Task.done def __flyTask(self, task): toon = task.info['toon'] if toon.isEmpty(): self.__resetToonToCannon(self.av) return Task.done curTime = task.time + task.info['launchTime'] t = min(curTime, task.info['timeOfImpact']) self.lastT = self.t self.t = t deltaT = self.t - self.lastT self.deltaT = deltaT if t >= task.info['timeOfImpact']: self.__resetToonToCannon(self.av) return Task.done pos = task.info['trajectory'].getPos(t) toon.setFluidPos(pos) vel = task.info['trajectory'].getVel(t) run = math.sqrt(vel[0] * vel[0] + vel[1] * vel[1]) rise = vel[2] theta = self.__toDegrees(math.atan(rise / run)) toon.setHpr(self.cannon.getH(render), -90 + theta, 0) view = 2 lookAt = task.info['toon'].getPos(render) hpr = task.info['toon'].getHpr(render) if self.localToonShooting: if view == 0: camera.wrtReparentTo(render) camera.lookAt(lookAt) elif view == 1: camera.reparentTo(render) camera.setPos(render, 100, 100, 35.25) camera.lookAt(render, lookAt) elif view == 2: if hpr[1] > -90: camera.setPos(0, 0, -30) if camera.getZ() < lookAt[2]: camera.setZ(render, lookAt[2] + 10) camera.lookAt(Point3(0, 0, 0)) return Task.cont def __stopFlyTask(self, avId): taskMgr.remove(self.taskName('flyingToon') + '-' + str(avId)) def __hitGround(self, avatar, pos, extraArgs = []): hitP = avatar.getPos(render) h = self.barrel.getH(render) avatar.setPos(pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) avatar.setHpr(h, -135, 0) self.dustCloud.setPos(render, pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) self.dustCloud.setScale(0.35) self.dustCloud.play() base.playSfx(self.sndHitGround) avatar.hide() def __hitChair(self, avatar, pos, extraArgs = []): hitP = avatar.getPos(render) h = self.barrel.getH(render) avatar.setPos(pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) avatar.setHpr(h, -135, 0) self.dustCloud.setPos(render, pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) self.dustCloud.setScale(0.35) self.dustCloud.play() base.playSfx(self.sndHitGround) base.playSfx(self.sndHitChair) avatar.hide() def generateCannonAppearTrack(self, avatar): self.cannon.setScale(0.1) self.cannon.show() kartTrack = Parallel(Sequence(ActorInterval(avatar, 'feedPet'), Func(avatar.loop, 'neutral')), Sequence(Func(self.cannon.reparentTo, avatar.rightHand), Wait(2.1), Func(self.cannon.wrtReparentTo, render), Func(self.cannon.setShear, 0, 0, 0), Parallel(LerpHprInterval(self.cannon, hpr=self.nodePath.getHpr(render), duration=1.2), ProjectileInterval(self.cannon, endPos=self.nodePath.getPos(render), duration=1.2, gravityMult=0.45)), Wait(0.2), Sequence(LerpScaleInterval(self.cannon, scale=Point3(1.1, 1.1, 0.1), duration=0.2), LerpScaleInterval(self.cannon, scale=Point3(0.9, 0.9, 0.1), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 0.1), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 1.1), duration=0.2), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 0.9), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 1.0), duration=0.1), Func(self.cannon.wrtReparentTo, self.nodePath)))) return kartTrack