import math import random from panda3d.core import VBase3, CollisionPlane, CollisionNode, CollisionSphere, CollisionTube, NodePath, Plane, Vec3, Vec2, Point3, BitMask32, CollisionHandlerEvent, TextureStage, VBase4, BoundingSphere from panda3d.otp import NametagGroup, CFSpeech from direct.interval.IntervalGlobal import Sequence, Wait, Func, LerpHprInterval, Parallel, LerpPosInterval, Track, ActorInterval, ParallelEndTogether, LerpFunctionInterval, LerpScaleInterval, LerpPosHprInterval, SoundInterval from direct.task import Task from direct.fsm import FSM from direct.directnotify import DirectNotifyGlobal from direct.distributed.ClockDelta import globalClockDelta from direct.showbase import PythonUtil from direct.task import Task from toontown.distributed import DelayDelete from toontown.toonbase import ToontownGlobals from toontown.suit import DistributedBossCog from toontown.toonbase import TTLocalizer from toontown.toonbase import ToontownGlobals from toontown.suit import SuitDNA from toontown.toon import Toon from toontown.toon import ToonDNA from toontown.building import ElevatorConstants from toontown.toonbase import ToontownTimer from toontown.toonbase import ToontownBattleGlobals from toontown.battle import RewardPanel from toontown.battle import MovieToonVictory from toontown.coghq import CogDisguiseGlobals from toontown.suit import Suit from toontown.suit import SuitDNA from toontown.effects import DustCloud OneBossCog = None TTL = TTLocalizer class DistributedBossbotBoss(DistributedBossCog.DistributedBossCog, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBossbotBoss') BallLaunchOffset = Point3(10.5, 8.5, -5) def __init__(self, cr): self.notify.debug('----- __init___') DistributedBossCog.DistributedBossCog.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedBossbotBoss') self.bossDamage = 0 self.bossMaxDamage = ToontownGlobals.BossbotBossMaxDamage self.elevatorType = ElevatorConstants.ELEVATOR_BB self.resistanceToon = None self.resistanceToonOnstage = 0 self.battleANode.setPosHpr(*ToontownGlobals.WaiterBattleAPosHpr) self.battleBNode.setPosHpr(*ToontownGlobals.WaiterBattleBPosHpr) self.toonFoodStatus = {} self.belts = [None, None] self.tables = {} self.golfSpots = {} self.servingTimer = None self.notDeadList = None self.moveTrack = None self.speedDamage = 0 self.maxSpeedDamage = ToontownGlobals.BossbotMaxSpeedDamage self.speedRecoverRate = 0 self.speedRecoverStartTime = 0 self.ballLaunch = None self.moveTrack = None self.lastZapLocalTime = 0 self.numAttacks = 0 return def announceGenerate(self): global OneBossCog DistributedBossCog.DistributedBossCog.announceGenerate(self) self.loadEnvironment() self.__makeResistanceToon() localAvatar.chatMgr.chatInputSpeedChat.addCEOMenu() if OneBossCog != None: self.notify.warning('Multiple BossCogs visible.') OneBossCog = self render.setTag('pieCode', str(ToontownGlobals.PieCodeNotBossCog)) self.setTag('attackCode', str(ToontownGlobals.BossCogGolfAttack)) target = CollisionTube(0, -2, -2, 0, -1, 9, 4.0) targetNode = CollisionNode('BossZap') targetNode.addSolid(target) targetNode.setCollideMask(ToontownGlobals.PieBitmask) self.targetNodePath = self.pelvis.attachNewNode(targetNode) self.targetNodePath.setTag('pieCode', str(ToontownGlobals.PieCodeBossCog)) self.axle.getParent().setTag('pieCode', str(ToontownGlobals.PieCodeBossCog)) disk = loader.loadModel('phase_9/models/char/bossCog-gearCollide') disk.find('**/+CollisionNode').setName('BossZap') disk.reparentTo(self.pelvis) disk.setZ(0.8) closeBubble = CollisionSphere(0, 0, 0, 10) closeBubble.setTangible(0) closeBubbleNode = CollisionNode('CloseBoss') closeBubbleNode.setIntoCollideMask(BitMask32(0)) closeBubbleNode.setFromCollideMask(ToontownGlobals.BanquetTableBitmask) closeBubbleNode.addSolid(closeBubble) self.closeBubbleNode = closeBubbleNode self.closeHandler = CollisionHandlerEvent() self.closeHandler.addInPattern('closeEnter') self.closeHandler.addOutPattern('closeExit') self.closeBubbleNodePath = self.attachNewNode(closeBubbleNode) (base.cTrav.addCollider(self.closeBubbleNodePath, self.closeHandler),) self.accept('closeEnter', self.closeEnter) self.accept('closeExit', self.closeExit) self.treads = self.find('**/treads') demotedCeo = Suit.Suit() demotedCeo.dna = SuitDNA.SuitDNA() demotedCeo.dna.newSuit('f') demotedCeo.setDNA(demotedCeo.dna) demotedCeo.reparentTo(self.geom) demotedCeo.loop('neutral') demotedCeo.stash() self.demotedCeo = demotedCeo self.bossClub = loader.loadModel('phase_12/models/char/bossbotBoss-golfclub') overtimeOneClubSequence = Sequence(self.bossClub.colorScaleInterval(0.1, colorScale=VBase4(0, 1, 0, 1)), self.bossClub.colorScaleInterval(0.3, colorScale=VBase4(1, 1, 1, 1))) overtimeTwoClubSequence = Sequence(self.bossClub.colorScaleInterval(0.1, colorScale=VBase4(1, 0, 0, 1)), self.bossClub.colorScaleInterval(0.3, colorScale=VBase4(1, 1, 1, 1))) self.bossClubIntervals = [overtimeOneClubSequence, overtimeTwoClubSequence] self.rightHandJoint = self.find('**/joint17') self.setPosHpr(*ToontownGlobals.BossbotBossBattleOnePosHpr) self.reparentTo(render) self.toonUpSfx = loader.loadSfx('phase_11/audio/sfx/LB_toonup.ogg') self.warningSfx = loader.loadSfx('phase_5/audio/sfx/Skel_COG_VO_grunt.ogg') self.swingClubSfx = loader.loadSfx('phase_5/audio/sfx/SA_hardball.ogg') self.moveBossTaskName = 'CEOMoveTask' return def disable(self): global OneBossCog self.notify.debug('----- disable') DistributedBossCog.DistributedBossCog.disable(self) self.demotedCeo.delete() base.cTrav.removeCollider(self.closeBubbleNodePath) taskMgr.remove('RecoverSpeedDamage') self.request('Off') self.unloadEnvironment() self.__cleanupResistanceToon() if self.servingTimer: self.servingTimer.destroy() del self.servingTimer localAvatar.chatMgr.chatInputSpeedChat.removeCEOMenu() if OneBossCog == self: OneBossCog = None self.promotionMusic.stop() self.betweenPhaseMusic.stop() self.phaseTwoMusic.stop() self.phaseFourMusic.stop() self.interruptMove() for ival in self.bossClubIntervals: ival.finish() self.belts = [] self.tables = {} self.removeAllTasks() return def loadEnvironment(self): self.notify.debug('----- loadEnvironment') DistributedBossCog.DistributedBossCog.loadEnvironment(self) self.geom = loader.loadModel('phase_12/models/bossbotHQ/BanquetInterior_1') self.elevatorEntrance = self.geom.find('**/elevator_origin') elevatorModel = loader.loadModel('phase_12/models/bossbotHQ/BB_Inside_Elevator') if not elevatorModel: elevatorModel = loader.loadModel('phase_12/models/bossbotHQ/BB_Elevator') elevatorModel.reparentTo(self.elevatorEntrance) self.setupElevator(elevatorModel) self.banquetDoor = self.geom.find('**/door3') plane = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, -50))) planeNode = CollisionNode('dropPlane') planeNode.addSolid(plane) planeNode.setCollideMask(ToontownGlobals.PieBitmask) self.geom.attachNewNode(planeNode) self.geom.reparentTo(render) self.promotionMusic = base.loader.loadMusic('phase_7/audio/bgm/encntr_suit_winning_indoor.ogg') self.betweenPhaseMusic = base.loader.loadMusic('phase_9/audio/bgm/encntr_toon_winning.ogg') self.phaseTwoMusic = base.loader.loadMusic('phase_12/audio/bgm/BossBot_CEO_v1.ogg') self.phaseFourMusic = base.loader.loadMusic('phase_12/audio/bgm/BossBot_CEO_v2.ogg') self.pickupFoodSfx = loader.loadSfx('phase_6/audio/sfx/SZ_MM_gliss.ogg') self.explodeSfx = loader.loadSfx('phase_4/audio/sfx/firework_distance_02.ogg') def unloadEnvironment(self): self.notify.debug('----- unloadEnvironment') for belt in self.belts: if belt: belt.cleanup() for spot in list(self.golfSpots.values()): if spot: spot.cleanup() self.golfSpots = {} self.geom.removeNode() del self.geom DistributedBossCog.DistributedBossCog.unloadEnvironment(self) def __makeResistanceToon(self): if self.resistanceToon: return npc = Toon.Toon() npc.setName(TTLocalizer.BossbotResistanceToonName) npc.setPickable(0) npc.setPlayerType(NametagGroup.CCNonPlayer) dna = ToonDNA.ToonDNA() dna.newToonRandom(335933, 'm', 1) dna.head = 'sls' npc.setDNAString(dna.makeNetString()) npc.animFSM.request('neutral') npc.loop('neutral') self.resistanceToon = npc self.resistanceToon.setPosHpr(*ToontownGlobals.BossbotRTIntroStartPosHpr) state = random.getstate() random.seed(self.doId) self.resistanceToon.suitType = SuitDNA.getRandomSuitByDept('c') random.setstate(state) def __cleanupResistanceToon(self): self.__hideResistanceToon() if self.resistanceToon: self.resistanceToon.takeOffSuit() self.resistanceToon.removeActive() self.resistanceToon.delete() self.resistanceToon = None return def __showResistanceToon(self, withSuit): if not self.resistanceToonOnstage: self.resistanceToon.addActive() self.resistanceToon.reparentTo(self.geom) self.resistanceToonOnstage = 1 if withSuit: suit = self.resistanceToon.suitType self.resistanceToon.putOnSuit(suit, False) else: self.resistanceToon.takeOffSuit() def __hideResistanceToon(self): if self.resistanceToonOnstage: self.resistanceToon.removeActive() self.resistanceToon.detachNode() self.resistanceToonOnstage = 0 def enterElevator(self): DistributedBossCog.DistributedBossCog.enterElevator(self) self.resistanceToon.removeActive() self.__showResistanceToon(True) self.resistanceToon.suit.loop('neutral') base.camera.setPos(0, 21, 7) self.reparentTo(render) self.setPosHpr(*ToontownGlobals.BossbotBossBattleOnePosHpr) self.loop('Ff_neutral') self.show() def enterIntroduction(self): if not self.resistanceToonOnstage: self.__showResistanceToon(True) DistributedBossCog.DistributedBossCog.enterIntroduction(self) base.playMusic(self.promotionMusic, looping=1, volume=0.9) def exitIntroduction(self): DistributedBossCog.DistributedBossCog.exitIntroduction(self) self.promotionMusic.stop() def makeIntroductionMovie(self, delayDeletes): rToon = self.resistanceToon rToonStartPos = Point3(ToontownGlobals.BossbotRTIntroStartPosHpr[0], ToontownGlobals.BossbotRTIntroStartPosHpr[1], ToontownGlobals.BossbotRTIntroStartPosHpr[2]) rToonEndPos = rToonStartPos + Point3(40, 0, 0) elevCamPosHpr = ToontownGlobals.BossbotElevCamPosHpr closeUpRTCamPos = Point3(elevCamPosHpr[0], elevCamPosHpr[1], elevCamPosHpr[2]) closeUpRTCamHpr = Point3(elevCamPosHpr[3], elevCamPosHpr[4], elevCamPosHpr[5]) closeUpRTCamPos.setY(closeUpRTCamPos.getY() + 20) closeUpRTCamPos.setZ(closeUpRTCamPos.getZ() + -2) closeUpRTCamHpr = Point3(0, 5, 0) loseSuitCamPos = Point3(rToonStartPos) loseSuitCamPos += Point3(0, -5, 4) loseSuitCamHpr = Point3(180, 0, 0) waiterCamPos = Point3(rToonStartPos) waiterCamPos += Point3(-5, -10, 5) waiterCamHpr = Point3(-30, 0, 0) track = Sequence(Func(camera.reparentTo, render), Func(camera.setPosHpr, *elevCamPosHpr), Func(rToon.setChatAbsolute, TTL.BossbotRTWelcome, CFSpeech), LerpPosHprInterval(camera, 3, closeUpRTCamPos, closeUpRTCamHpr), Func(rToon.setChatAbsolute, TTL.BossbotRTRemoveSuit, CFSpeech), Wait(3), Func(self.clearChat), self.loseCogSuits(self.toonsA + self.toonsB, render, (loseSuitCamPos[0], loseSuitCamPos[1], loseSuitCamPos[2], loseSuitCamHpr[0], loseSuitCamHpr[1], loseSuitCamHpr[2])), self.toonNormalEyes(self.involvedToons), Wait(2), Func(camera.setPosHpr, closeUpRTCamPos, closeUpRTCamHpr), Func(rToon.setChatAbsolute, TTL.BossbotRTFightWaiter, CFSpeech), Wait(1), LerpHprInterval(camera, 2, Point3(-15, 5, 0)), Sequence(Func(rToon.suit.loop, 'walk'), rToon.hprInterval(1, VBase3(270, 0, 0)), rToon.posInterval(2.5, rToonEndPos), Func(rToon.suit.loop, 'neutral')), Wait(3), Func(rToon.clearChat), Func(self.__hideResistanceToon)) return track def enterFrolic(self): self.notify.debug('----- enterFrolic') self.setPosHpr(*ToontownGlobals.BossbotBossBattleOnePosHpr) DistributedBossCog.DistributedBossCog.enterFrolic(self) self.show() def enterPrepareBattleTwo(self): self.controlToons() self.setToonsToNeutral(self.involvedToons) for toonId in self.involvedToons: toon = self.cr.doId2do.get(toonId) if toon: toon.takeOffSuit() self.__showResistanceToon(True) self.resistanceToon.setPosHpr(*ToontownGlobals.BossbotRTPreTwoPosHpr) self.__arrangeToonsAroundResistanceToon() intervalName = 'PrepareBattleTwoMovie' delayDeletes = [] seq = Sequence(self.makePrepareBattleTwoMovie(delayDeletes), Func(self.__onToBattleTwo), name=intervalName) seq.delayDeletes = delayDeletes seq.start() self.storeInterval(seq, intervalName) base.playMusic(self.betweenPhaseMusic, looping=1, volume=0.9) def makePrepareBattleTwoMovie(self, delayDeletes): for toonId in self.involvedToons: toon = self.cr.doId2do.get(toonId) if toon: delayDeletes.append(DelayDelete.DelayDelete(toon, 'BossbotBoss.makePrepareBattleTwoMovie')) rToon = self.resistanceToon rToonStartPos = Point3(ToontownGlobals.BossbotRTPreTwoPosHpr[0], ToontownGlobals.BossbotRTPreTwoPosHpr[1], ToontownGlobals.BossbotRTPreTwoPosHpr[2]) rToonEndPos = rToonStartPos + Point3(-40, 0, 0) bossPos = Point3(ToontownGlobals.BossbotBossPreTwoPosHpr[0], ToontownGlobals.BossbotBossPreTwoPosHpr[1], ToontownGlobals.BossbotBossPreTwoPosHpr[2]) bossEndPos = Point3(ToontownGlobals.BossbotBossBattleOnePosHpr[0], ToontownGlobals.BossbotBossBattleOnePosHpr[1], ToontownGlobals.BossbotBossBattleOnePosHpr[2]) tempNode = self.attachNewNode('temp') tempNode.setPos(0, -40, 18) def getCamBossPos(tempNode = tempNode): return tempNode.getPos(render) rNode = rToon.attachNewNode('temp2') rNode.setPos(-5, 25, 12) def getCamRTPos(rNode = rNode): return rNode.getPos(render) track = Sequence( Func(camera.reparentTo, render), Func(camera.setPos, rToon, 0, 22, 6), Func(camera.setHpr, 0, 0, 0), Func(rToon.setChatAbsolute, TTL.BossbotRTWearWaiter, CFSpeech), Wait(3.0), self.wearCogSuits(self.toonsA + self.toonsB, render, None, waiter=True), Func(rToon.clearChat), Func(self.setPosHpr, bossPos, Point3(0, 0, 0)), Parallel(LerpHprInterval(self.banquetDoor, 2, Point3(90, 0, 0)), LerpPosInterval(camera, 2, getCamBossPos)), Func(self.setChatAbsolute, TTL.BossbotBossPreTwo1, CFSpeech), Wait(3.0), Func(self.setChatAbsolute, TTL.BossbotBossPreTwo2, CFSpeech), Wait(3.0), Parallel( LerpHprInterval(self.banquetDoor, 2, Point3(0, 0, 0)), LerpPosHprInterval(camera, 2, getCamRTPos, Point3(10, -8, 0))), Func(self.setPos, bossEndPos), Func(self.clearChat), Func(rToon.setChatAbsolute, TTL.BossbotRTServeFood1, CFSpeech), Wait(3.0), Func(rToon.setChatAbsolute, TTL.BossbotRTServeFood2, CFSpeech), Wait(1.0), LerpHprInterval(self.banquetDoor, 2, Point3(120, 0, 0)), Sequence( Func(rToon.suit.loop, 'walk'), rToon.hprInterval(1, VBase3(90, 0, 0)), rToon.posInterval(2.5, rToonEndPos), Func(rToon.suit.loop, 'neutral')), self.createWalkInInterval(), Func(self.banquetDoor.setH, 0), Func(rToon.clearChat), Func(self.__hideResistanceToon)) return track def createWalkInInterval(self): retval = Parallel() delay = 0 index = 0 for toonId in self.involvedToons: toon = base.cr.doId2do.get(toonId) if not toon: continue destPos = Point3(-14 + index * 4, 25, 0) def toWalk(toon): if hasattr(toon, 'suit') and toon.suit: toon.suit.loop('walk') def toNeutral(toon): if hasattr(toon, 'suit') and toon.suit: toon.suit.loop('neutral') retval.append(Sequence(Wait(delay), Func(toon.wrtReparentTo, render), Func(toWalk, toon), Func(toon.headsUp, 0, 0, 0), LerpPosInterval(toon, 3, Point3(0, 0, 0)), Func(toon.headsUp, destPos), LerpPosInterval(toon, 3, destPos), LerpHprInterval(toon, 1, Point3(0, 0, 0)), Func(toNeutral, toon))) if toon == base.localAvatar: retval.append(Sequence(Wait(delay), Func(camera.reparentTo, toon), Func(camera.setPos, toon.cameraPositions[0][0]), Func(camera.setHpr, 0, 0, 0))) delay += 1.0 index += 1 return retval def __onToBattleTwo(self, elapsedTime = 0): self.doneBarrier('PrepareBattleTwo') def exitPrepareBattleTwo(self): self.clearInterval('PrepareBattleTwoMovie') self.betweenPhaseMusic.stop() def __arrangeToonsAroundResistanceToon(self): radius = 9 numToons = len(self.involvedToons) center = (numToons - 1) / 2.0 for i in range(numToons): toon = self.cr.doId2do.get(self.involvedToons[i]) if toon: angle = 90 - 25 * (i - center) radians = angle * math.pi / 180.0 x = math.cos(radians) * radius y = math.sin(radians) * radius toon.reparentTo(render) toon.setPos(self.resistanceToon, x, y, 0) toon.headsUp(self.resistanceToon) toon.loop('neutral') toon.show() def enterBattleTwo(self): self.releaseToons(finalBattle=1) for toonId in self.involvedToons: toon = self.cr.doId2do.get(toonId) if toon: self.putToonInCogSuit(toon) self.servingTimer = ToontownTimer.ToontownTimer() self.servingTimer.posInTopRightCorner() self.servingTimer.countdown(ToontownGlobals.BossbotBossServingDuration) base.playMusic(self.phaseTwoMusic, looping=1, volume=0.9) def exitBattleTwo(self): if self.servingTimer: self.servingTimer.destroy() del self.servingTimer self.servingTimer = None for toonId in self.involvedToons: self.removeFoodFromToon(toonId) self.phaseTwoMusic.stop() return def setBelt(self, belt, beltIndex): if beltIndex < len(self.belts): self.belts[beltIndex] = belt def localToonTouchedBeltFood(self, beltIndex, foodIndex, foodNum): avId = base.localAvatar.doId doRequest = False if avId not in self.toonFoodStatus: doRequest = True elif not self.toonFoodStatus[avId]: doRequest = True if doRequest: self.sendUpdate('requestGetFood', [beltIndex, foodIndex, foodNum]) def toonGotFood(self, avId, beltIndex, foodIndex, foodNum): if self.belts[beltIndex]: self.belts[beltIndex].removeFood(foodIndex) self.putFoodOnToon(avId, beltIndex, foodNum) def putFoodOnToon(self, avId, beltIndex, foodNum): self.toonFoodStatus[avId] = (beltIndex, foodNum) av = base.cr.doId2do.get(avId) if av: intervalName = self.uniqueName('loadFoodSoundIval-%d' % avId) seq = SoundInterval(self.pickupFoodSfx, node=av, name=intervalName) oldSeq = self.activeIntervals.get(intervalName) if oldSeq: oldSeq.finish() seq.start() self.activeIntervals[intervalName] = seq foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood') foodModel.setName('cogFood') foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(av.suit.getRightHand()) foodModel.setHpr(52.1961, 180.4983, -4.2882) curAnim = av.suit.getCurrentAnim() self.notify.debug('curAnim=%s' % curAnim) if curAnim in ('walk', 'run'): av.suit.loop('tray-walk') elif curAnim == 'neutral': self.notify.debug('looping tray-netural') av.suit.loop('tray-neutral') else: self.notify.warning("don't know what to do with anim=%s" % curAnim) def removeFoodFromToon(self, avId): self.toonFoodStatus[avId] = None av = base.cr.doId2do.get(avId) if av: cogFood = av.find('**/cogFood') if not cogFood.isEmpty(): cogFood.removeNode() return def detachFoodFromToon(self, avId): cogFood = None self.toonFoodStatus[avId] = None av = base.cr.doId2do.get(avId) if av: cogFood = av.find('**/cogFood') if not cogFood.isEmpty(): retval = cogFood cogFood.wrtReparentTo(render) curAnim = av.suit.getCurrentAnim() self.notify.debug('curAnim=%s' % curAnim) if curAnim == 'tray-walk': av.suit.loop('run') elif curAnim == 'tray-neutral': av.suit.loop('neutral') else: self.notify.warning("don't know what to do with anim=%s" % curAnim) return cogFood def setTable(self, table, tableIndex): self.tables[tableIndex] = table def localToonTouchedChair(self, tableIndex, chairIndex): avId = base.localAvatar.doId if avId in self.toonFoodStatus and self.toonFoodStatus[avId] != None: self.sendUpdate('requestServeFood', [tableIndex, chairIndex]) return def toonServeFood(self, avId, tableIndex, chairIndex): food = self.detachFoodFromToon(avId) table = self.tables[tableIndex] table.serveFood(food, chairIndex) def enterPrepareBattleThree(self): self.calcNotDeadList() self.battleANode.setPosHpr(*ToontownGlobals.DinerBattleAPosHpr) self.battleBNode.setPosHpr(*ToontownGlobals.DinerBattleBPosHpr) self.cleanupIntervals() self.controlToons() self.setToonsToNeutral(self.involvedToons) for toonId in self.involvedToons: toon = self.cr.doId2do.get(toonId) if toon: self.putToonInCogSuit(toon) intervalName = 'PrepareBattleThreeMovie' seq = Sequence(self.makePrepareBattleThreeMovie(), Func(self.__onToBattleThree), name=intervalName) seq.start() self.storeInterval(seq, intervalName) base.playMusic(self.betweenPhaseMusic, looping=1, volume=0.9) def calcNotDeadList(self): if not self.notDeadList: self.notDeadList = [] for tableIndex in range(len(self.tables)): table = self.tables[tableIndex] tableInfo = table.getNotDeadInfo() self.notDeadList += tableInfo def exitPrepareBattleThree(self): self.clearInterval('PrepareBattleThreeMovie') self.betweenPhaseMusic.stop() def __onToBattleThree(self, elapsedTime = 0): self.doneBarrier('PrepareBattleThree') def makePrepareBattleThreeMovie(self): loseSuitCamAngle = (0, 19, 6, -180, -5, 0) track = Sequence( Func(camera.reparentTo, self), Func(camera.setPos, Point3(0, -45, 5)), Func(camera.setHpr, Point3(0, 14, 0)), Func(self.setChatAbsolute, TTL.BossbotPhase3Speech1, CFSpeech), Wait(3.0), Func(self.setChatAbsolute, TTL.BossbotPhase3Speech2, CFSpeech), Wait(3.0), Func(camera.setPosHpr, base.localAvatar, *loseSuitCamAngle), Wait(1.0), self.loseCogSuits(self.toonsA + self.toonsB, base.localAvatar, loseSuitCamAngle), self.toonNormalEyes(self.involvedToons), Wait(2), Func(camera.reparentTo, self), Func(camera.setPos, Point3(0, -45, 5)), Func(camera.setHpr, Point3(0, 14, 0)), Func(self.setChatAbsolute, TTL.BossbotPhase3Speech3, CFSpeech), Wait(3.0), Func(self.clearChat)) return track def enterBattleThree(self): self.cleanupIntervals() self.calcNotDeadList() for table in list(self.tables.values()): table.setAllDinersToSitNeutral() self.battleANode.setPosHpr(*ToontownGlobals.DinerBattleAPosHpr) self.battleBNode.setPosHpr(*ToontownGlobals.DinerBattleBPosHpr) self.setToonsToNeutral(self.involvedToons) for toonId in self.involvedToons: toon = self.cr.doId2do.get(toonId) if toon: toon.takeOffSuit() mult = 1 localAvatar.inventory.setBattleCreditMultiplier(mult) self.toonsToBattlePosition(self.toonsA, self.battleANode) self.toonsToBattlePosition(self.toonsB, self.battleBNode) self.releaseToons() base.playMusic(self.battleOneMusic, looping=1, volume=0.9) def exitBattleThree(self): self.cleanupBattles() self.battleOneMusic.stop() localAvatar.inventory.setBattleCreditMultiplier(1) def claimOneChair(self): chairInfo = None if self.notDeadList: chairInfo = self.notDeadList.pop() return chairInfo def enterPrepareBattleFour(self): self.controlToons() intervalName = 'PrepareBattleFourMovie' seq = Sequence(self.makePrepareBattleFourMovie(), Func(self.__onToBattleFour), name=intervalName) seq.start() self.storeInterval(seq, intervalName) base.playMusic(self.phaseFourMusic, looping=1, volume=0.9) def exitPrepareBattleFour(self): self.clearInterval('PrepareBattleFourMovie') self.phaseFourMusic.stop() def makePrepareBattleFourMovie(self): rToon = self.resistanceToon offsetZ = rToon.suit.getHeight() / 2.0 track = Sequence( Func(self.__showResistanceToon, True), Func(rToon.setPos, Point3(0, -5, 0)), Func(rToon.setHpr, Point3(0, 0, 0)), Func(camera.reparentTo, rToon), Func(camera.setPos, Point3(0, 13, 3 + offsetZ)), Func(camera.setHpr, Point3(-180, 0, 0)), Func(self.banquetDoor.setH, 90), Func(rToon.setChatAbsolute, TTL.BossbotRTPhase4Speech1, CFSpeech), Wait(4.0), Func(rToon.setChatAbsolute, TTL.BossbotRTPhase4Speech2, CFSpeech), Wait(4.0), Func(self.__hideResistanceToon), Func(camera.reparentTo, self), Func(camera.setPos, Point3(0, -45, 5)), Func(camera.setHpr, Point3(0, 14, 0)), Func(self.setChatAbsolute, TTL.BossbotPhase4Speech1, CFSpeech), Func(self.banquetDoor.setH, 0), Wait(3.0), Func(self.setChatAbsolute, TTL.BossbotPhase4Speech2, CFSpeech), Func(self.bossClub.setScale, 0.01), Func(self.bossClub.reparentTo, self.rightHandJoint), LerpScaleInterval(self.bossClub, 3, Point3(1, 1, 1)), Func(self.clearChat)) return track def __onToBattleFour(self, elapsedTime = 0): self.doneBarrier('PrepareBattleFour') def enterBattleFour(self): DistributedBossCog.DistributedBossCog.enterBattleFour(self) self.releaseToons(finalBattle=1) self.setToonsToNeutral(self.involvedToons) for toonId in self.involvedToons: toon = self.cr.doId2do.get(toonId) if toon: toon.takeOffSuit() self.bossClub.reparentTo(self.rightHandJoint) self.generateHealthBar() self.updateHealthBar() base.playMusic(self.phaseFourMusic, looping=1, volume=0.9) def exitBattleFour(self): DistributedBossCog.DistributedBossCog.exitBattleFour(self) self.phaseFourMusic.stop() def d_hitBoss(self, bossDamage): self.sendUpdate('hitBoss', [bossDamage]) def d_ballHitBoss(self, bossDamage): self.sendUpdate('ballHitBoss', [bossDamage]) def setBossDamage(self, bossDamage, recoverRate, recoverStartTime): if bossDamage > self.bossDamage: delta = bossDamage - self.bossDamage self.flashRed() self.showHpText(-delta, scale=5) self.bossDamage = bossDamage self.updateHealthBar() def setGolfSpot(self, golfSpot, golfSpotIndex): self.golfSpots[golfSpotIndex] = golfSpot def enterVictory(self): self.notify.debug('----- enterVictory') self.cleanupIntervals() self.cleanupAttacks() self.doAnimate('Ff_neutral', now=1) self.stopMoveTask() if hasattr(self, 'tableIndex'): table = self.tables[self.tableIndex] table.tableGroup.hide() self.loop('neutral') localAvatar.setCameraFov(ToontownGlobals.BossBattleCameraFov) self.clearChat() self.controlToons() self.setToonsToNeutral(self.involvedToons) self.happy = 1 self.raised = 1 self.forward = 1 intervalName = 'VictoryMovie' seq = Sequence(self.makeVictoryMovie(), Func(self.__continueVictory), name=intervalName) seq.start() self.storeInterval(seq, intervalName) base.playMusic(self.phaseFourMusic, looping=1, volume=0.9) def __continueVictory(self): self.notify.debug('----- __continueVictory') self.stopAnimate() self.doneBarrier('Victory') def exitVictory(self): self.notify.debug('----- exitVictory') self.stopAnimate() self.unstash() localAvatar.setCameraFov(ToontownGlobals.CogHQCameraFov) self.phaseFourMusic.stop() def makeVictoryMovie(self): self.show() dustCloud = DustCloud.DustCloud(fBillboard=0, wantSound=1) dustCloud.reparentTo(self) dustCloud.setPos(0, -10, 3) dustCloud.setScale(4) dustCloud.wrtReparentTo(self.geom) dustCloud.createTrack(12) newHpr = self.getHpr() newHpr.setX(newHpr.getX() + 180) bossTrack = Sequence( Func(self.show), Func(camera.reparentTo, self), Func(camera.setPos, Point3(0, -35, 25)), Func(camera.setHpr, Point3(0, -20, 0)), Func(self.setChatAbsolute, TTL.BossbotRewardSpeech1, CFSpeech), Wait(3.0), Func(self.setChatAbsolute, TTL.BossbotRewardSpeech2, CFSpeech), Wait(2.0), Func(self.clearChat), Parallel( Sequence( Wait(0.5), Func(self.demotedCeo.setPos, self.getPos()), Func(self.demotedCeo.setHpr, newHpr), Func(self.hide), Wait(0.5), Func(self.demotedCeo.reparentTo, self.geom), Func(self.demotedCeo.unstash)), Sequence(dustCloud.track)), Wait(2.0), Func(dustCloud.destroy)) return bossTrack def enterReward(self): self.cleanupIntervals() self.clearChat() self.resistanceToon.clearChat() self.stash() self.stopAnimate() self.controlToons() panelName = self.uniqueName('reward') self.rewardPanel = RewardPanel.RewardPanel(panelName) victory, camVictory, skipper = MovieToonVictory.doToonVictory(1, self.involvedToons, self.toonRewardIds, self.toonRewardDicts, self.deathList, self.rewardPanel, allowGroupShot=0, uberList=self.uberList, noSkip=True) ival = Sequence(Parallel(victory, camVictory), Func(self.__doneReward)) intervalName = 'RewardMovie' delayDeletes = [] for toonId in self.involvedToons: toon = self.cr.doId2do.get(toonId) if toon: delayDeletes.append(DelayDelete.DelayDelete(toon, 'BossbotBoss.enterReward')) ival.delayDeletes = delayDeletes ival.start() self.storeInterval(ival, intervalName) base.playMusic(self.betweenPhaseMusic, looping=1, volume=0.9) def __doneReward(self): self.notify.debug('----- __doneReward') self.doneBarrier('Reward') self.toWalkMode() def exitReward(self): self.notify.debug('----- exitReward') intervalName = 'RewardMovie' self.clearInterval(intervalName) self.unstash() self.rewardPanel.destroy() del self.rewardPanel self.betweenPhaseMusic.stop() def enterEpilogue(self): self.cleanupIntervals() self.clearChat() self.resistanceToon.clearChat() self.stash() self.stopAnimate() self.controlToons() self.__showResistanceToon(False) self.resistanceToon.reparentTo(render) self.resistanceToon.setPosHpr(*ToontownGlobals.BossbotRTEpiloguePosHpr) self.resistanceToon.loop('Sit') self.__arrangeToonsAroundResistanceToonForReward() camera.reparentTo(render) camera.setPos(self.resistanceToon, -9, 12, 6) camera.lookAt(self.resistanceToon, 0, 0, 3) intervalName = 'EpilogueMovie' seq = Sequence(self.makeEpilogueMovie(), name=intervalName) seq.start() self.storeInterval(seq, intervalName) self.accept('doneChatPage', self.__doneEpilogue) base.playMusic(self.epilogueMusic, looping=1, volume=0.9) def __doneEpilogue(self, elapsedTime = 0): self.notify.debug('----- __doneEpilogue') intervalName = 'EpilogueMovieToonAnim' self.clearInterval(intervalName) track = Parallel(Sequence(Wait(0.5), Func(self.localToonToSafeZone))) self.storeInterval(track, intervalName) track.start() def exitEpilogue(self): self.notify.debug('----- exitEpilogue') self.clearInterval('EpilogueMovieToonAnim') self.unstash() self.epilogueMusic.stop() def makeEpilogueMovie(self): epSpeech = TTLocalizer.BossbotRTCongratulations epSpeech = self.__talkAboutPromotion(epSpeech) bossTrack = Sequence(Func(self.resistanceToon.animFSM.request, 'neutral'), Func(self.resistanceToon.setLocalPageChat, epSpeech, 0)) return bossTrack def __talkAboutPromotion(self, speech): if self.prevCogSuitLevel < ToontownGlobals.MaxCogSuitLevel: newCogSuitLevel = localAvatar.getCogLevels()[CogDisguiseGlobals.dept2deptIndex(self.style.dept)] if newCogSuitLevel == ToontownGlobals.MaxCogSuitLevel: speech += TTLocalizer.BossbotRTLastPromotion % (ToontownGlobals.MaxCogSuitLevel + 1) if newCogSuitLevel in ToontownGlobals.CogSuitHPLevels: speech += TTLocalizer.BossbotRTHPBoost else: speech += TTLocalizer.BossbotRTMaxed % (ToontownGlobals.MaxCogSuitLevel + 1) return speech def __arrangeToonsAroundResistanceToonForReward(self): radius = 7 numToons = len(self.involvedToons) center = (numToons - 1) / 2.0 for i in range(numToons): toon = self.cr.doId2do.get(self.involvedToons[i]) if toon: angle = 90 - 15 * (i - center) radians = angle * math.pi / 180.0 x = math.cos(radians) * radius y = math.sin(radians) * radius toon.setPos(self.resistanceToon, x, y, 0) toon.headsUp(self.resistanceToon) toon.loop('neutral') toon.show() def doDirectedAttack(self, avId, attackCode): toon = base.cr.doId2do.get(avId) if toon: distance = toon.getDistance(self) gearRoot = self.rotateNode.attachNewNode('gearRoot-atk%d' % self.numAttacks) gearRoot.setZ(10) gearRoot.setTag('attackCode', str(attackCode)) gearModel = self.getGearFrisbee() gearModel.setScale(0.2) gearRoot.headsUp(toon) toToonH = PythonUtil.fitDestAngle2Src(0, gearRoot.getH() + 180) gearRoot.lookAt(toon) neutral = 'Fb_neutral' if not self.twoFaced: neutral = 'Ff_neutral' gearTrack = Parallel() for i in range(4): nodeName = '%s-%s' % (str(i), globalClock.getFrameTime()) node = gearRoot.attachNewNode(nodeName) node.hide() node.setPos(0, 5.85, 4.0) gear = gearModel.instanceTo(node) x = random.uniform(-5, 5) z = random.uniform(-3, 3) h = random.uniform(-720, 720) if i == 2: x = 0 z = 0 def detachNode(node): if not node.isEmpty(): node.detachNode() return Task.done def detachNodeLater(node = node): if node.isEmpty(): return center = node.node().getBounds().getCenter() node.node().setBounds(BoundingSphere(center, distance * 1.5)) node.node().setFinal(1) self.doMethodLater(0.005, detachNode, 'detach-%s-%s' % (gearRoot.getName(), node.getName()), extraArgs=[node]) gearTrack.append(Sequence(Wait(i * 0.15), Func(node.show), Parallel(node.posInterval(1, Point3(x, distance, z), fluid=1), node.hprInterval(1, VBase3(h, 0, 0), fluid=1)), Func(detachNodeLater))) if not self.raised: neutral1Anim = self.getAnim('down2Up') self.raised = 1 else: neutral1Anim = ActorInterval(self, neutral, startFrame=48) throwAnim = self.getAnim('throw') neutral2Anim = ActorInterval(self, neutral) extraAnim = Sequence() if attackCode == ToontownGlobals.BossCogSlowDirectedAttack: extraAnim = ActorInterval(self, neutral) def detachGearRoot(task, gearRoot = gearRoot): if not gearRoot.isEmpty(): gearRoot.detachNode() return task.done def detachGearRootLater(gearRoot = gearRoot): if gearRoot.isEmpty(): return self.doMethodLater(0.01, detachGearRoot, 'detach-%s' % gearRoot.getName()) seq = Sequence(ParallelEndTogether(self.pelvis.hprInterval(1, VBase3(toToonH, 0, 0)), neutral1Anim), extraAnim, Parallel(Sequence(Wait(0.19), gearTrack, Func(detachGearRootLater), self.pelvis.hprInterval(0.2, VBase3(0, 0, 0))), Sequence(throwAnim, neutral2Anim))) self.doAnimate(seq, now=1, raised=1) def setBattleDifficulty(self, diff): self.notify.debug('battleDifficulty = %d' % diff) self.battleDifficulty = diff def doMoveAttack(self, tableIndex): self.tableIndex = tableIndex table = self.tables[tableIndex] fromPos = self.getPos() fromHpr = self.getHpr() toPos = table.getPos() foo = render.attachNewNode('foo') foo.setPos(self.getPos()) foo.setHpr(self.getHpr()) foo.lookAt(table.getLocator()) toHpr = foo.getHpr() toHpr.setX(toHpr.getX() - 180) foo.removeNode() reverse = False moveTrack, hpr = self.moveBossToPoint(fromPos, fromHpr, toPos, toHpr, reverse) self.moveTrack = moveTrack self.moveTrack.start() self.storeInterval(self.moveTrack, 'moveTrack') def interruptMove(self): if self.moveTrack and self.moveTrack.isPlaying(): self.moveTrack.pause() self.stopMoveTask() def setAttackCode(self, attackCode, avId = 0): if self.state != 'BattleFour': return self.numAttacks += 1 self.notify.debug('numAttacks=%d' % self.numAttacks) self.attackCode = attackCode self.attackAvId = avId if attackCode == ToontownGlobals.BossCogMoveAttack: self.interruptMove() self.doMoveAttack(avId) elif attackCode == ToontownGlobals.BossCogGolfAttack: self.interruptMove() self.cleanupAttacks() self.doGolfAttack(avId, attackCode) elif attackCode == ToontownGlobals.BossCogDizzy: self.setDizzy(1) self.cleanupAttacks() self.doAnimate(None, raised=0, happy=1) elif attackCode == ToontownGlobals.BossCogDizzyNow: self.setDizzy(1) self.cleanupAttacks() self.doAnimate('hit', happy=1, now=1) elif attackCode == ToontownGlobals.BossCogSwatLeft: self.setDizzy(0) self.doAnimate('ltSwing', now=1) elif attackCode == ToontownGlobals.BossCogSwatRight: self.setDizzy(0) self.doAnimate('rtSwing', now=1) elif attackCode == ToontownGlobals.BossCogAreaAttack: self.setDizzy(0) self.doAnimate('areaAttack', now=1) elif attackCode == ToontownGlobals.BossCogFrontAttack: self.setDizzy(0) self.doAnimate('frontAttack', now=1) elif attackCode == ToontownGlobals.BossCogRecoverDizzyAttack: self.setDizzy(0) self.doAnimate('frontAttack', now=1) elif attackCode == ToontownGlobals.BossCogDirectedAttack or attackCode == ToontownGlobals.BossCogSlowDirectedAttack or attackCode == ToontownGlobals.BossCogGearDirectedAttack: self.interruptMove() self.setDizzy(0) self.doDirectedAttack(avId, attackCode) elif attackCode == ToontownGlobals.BossCogGolfAreaAttack: self.interruptMove() self.setDizzy(0) self.doGolfAreaAttack() elif attackCode == ToontownGlobals.BossCogNoAttack: self.setDizzy(0) self.doAnimate(None, raised=1) elif attackCode == ToontownGlobals.BossCogOvertimeAttack: self.interruptMove() self.setDizzy(0) self.cleanupAttacks() self.doOvertimeAttack(avId) return def signalAtTable(self): self.sendUpdate('reachedTable', [self.tableIndex]) def closeEnter(self, colEntry): tableStr = colEntry.getIntoNodePath().getNetTag('tableIndex') if tableStr: tableIndex = int(tableStr) self.sendUpdate('hitTable', [tableIndex]) def closeExit(self, colEntry): tableStr = colEntry.getIntoNodePath().getNetTag('tableIndex') if tableStr: tableIndex = int(tableStr) if self.tableIndex != tableIndex: self.sendUpdate('awayFromTable', [tableIndex]) def setSpeedDamage(self, speedDamage, recoverRate, timestamp): recoverStartTime = globalClockDelta.networkToLocalTime(timestamp) self.speedDamage = speedDamage self.speedRecoverRate = recoverRate self.speedRecoverStartTime = recoverStartTime speedFraction = max(1 - speedDamage / self.maxSpeedDamage, 0) self.treads.setColorScale(1, speedFraction, speedFraction, 1) taskName = 'RecoverSpeedDamage' taskMgr.remove(taskName) if self.speedRecoverRate: taskMgr.add(self.__recoverSpeedDamage, taskName) def getSpeedDamage(self): now = globalClock.getFrameTime() elapsed = now - self.speedRecoverStartTime return max(self.speedDamage - self.speedRecoverRate * elapsed / 60.0, 0) def getFractionalSpeedDamage(self): result = self.getSpeedDamage() / self.maxSpeedDamage return result def __recoverSpeedDamage(self, task): speedDamage = self.getSpeedDamage() speedFraction = max(1 - speedDamage / self.maxSpeedDamage, 0) self.treads.setColorScale(1, speedFraction, speedFraction, 1) return task.cont def moveBossToPoint(self, fromPos, fromHpr, toPos, toHpr, reverse): vector = Vec3(toPos - fromPos) distance = vector.length() self.distanceToTravel = distance self.notify.debug('self.distanceToTravel = %s' % self.distanceToTravel) if toHpr == None: mat = Mat3(0, 0, 0, 0, 0, 0, 0, 0, 0) headsUp(mat, vector, CSDefault) scale = VBase3(0, 0, 0) shear = VBase3(0, 0, 0) toHpr = VBase3(0, 0, 0) decomposeMatrix(mat, scale, shear, toHpr, CSDefault) if fromHpr: newH = PythonUtil.fitDestAngle2Src(fromHpr[0], toHpr[0]) toHpr = VBase3(newH, 0, 0) else: fromHpr = toHpr turnTime = abs(toHpr[0] - fromHpr[0]) / self.getCurTurnSpeed() if toHpr[0] < fromHpr[0]: leftRate = ToontownGlobals.BossCogTreadSpeed else: leftRate = -ToontownGlobals.BossCogTreadSpeed if reverse: rollTreadRate = -ToontownGlobals.BossCogTreadSpeed else: rollTreadRate = ToontownGlobals.BossCogTreadSpeed rollTime = distance / ToontownGlobals.BossCogRollSpeed deltaPos = toPos - fromPos self.toPos = toPos self.fromPos = fromPos self.dirVector = self.toPos - self.fromPos self.dirVector.normalize() track = Sequence(Func(self.setPos, fromPos), Func(self.headsUp, toPos), Parallel(self.hprInterval(turnTime, toHpr, fromHpr), self.rollLeftTreads(turnTime, leftRate), self.rollRightTreads(turnTime, -leftRate)), Func(self.startMoveTask)) return (track, toHpr) def getCurTurnSpeed(self): result = ToontownGlobals.BossbotTurnSpeedMax - (ToontownGlobals.BossbotTurnSpeedMax - ToontownGlobals.BossbotTurnSpeedMin) * self.getFractionalSpeedDamage() return result def getCurRollSpeed(self): result = ToontownGlobals.BossbotRollSpeedMax - (ToontownGlobals.BossbotRollSpeedMax - ToontownGlobals.BossbotRollSpeedMin) * self.getFractionalSpeedDamage() return result def getCurTreadSpeed(self): result = ToontownGlobals.BossbotTreadSpeedMax - (ToontownGlobals.BossbotTreadSpeedMax - ToontownGlobals.BossbotTreadSpeedMin) * self.getFractionalSpeedDamage() return result def startMoveTask(self): taskMgr.add(self.moveBossTask, self.moveBossTaskName) def stopMoveTask(self): taskMgr.remove(self.moveBossTaskName) def moveBossTask(self, task): dt = globalClock.getDt() distanceTravelledThisFrame = dt * self.getCurRollSpeed() diff = self.toPos - self.getPos() distanceLeft = diff.length() def rollTexMatrix(t, object = object): object.setTexOffset(TextureStage.getDefault(), t, 0) self.treadsLeftPos += dt * self.getCurTreadSpeed() self.treadsRightPos += dt * self.getCurTreadSpeed() rollTexMatrix(self.treadsLeftPos, self.treadsLeft) rollTexMatrix(self.treadsRightPos, self.treadsRight) if distanceTravelledThisFrame >= distanceLeft: self.setPos(self.toPos) self.signalAtTable() return Task.done else: newPos = self.getPos() + self.dirVector * dt * self.getCurRollSpeed() self.setPos(newPos) return Task.cont def doZapToon(self, toon, pos = None, hpr = None, ts = 0, fling = 1, shake = 1): zapName = toon.uniqueName('zap') self.clearInterval(zapName) zapTrack = Sequence(name=zapName) if toon == localAvatar: self.toOuchMode() messenger.send('interrupt-pie') self.enableLocalToonSimpleCollisions() else: zapTrack.append(Func(toon.stopSmooth)) def getSlideToPos(toon = toon): return render.getRelativePoint(toon, Point3(0, -5, 0)) if pos != None and hpr != None: (zapTrack.append(Func(toon.setPosHpr, pos, hpr)),) toonTrack = Parallel() if shake and toon == localAvatar: toonTrack.append(Sequence(Func(camera.setZ, camera, 1), Wait(0.15), Func(camera.setZ, camera, -2), Wait(0.15), Func(camera.setZ, camera, 1))) if fling: if self.isToonRoaming(toon.doId): toonTrack += [ActorInterval(toon, 'slip-backward')] toonTrack += [toon.posInterval(0.5, getSlideToPos, fluid=1)] else: toonTrack += [ActorInterval(toon, 'slip-forward')] zapTrack.append(toonTrack) if toon == localAvatar: zapTrack.append(Func(self.disableLocalToonSimpleCollisions)) currentState = self.state if currentState in ('BattleFour', 'BattleTwo'): zapTrack.append(Func(self.toFinalBattleMode)) else: self.notify.warning('doZapToon going to walkMode, how did this happen?') zapTrack.append(Func(self.toWalkMode)) else: zapTrack.append(Func(toon.startSmooth)) if ts > 0: startTime = ts else: zapTrack = Sequence(Wait(-ts), zapTrack) startTime = 0 zapTrack.append(Func(self.clearInterval, zapName)) zapTrack.delayDelete = DelayDelete.DelayDelete(toon, 'BossbotBoss.doZapToon') zapTrack.start(startTime) self.storeInterval(zapTrack, zapName) return def zapLocalToon(self, attackCode, origin = None): if self.localToonIsSafe or localAvatar.ghostMode or localAvatar.isStunned: return if globalClock.getFrameTime() < self.lastZapLocalTime + 1.0: return else: self.lastZapLocalTime = globalClock.getFrameTime() self.notify.debug('zapLocalToon frameTime=%s' % globalClock.getFrameTime()) messenger.send('interrupt-pie') place = self.cr.playGame.getPlace() currentState = None if place: currentState = place.fsm.getCurrentState().getName() if currentState != 'walk' and currentState != 'finalBattle' and currentState != 'crane': return self.notify.debug('continuing zap') toon = localAvatar fling = 1 shake = 0 if attackCode == ToontownGlobals.BossCogAreaAttack: fling = 0 shake = 1 if fling: if origin == None: origin = self if self.isToonRoaming(toon.doId): camera.wrtReparentTo(render) toon.headsUp(origin) camera.wrtReparentTo(toon) bossRelativePos = toon.getPos(self.getGeomNode()) bp2d = Vec2(bossRelativePos[0], bossRelativePos[1]) bp2d.normalize() pos = toon.getPos() hpr = toon.getHpr() timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate('zapToon', [pos[0], pos[1], pos[2], hpr[0], hpr[1], hpr[2], bp2d[0], bp2d[1], attackCode, timestamp]) self.doZapToon(toon, fling=fling, shake=shake) return def getToonTableIndex(self, toonId): tableIndex = -1 for table in list(self.tables.values()): if table.avId == toonId: tableIndex = table.index break return tableIndex def getToonGolfSpotIndex(self, toonId): golfSpotIndex = -1 for golfSpot in list(self.golfSpots.values()): if golfSpot.avId == toonId: golfSpotIndex = golfSpot.index break return golfSpotIndex def isToonOnTable(self, toonId): result = self.getToonTableIndex(toonId) != -1 return result def isToonOnGolfSpot(self, toonId): result = self.getToonGolfSpotIndex(toonId) != -1 return result def isToonRoaming(self, toonId): result = not self.isToonOnTable(toonId) and not self.isToonOnGolfSpot(toonId) return result def getGolfBall(self): golfRoot = NodePath('golfRoot') golfBall = loader.loadModel('phase_6/models/golf/golf_ball') golfBall.setColorScale(0.75, 0.75, 0.75, 0.5) golfBall.setTransparency(1) ballScale = 5 golfBall.setScale(ballScale) golfBall.reparentTo(golfRoot) cs = CollisionSphere(0, 0, 0, ballScale * 0.25) cs.setTangible(0) cn = CollisionNode('BossZap') cn.addSolid(cs) cn.setIntoCollideMask(ToontownGlobals.WallBitmask) cnp = golfRoot.attachNewNode(cn) return golfRoot def doGolfAttack(self, avId, attackCode): toon = base.cr.doId2do.get(avId) if toon: distance = toon.getDistance(self) self.notify.debug('distance = %s' % distance) gearRoot = self.rotateNode.attachNewNode('gearRoot-atk%d' % self.numAttacks) gearRoot.setZ(10) gearRoot.setTag('attackCode', str(attackCode)) gearModel = self.getGolfBall() self.ballLaunch = NodePath('') self.ballLaunch.reparentTo(gearRoot) self.ballLaunch.setPos(self.BallLaunchOffset) gearRoot.headsUp(toon) toToonH = PythonUtil.fitDestAngle2Src(0, gearRoot.getH() + 180) gearRoot.lookAt(toon) neutral = 'Fb_neutral' if not self.twoFaced: neutral = 'Ff_neutral' gearTrack = Parallel() for i in range(5): nodeName = '%s-%s' % (str(i), globalClock.getFrameTime()) node = gearRoot.attachNewNode(nodeName) node.hide() node.reparentTo(self.ballLaunch) node.wrtReparentTo(gearRoot) distance = toon.getDistance(node) gear = gearModel.instanceTo(node) x = random.uniform(-5, 5) z = random.uniform(-3, 3) p = random.uniform(-720, -90) y = distance + random.uniform(5, 15) if i == 2: x = 0 z = 0 y = distance + 10 def detachNode(node): if not node.isEmpty(): node.detachNode() return Task.done def detachNodeLater(node = node): if node.isEmpty(): return node.node().setBounds(BoundingSphere(Point3(0, 0, 0), distance * 1.5)) node.node().setFinal(1) self.doMethodLater(0.005, detachNode, 'detach-%s-%s' % (gearRoot.getName(), node.getName()), extraArgs=[node]) gearTrack.append(Sequence(Wait(26.0 / 24.0), Wait(i * 0.15), Func(node.show), Parallel(node.posInterval(1, Point3(x, y, z), fluid=1), node.hprInterval(1, VBase3(0, p, 0), fluid=1)), Func(detachNodeLater))) if not self.raised: neutral1Anim = self.getAnim('down2Up') self.raised = 1 else: neutral1Anim = ActorInterval(self, neutral, startFrame=48) throwAnim = self.getAnim('golf_swing') neutral2Anim = ActorInterval(self, neutral) extraAnim = Sequence() if attackCode == ToontownGlobals.BossCogSlowDirectedAttack: extraAnim = ActorInterval(self, neutral) def detachGearRoot(task, gearRoot = gearRoot): if not gearRoot.isEmpty(): gearRoot.detachNode() return task.done def detachGearRootLater(gearRoot = gearRoot): self.doMethodLater(0.01, detachGearRoot, 'detach-%s' % gearRoot.getName()) seq = Sequence(ParallelEndTogether(self.pelvis.hprInterval(1, VBase3(toToonH, 0, 0)), neutral1Anim), extraAnim, Parallel(Sequence(Wait(0.19), gearTrack, Func(detachGearRootLater), self.pelvis.hprInterval(0.2, VBase3(0, 0, 0))), Sequence(throwAnim, neutral2Anim), Sequence(Wait(0.85), SoundInterval(self.swingClubSfx, node=self, duration=0.45, cutOff=300, listenerNode=base.localAvatar)))) self.doAnimate(seq, now=1, raised=1) def doGolfAreaAttack(self): toons = [] for toonId in self.involvedToons: toon = base.cr.doId2do.get(toonId) if toon: toons.append(toon) if not toons: return neutral = 'Fb_neutral' if not self.twoFaced: neutral = 'Ff_neutral' if not self.raised: neutral1Anim = self.getAnim('down2Up') self.raised = 1 else: neutral1Anim = ActorInterval(self, neutral, startFrame=48) throwAnim = self.getAnim('golf_swing') neutral2Anim = ActorInterval(self, neutral) extraAnim = Sequence() if False: extraAnim = ActorInterval(self, neutral) gearModel = self.getGolfBall() toToonH = self.rotateNode.getH() + 360 self.notify.debug('toToonH = %s' % toToonH) gearRoots = [] allGearTracks = Parallel() for toon in toons: gearRoot = self.rotateNode.attachNewNode('gearRoot-atk%d-%d' % (self.numAttacks, toons.index(toon))) gearRoot.setZ(10) gearRoot.setTag('attackCode', str(ToontownGlobals.BossCogGolfAreaAttack)) gearRoot.lookAt(toon) ballLaunch = NodePath('') ballLaunch.reparentTo(gearRoot) ballLaunch.setPos(self.BallLaunchOffset) gearTrack = Parallel() for i in range(5): nodeName = '%s-%s' % (str(i), globalClock.getFrameTime()) node = gearRoot.attachNewNode(nodeName) node.hide() node.reparentTo(ballLaunch) node.wrtReparentTo(gearRoot) distance = toon.getDistance(node) toonPos = toon.getPos(render) nodePos = node.getPos(render) vector = toonPos - nodePos gear = gearModel.instanceTo(node) x = random.uniform(-5, 5) z = random.uniform(-3, 3) p = random.uniform(-720, -90) y = distance + random.uniform(5, 15) if i == 2: x = 0 z = 0 y = distance + 10 def detachNode(node): if not node.isEmpty(): node.detachNode() return Task.done def detachNodeLater(node = node): if node.isEmpty(): return node.node().setBounds(BoundingSphere(Point3(0, 0, 0), distance * 1.5)) node.node().setFinal(1) self.doMethodLater(0.005, detachNode, 'detach-%s-%s' % (gearRoot.getName(), node.getName()), extraArgs=[node]) gearTrack.append(Sequence(Wait(26.0 / 24.0), Wait(i * 0.15), Func(node.show), Parallel(node.posInterval(1, Point3(x, y, z), fluid=1), node.hprInterval(1, VBase3(0, p, 0), fluid=1)), Func(detachNodeLater))) allGearTracks.append(gearTrack) def detachGearRoots(gearRoots = gearRoots): for gearRoot in gearRoots: def detachGearRoot(task, gearRoot = gearRoot): if not gearRoot.isEmpty(): gearRoot.detachNode() return task.done if gearRoot.isEmpty(): continue self.doMethodLater(0.01, detachGearRoot, 'detach-%s' % gearRoot.getName()) gearRoots = [] rotateFire = Parallel(self.pelvis.hprInterval(2, VBase3(toToonH + 1440, 0, 0)), allGearTracks) seq = Sequence(Func(base.playSfx, self.warningSfx), Func(self.saySomething, TTLocalizer.GolfAreaAttackTaunt), ParallelEndTogether(self.pelvis.hprInterval(2, VBase3(toToonH, 0, 0)), neutral1Anim), extraAnim, Parallel(Sequence(rotateFire, Func(detachGearRoots), Func(self.pelvis.setHpr, VBase3(0, 0, 0))), Sequence(throwAnim, neutral2Anim), Sequence(Wait(0.85), SoundInterval(self.swingClubSfx, node=self, duration=0.45, cutOff=300, listenerNode=base.localAvatar)))) self.doAnimate(seq, now=1, raised=1) def saySomething(self, chatString): intervalName = 'CEOTaunt' seq = Sequence(name=intervalName) seq.append(Func(self.setChatAbsolute, chatString, CFSpeech)) seq.append(Wait(4.0)) seq.append(Func(self.clearChat)) oldSeq = self.activeIntervals.get(intervalName) if oldSeq: oldSeq.finish() seq.start() self.activeIntervals[intervalName] = seq def d_hitToon(self, toonId): self.notify.debug('----- d_hitToon') self.sendUpdate('hitToon', [toonId]) def toonGotHealed(self, toonId): toon = base.cr.doId2do.get(toonId) if toon: base.playSfx(self.toonUpSfx, node=toon) def localToonTouchedBeltToonup(self, beltIndex, toonupIndex, toonupNum): avId = base.localAvatar.doId doRequest = True if doRequest: self.sendUpdate('requestGetToonup', [beltIndex, toonupIndex, toonupNum]) def toonGotToonup(self, avId, beltIndex, toonupIndex, toonupNum): if self.belts[beltIndex]: self.belts[beltIndex].removeToonup(toonupIndex) toon = base.cr.doId2do.get(avId) if toon: base.playSfx(self.toonUpSfx, node=toon) def doOvertimeAttack(self, index): attackCode = ToontownGlobals.BossCogOvertimeAttack attackBelts = Sequence() if index < len(self.belts): belt = self.belts[index] self.saySomething(TTLocalizer.OvertimeAttackTaunts[index]) if index: self.bossClubIntervals[0].finish() self.bossClubIntervals[1].loop() else: self.bossClubIntervals[1].finish() self.bossClubIntervals[0].loop() distance = belt.beltModel.getDistance(self) gearRoot = self.rotateNode.attachNewNode('gearRoot') gearRoot.setZ(10) gearRoot.setTag('attackCode', str(attackCode)) gearModel = self.getGearFrisbee() gearModel.setScale(0.2) gearRoot.headsUp(belt.beltModel) toToonH = PythonUtil.fitDestAngle2Src(0, gearRoot.getH() + 180) gearRoot.lookAt(belt.beltModel) neutral = 'Fb_neutral' if not self.twoFaced: neutral = 'Ff_neutral' gearTrack = Parallel() for i in range(4): node = gearRoot.attachNewNode(str(i)) node.hide() node.setPos(0, 5.85, 4.0) gear = gearModel.instanceTo(node) x = random.uniform(-5, 5) z = random.uniform(-3, 3) h = random.uniform(-720, 720) gearTrack.append(Sequence(Wait(i * 0.15), Func(node.show), Parallel(node.posInterval(1, Point3(x, distance, z), fluid=1), node.hprInterval(1, VBase3(h, 0, 0), fluid=1)), Func(node.detachNode))) if not self.raised: neutral1Anim = self.getAnim('down2Up') self.raised = 1 else: neutral1Anim = ActorInterval(self, neutral, startFrame=48) throwAnim = self.getAnim('throw') neutral2Anim = ActorInterval(self, neutral) extraAnim = Sequence() if attackCode == ToontownGlobals.BossCogSlowDirectedAttack: extraAnim = ActorInterval(self, neutral) seq = Sequence(ParallelEndTogether(self.pelvis.hprInterval(1, VBase3(toToonH, 0, 0)), neutral1Anim), extraAnim, Parallel(Sequence(Wait(0.19), gearTrack, Func(gearRoot.detachNode), Func(self.explodeSfx.play), self.pelvis.hprInterval(0.2, VBase3(0, 0, 0))), Sequence(throwAnim, neutral2Anim)), Func(belt.request, 'Inactive')) attackBelts.append(seq) self.notify.debug('attackBelts duration= %.2f' % attackBelts.getDuration()) self.doAnimate(attackBelts, now=1, raised=1)