from panda3d.core import * from panda3d.otp import * from direct.interval.IntervalGlobal import * from toontown.battle.BattleProps import * from direct.distributed.ClockDelta import * from direct.showbase.PythonUtil import Functor from direct.gui.DirectGui import * from panda3d.core import * from direct.fsm import FSM from direct.fsm import ClassicFSM, State from direct.fsm import State from direct.directnotify import DirectNotifyGlobal from toontown.toonbase import ToontownGlobals from toontown.toonbase import ToontownBattleGlobals from . import DistributedBossCog from toontown.toonbase import TTLocalizer from . import SuitDNA from toontown.toon import Toon from toontown.battle import BattleBase from direct.directutil import Mopath from direct.showutil import Rope from toontown.distributed import DelayDelete from toontown.battle import MovieToonVictory from toontown.building import ElevatorUtils from toontown.battle import RewardPanel from toontown.toon import NPCToons from direct.task import Task import random import math from toontown.coghq import CogDisguiseGlobals from toontown.suit import SellbotBossGlobals OneBossCog = None class DistributedSellbotBoss(DistributedBossCog.DistributedBossCog, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedSellbotBoss') cageHeights = [100, 81, 63, 44, 25, 18] def __init__(self, cr): DistributedBossCog.DistributedBossCog.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedSellbotBoss') self.cagedToonNpcId = None self.doobers = [] self.dooberRequest = None self.bossDamage = 0 self.attackCode = None self.attackAvId = 0 self.recoverRate = 0 self.recoverStartTime = 0 self.bossDamageMovie = None self.cagedToon = None self.cageShadow = None self.cageIndex = 0 self.everThrownPie = 0 self.battleThreeMusicTime = 0 self.insidesANodePath = None self.insidesBNodePath = None self.rampA = None self.rampB = None self.rampC = None self.strafeInterval = None self.onscreenMessage = None self.toonMopathInterval = [] self.nerfed = ToontownGlobals.SELLBOT_NERF_HOLIDAY in base.cr.newsManager.getHolidayIdList() self.localToonPromoted = True self.resetMaxDamage() return def announceGenerate(self): global OneBossCog DistributedBossCog.DistributedBossCog.announceGenerate(self) self.setName(TTLocalizer.SellbotBossName) nameInfo = TTLocalizer.BossCogNameWithDept % {'name': self._name, 'dept': SuitDNA.getDeptFullname(self.style.dept)} self.setDisplayName(nameInfo) self.cageDoorSfx = loader.loadSfx('phase_5/audio/sfx/CHQ_SOS_cage_door.ogg') self.cageLandSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_SOS_cage_land.ogg') self.cageLowerSfx = loader.loadSfx('phase_5/audio/sfx/CHQ_SOS_cage_lower.ogg') self.piesRestockSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_SOS_pies_restock.ogg') self.rampSlideSfx = loader.loadSfx('phase_9/audio/sfx/CHQ_VP_ramp_slide.ogg') self.strafeSfx = [] for i in range(10): self.strafeSfx.append(loader.loadSfx('phase_3.5/audio/sfx/SA_shred.ogg')) render.setTag('pieCode', str(ToontownGlobals.PieCodeNotBossCog)) insidesA = CollisionPolygon(Point3(4.0, -2.0, 5.0), Point3(-4.0, -2.0, 5.0), Point3(-4.0, -2.0, 0.5), Point3(4.0, -2.0, 0.5)) insidesANode = CollisionNode('BossZap') insidesANode.addSolid(insidesA) insidesANode.setCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.WallBitmask) self.insidesANodePath = self.axle.attachNewNode(insidesANode) self.insidesANodePath.setTag('pieCode', str(ToontownGlobals.PieCodeBossInsides)) self.insidesANodePath.stash() insidesB = CollisionPolygon(Point3(-4.0, 2.0, 5.0), Point3(4.0, 2.0, 5.0), Point3(4.0, 2.0, 0.5), Point3(-4.0, 2.0, 0.5)) insidesBNode = CollisionNode('BossZap') insidesBNode.addSolid(insidesB) insidesBNode.setCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.WallBitmask) self.insidesBNodePath = self.axle.attachNewNode(insidesBNode) self.insidesBNodePath.setTag('pieCode', str(ToontownGlobals.PieCodeBossInsides)) self.insidesBNodePath.stash() target = CollisionTube(0, -1, 4, 0, -1, 9, 3.5) targetNode = CollisionNode('BossZap') targetNode.addSolid(target) targetNode.setCollideMask(ToontownGlobals.PieBitmask) self.targetNodePath = self.pelvis.attachNewNode(targetNode) self.targetNodePath.setTag('pieCode', str(ToontownGlobals.PieCodeBossCog)) shield = CollisionTube(0, 1, 4, 0, 1, 7, 3.5) shieldNode = CollisionNode('BossZap') shieldNode.addSolid(shield) shieldNode.setCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask) shieldNodePath = self.pelvis.attachNewNode(shieldNode) disk = loader.loadModel('phase_9/models/char/bossCog-gearCollide') disk.find('**/+CollisionNode').setName('BossZap') disk.reparentTo(self.pelvis) disk.setZ(0.8) self.loadEnvironment() self.__makeCagedToon() self.__loadMopaths() if OneBossCog != None: self.notify.warning('Multiple BossCogs visible.') OneBossCog = self return def disable(self): global OneBossCog DistributedBossCog.DistributedBossCog.disable(self) self.request('Off') self.unloadEnvironment() self.__unloadMopaths() self.__cleanupCagedToon() self.__clearOnscreenMessage() taskMgr.remove(self.uniqueName('PieAdvice')) self.__cleanupStrafe() render.clearTag('pieCode') self.targetNodePath.detachNode() self.cr.relatedObjectMgr.abortRequest(self.dooberRequest) self.dooberRequest = None self.betweenBattleMusic.stop() self.promotionMusic.stop() self.stingMusic.stop() self.battleTwoMusic.stop() self.battleThreeMusic.stop() self.epilogueMusic.stop() while len(self.toonMopathInterval): toonMopath = self.toonMopathInterval[0] toonMopath.finish() toonMopath.destroy() self.toonMopathInterval.remove(toonMopath) if OneBossCog == self: OneBossCog = None return def resetMaxDamage(self): if self.nerfed: self.bossMaxDamage = ToontownGlobals.SellbotBossMaxDamageNerfed else: self.bossMaxDamage = ToontownGlobals.SellbotBossMaxDamage def d_hitBoss(self, bossDamage): self.sendUpdate('hitBoss', [bossDamage]) def d_hitBossInsides(self): self.sendUpdate('hitBossInsides', []) def d_hitToon(self, toonId): self.sendUpdate('hitToon', [toonId]) def setCagedToonNpcId(self, npcId): self.cagedToonNpcId = npcId def gotToon(self, toon): stateName = self.state if stateName == 'Elevator': self.placeToonInElevator(toon) def setDooberIds(self, dooberIds): self.doobers = [] self.cr.relatedObjectMgr.abortRequest(self.dooberRequest) self.dooberRequest = self.cr.relatedObjectMgr.requestObjects(dooberIds, allCallback=self.__gotDoobers) def __gotDoobers(self, doobers): self.dooberRequest = None self.doobers = doobers return def setBossDamage(self, bossDamage, recoverRate, timestamp): recoverStartTime = globalClockDelta.networkToLocalTime(timestamp) self.bossDamage = bossDamage self.recoverRate = recoverRate self.recoverStartTime = recoverStartTime taskName = 'RecoverBossDamage' taskMgr.remove(taskName) if self.bossDamageMovie: if self.bossDamage >= self.bossMaxDamage: self.bossDamageMovie.resumeUntil(self.bossDamageMovie.getDuration()) else: self.bossDamageMovie.resumeUntil(self.bossDamage * self.bossDamageToMovie) if self.recoverRate: taskMgr.add(self.__recoverBossDamage, taskName) def getBossDamage(self): now = globalClock.getFrameTime() elapsed = now - self.recoverStartTime return max(self.bossDamage - self.recoverRate * elapsed / 60.0, 0) def __recoverBossDamage(self, task): self.bossDamageMovie.setT(self.getBossDamage() * self.bossDamageToMovie) return Task.cont def __makeCagedToon(self): if self.cagedToon: return self.cagedToon = NPCToons.createLocalNPC(self.cagedToonNpcId) self.cagedToon.addActive() self.cagedToon.reparentTo(self.cage) self.cagedToon.setPosHpr(0, -2, 0, 180, 0, 0) self.cagedToon.loop('neutral') touch = CollisionPolygon(Point3(-3.0382, 3.0382, -1), Point3(3.0382, 3.0382, -1), Point3(3.0382, -3.0382, -1), Point3(-3.0382, -3.0382, -1)) touch.setTangible(0) touchNode = CollisionNode('Cage') touchNode.setCollideMask(ToontownGlobals.WallBitmask) touchNode.addSolid(touch) self.cage.attachNewNode(touchNode) def __cleanupCagedToon(self): if self.cagedToon: self.cagedToon.removeActive() self.cagedToon.delete() self.cagedToon = None return def __walkToonToPromotion(self, toonId, delay, mopath, track, delayDeletes): toon = base.cr.doId2do.get(toonId) if toon: destPos = toon.getPos() self.placeToonInElevator(toon) toon.wrtReparentTo(render) walkMopath = MopathInterval(mopath, toon) ival = Sequence(Wait(delay), Func(toon.suit.setPlayRate, 1, 'walk'), Func(toon.suit.loop, 'walk'), toon.posInterval(1, Point3(0, 90, 20)), ParallelEndTogether(walkMopath, toon.posInterval(2, destPos, blendType='noBlend')), Func(toon.suit.loop, 'neutral')) self.toonMopathInterval.append(walkMopath) track.append(ival) delayDeletes.append(DelayDelete.DelayDelete(toon, 'SellbotBoss.__walkToonToPromotion')) def __walkDoober(self, suit, delay, turnPos, track, delayDeletes): turnPos = Point3(*turnPos) turnPosDown = Point3(*ToontownGlobals.SellbotBossDooberTurnPosDown) flyPos = Point3(*ToontownGlobals.SellbotBossDooberFlyPos) seq = Sequence(Func(suit.headsUp, turnPos), Wait(delay), Func(suit.loop, 'walk', 0), self.__walkSuitToPoint(suit, suit.getPos(), turnPos), self.__walkSuitToPoint(suit, turnPos, turnPosDown), self.__walkSuitToPoint(suit, turnPosDown, flyPos), suit.beginSupaFlyMove(flyPos, 0, 'flyAway'), Func(suit.fsm.request, 'Off')) track.append(seq) delayDeletes.append(DelayDelete.DelayDelete(suit, 'SellbotBoss.__walkDoober')) def __walkSuitToPoint(self, node, fromPos, toPos): vector = Vec3(toPos - fromPos) distance = vector.length() time = distance / (ToontownGlobals.SuitWalkSpeed * 1.8) return Sequence(Func(node.setPos, fromPos), Func(node.headsUp, toPos), node.posInterval(time, toPos)) def makeIntroductionMovie(self, delayDeletes): track = Parallel() camera.reparentTo(render) camera.setPosHpr(0, 25, 30, 0, 0, 0) localAvatar.setCameraFov(ToontownGlobals.CogHQCameraFov) dooberTrack = Parallel() if self.doobers: self.__doobersToPromotionPosition(self.doobers[:4], self.battleANode) self.__doobersToPromotionPosition(self.doobers[4:], self.battleBNode) turnPosA = ToontownGlobals.SellbotBossDooberTurnPosA turnPosB = ToontownGlobals.SellbotBossDooberTurnPosB self.__walkDoober(self.doobers[0], 0, turnPosA, dooberTrack, delayDeletes) self.__walkDoober(self.doobers[1], 4, turnPosA, dooberTrack, delayDeletes) self.__walkDoober(self.doobers[2], 8, turnPosA, dooberTrack, delayDeletes) self.__walkDoober(self.doobers[3], 12, turnPosA, dooberTrack, delayDeletes) self.__walkDoober(self.doobers[7], 2, turnPosB, dooberTrack, delayDeletes) self.__walkDoober(self.doobers[6], 6, turnPosB, dooberTrack, delayDeletes) self.__walkDoober(self.doobers[5], 10, turnPosB, dooberTrack, delayDeletes) self.__walkDoober(self.doobers[4], 14, turnPosB, dooberTrack, delayDeletes) toonTrack = Parallel() self.__toonsToPromotionPosition(self.toonsA, self.battleANode) self.__toonsToPromotionPosition(self.toonsB, self.battleBNode) delay = 0 for toonId in self.toonsA: self.__walkToonToPromotion(toonId, delay, self.toonsEnterA, toonTrack, delayDeletes) delay += 1 for toonId in self.toonsB: self.__walkToonToPromotion(toonId, delay, self.toonsEnterB, toonTrack, delayDeletes) delay += 1 toonTrack.append(Sequence(Wait(delay), self.closeDoors)) self.rampA.request('extended') self.rampB.request('extended') self.rampC.request('retracted') self.clearChat() self.cagedToon.clearChat() promoteDoobers = TTLocalizer.BossCogPromoteDoobers % SuitDNA.getDeptFullnameP(self.style.dept) doobersAway = TTLocalizer.BossCogDoobersAway[self.style.dept] welcomeToons = TTLocalizer.BossCogWelcomeToons promoteToons = TTLocalizer.BossCogPromoteToons % SuitDNA.getDeptFullnameP(self.style.dept) discoverToons = TTLocalizer.BossCogDiscoverToons attackToons = TTLocalizer.BossCogAttackToons interruptBoss = TTLocalizer.CagedToonInterruptBoss rescueQuery = TTLocalizer.CagedToonRescueQuery bossAnimTrack = Sequence( ActorInterval(self, 'Ff_speech', startTime=2, duration=10, loop=1), ActorInterval(self, 'ltTurn2Wave', duration=2), ActorInterval(self, 'wave', duration=4, loop=1), ActorInterval(self, 'ltTurn2Wave', startTime=2, endTime=0), ActorInterval(self, 'Ff_speech', duration=7, loop=1)) track.append(bossAnimTrack) dialogTrack = Track( (0, Parallel( camera.posHprInterval(8, Point3(-22, -100, 35), Point3(-10, -13, 0), blendType='easeInOut'), IndirectInterval(toonTrack, 0, 18))), (5.6, Func(self.setChatAbsolute, promoteDoobers, CFSpeech)), (9, IndirectInterval(dooberTrack, 0, 9)), (10, Sequence( Func(self.clearChat), Func(camera.setPosHpr, -23.1, 15.7, 17.2, -160, -2.4, 0))), (12, Func(self.setChatAbsolute, doobersAway, CFSpeech)), (16, Parallel( Func(self.clearChat), Func(camera.setPosHpr, -25, -99, 10, -14, 10, 0), IndirectInterval(dooberTrack, 14), IndirectInterval(toonTrack, 30))), (18, Func(self.setChatAbsolute, welcomeToons, CFSpeech)), (22, Func(self.setChatAbsolute, promoteToons, CFSpeech)), (22.2, Sequence( Func(self.cagedToon.nametag3d.setScale, 2), Func(self.cagedToon.setChatAbsolute, interruptBoss, CFSpeech), ActorInterval(self.cagedToon, 'wave'), Func(self.cagedToon.loop, 'neutral'))), (25, Sequence( Func(self.clearChat), Func(self.cagedToon.clearChat), Func(camera.setPosHpr, -12, -15, 27, -151, -15, 0), ActorInterval(self, 'Ff_lookRt'))), (27, Sequence( Func(self.cagedToon.setChatAbsolute, rescueQuery, CFSpeech), Func(camera.setPosHpr, -12, 48, 94, -26, 20, 0), ActorInterval(self.cagedToon, 'wave'), Func(self.cagedToon.loop, 'neutral'))), (31, Sequence( Func(camera.setPosHpr, -20, -35, 10, -88, 25, 0), Func(self.setChatAbsolute, discoverToons, CFSpeech), Func(self.cagedToon.nametag3d.setScale, 1), Func(self.cagedToon.clearChat), ActorInterval(self, 'turn2Fb'))), (34, Sequence( Func(self.clearChat), self.loseCogSuits(self.toonsA, self.battleANode, (0, 18, 5, -180, 0, 0)), self.loseCogSuits(self.toonsB, self.battleBNode, (0, 18, 5, -180, 0, 0)))), (37, Sequence( self.toonNormalEyes(self.involvedToons), Func(camera.setPosHpr, -23.4, -145.6, 44.0, -10.0, -12.5, 0), Func(self.loop, 'Fb_neutral'), Func(self.rampA.request, 'retract'), Func(self.rampB.request, 'retract'), Parallel(self.backupToonsToBattlePosition(self.toonsA, self.battleANode), self.backupToonsToBattlePosition(self.toonsB, self.battleBNode), Sequence( Wait(2), Func(self.setChatAbsolute, attackToons, CFSpeech)))))) track.append(dialogTrack) return Sequence(Func(self.stickToonsToFloor), track, Func(self.unstickToons), name=self.uniqueName('Introduction')) def __makeRollToBattleTwoMovie(self): startPos = Point3(ToontownGlobals.SellbotBossBattleOnePosHpr[0], ToontownGlobals.SellbotBossBattleOnePosHpr[1], ToontownGlobals.SellbotBossBattleOnePosHpr[2]) if self.arenaSide: topRampPos = Point3(*ToontownGlobals.SellbotBossTopRampPosB) topRampTurnPos = Point3(*ToontownGlobals.SellbotBossTopRampTurnPosB) p3Pos = Point3(*ToontownGlobals.SellbotBossP3PosB) else: topRampPos = Point3(*ToontownGlobals.SellbotBossTopRampPosA) topRampTurnPos = Point3(*ToontownGlobals.SellbotBossTopRampTurnPosA) p3Pos = Point3(*ToontownGlobals.SellbotBossP3PosA) battlePos = Point3(ToontownGlobals.SellbotBossBattleTwoPosHpr[0], ToontownGlobals.SellbotBossBattleTwoPosHpr[1], ToontownGlobals.SellbotBossBattleTwoPosHpr[2]) battleHpr = VBase3(ToontownGlobals.SellbotBossBattleTwoPosHpr[3], ToontownGlobals.SellbotBossBattleTwoPosHpr[4], ToontownGlobals.SellbotBossBattleTwoPosHpr[5]) bossTrack = Sequence() bossTrack.append(Func(self.getGeomNode().setH, 180)) bossTrack.append(Func(self.loop, 'Fb_neutral')) track, hpr = self.rollBossToPoint(startPos, None, topRampPos, None, 0) bossTrack.append(track) track, hpr = self.rollBossToPoint(topRampPos, hpr, topRampTurnPos, None, 0) bossTrack.append(track) track, hpr = self.rollBossToPoint(topRampTurnPos, hpr, p3Pos, None, 0) bossTrack.append(track) track, hpr = self.rollBossToPoint(p3Pos, hpr, battlePos, None, 0) bossTrack.append(track) return Sequence(bossTrack, Func(self.getGeomNode().setH, 0), name=self.uniqueName('BattleTwo')) def cagedToonMovieFunction(self, instruct, cageIndex): self.notify.debug('cagedToonMovieFunction()') if not (hasattr(self, 'cagedToon') and hasattr(self.cagedToon, 'nametag') and hasattr(self.cagedToon, 'nametag3d')): return if instruct == 1: self.cagedToon.nametag3d.setScale(2) elif instruct == 2: self.cagedToon.setChatAbsolute(TTLocalizer.CagedToonDrop[cageIndex], CFSpeech) elif instruct == 3: self.cagedToon.nametag3d.setScale(1) elif instruct == 4: self.cagedToon.clearChat() def makeEndOfBattleMovie(self, hasLocalToon): name = self.uniqueName('CageDrop') seq = Sequence(name=name) seq.append(Func(self.cage.setPos, self.cagePos[self.cageIndex])) if hasLocalToon: seq += [Func(camera.reparentTo, render), Func(camera.setPosHpr, self.cage, 0, -50, 0, 0, 0, 0), Func(localAvatar.setCameraFov, ToontownGlobals.CogHQCameraFov), Func(self.hide)] seq += [Wait(0.5), Parallel(self.cage.posInterval(1, self.cagePos[self.cageIndex + 1], blendType='easeInOut'), SoundInterval(self.cageLowerSfx, duration=1)), Func(self.cagedToonMovieFunction, 1, self.cageIndex), Func(self.cagedToonMovieFunction, 2, self.cageIndex), Wait(3), Func(self.cagedToonMovieFunction, 3, self.cageIndex), Func(self.cagedToonMovieFunction, 4, self.cageIndex)] if hasLocalToon: seq += [Func(self.show), Func(camera.reparentTo, localAvatar), Func(camera.setPos, localAvatar.cameraPositions[0][0]), Func(camera.setHpr, 0, 0, 0)] self.cageIndex += 1 return seq def __makeBossDamageMovie(self): startPos = Point3(ToontownGlobals.SellbotBossBattleTwoPosHpr[0], ToontownGlobals.SellbotBossBattleTwoPosHpr[1], ToontownGlobals.SellbotBossBattleTwoPosHpr[2]) startHpr = Point3(*ToontownGlobals.SellbotBossBattleThreeHpr) bottomPos = Point3(*ToontownGlobals.SellbotBossBottomPos) deathPos = Point3(*ToontownGlobals.SellbotBossDeathPos) self.setPosHpr(startPos, startHpr) bossTrack = Sequence() bossTrack.append(Func(self.loop, 'Fb_neutral')) track, hpr = self.rollBossToPoint(startPos, startHpr, bottomPos, None, 1) bossTrack.append(track) track, hpr = self.rollBossToPoint(bottomPos, startHpr, deathPos, None, 1) bossTrack.append(track) duration = bossTrack.getDuration() return bossTrack def __talkAboutPromotion(self, speech): if not self.localToonPromoted: pass elif self.prevCogSuitLevel < ToontownGlobals.MaxCogSuitLevel: speech += TTLocalizer.CagedToonPromotion newCogSuitLevel = localAvatar.getCogLevels()[CogDisguiseGlobals.dept2deptIndex(self.style.dept)] if newCogSuitLevel == ToontownGlobals.MaxCogSuitLevel: speech += TTLocalizer.CagedToonLastPromotion % (ToontownGlobals.MaxCogSuitLevel + 1) if newCogSuitLevel in ToontownGlobals.CogSuitHPLevels: speech += TTLocalizer.CagedToonHPBoost else: speech += TTLocalizer.CagedToonMaxed % (ToontownGlobals.MaxCogSuitLevel + 1) return speech def __makeCageOpenMovie(self): speech = TTLocalizer.CagedToonThankYou speech = self.__talkAboutPromotion(speech) name = self.uniqueName('CageOpen') seq = Sequence( Func(self.cage.setPos, self.cagePos[4]), Func(self.cageDoor.setHpr, VBase3(0, 0, 0)), Func(self.cagedToon.setPos, Point3(0, -2, 0)), Parallel( self.cage.posInterval(0.5, self.cagePos[5], blendType='easeOut'), SoundInterval(self.cageLowerSfx, duration=0.5)), Parallel( self.cageDoor.hprInterval(0.5, VBase3(0, 90, 0), blendType='easeOut'), Sequence(SoundInterval(self.cageDoorSfx), duration=0)), Wait(0.2), Func(self.cagedToon.loop, 'walk'), self.cagedToon.posInterval(0.8, Point3(0, -6, 0)), Func(self.cagedToon.setChatAbsolute, TTLocalizer.CagedToonYippee, CFSpeech), ActorInterval(self.cagedToon, 'jump'), Func(self.cagedToon.loop, 'neutral'), Func(self.cagedToon.headsUp, localAvatar), Func(self.cagedToon.setLocalPageChat, speech, 0), Func(camera.reparentTo, localAvatar), Func(camera.setPos, 0, -9, 9), Func(camera.lookAt, self.cagedToon, Point3(0, 0, 2)), name=name) return seq def __showOnscreenMessage(self, text): if self.onscreenMessage: self.onscreenMessage.destroy() self.onscreenMessage = None self.onscreenMessage = DirectLabel(text=text, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.35), scale=0.1) return def __clearOnscreenMessage(self): if self.onscreenMessage: self.onscreenMessage.destroy() self.onscreenMessage = None return def __showWaitingMessage(self, task): self.__showOnscreenMessage(TTLocalizer.BuildingWaitingForVictors) def __placeCageShadow(self): if self.cageShadow == None: self.cageShadow = loader.loadModel('phase_3/models/props/drop_shadow') self.cageShadow.setPos(0, 77.9, 18) self.cageShadow.setColorScale(1, 1, 1, 0.6) self.cageShadow.reparentTo(render) return def __removeCageShadow(self): if self.cageShadow != None: self.cageShadow.detachNode() return def setCageIndex(self, cageIndex): self.cageIndex = cageIndex self.cage.setPos(self.cagePos[self.cageIndex]) if self.cageIndex >= 4: self.__placeCageShadow() else: self.__removeCageShadow() def loadEnvironment(self): DistributedBossCog.DistributedBossCog.loadEnvironment(self) self.geom = loader.loadModel('phase_9/models/cogHQ/BossRoomHQ') self.rampA = self.__findRamp('rampA', '**/west_ramp2') self.rampB = self.__findRamp('rampB', '**/west_ramp') self.rampC = self.__findRamp('rampC', '**/west_ramp1') self.cage = self.geom.find('**/cage') elevatorEntrance = self.geom.find('**/elevatorEntrance') elevatorEntrance.getChildren().detach() elevatorEntrance.setScale(1) elevatorModel = loader.loadModel('phase_9/models/cogHQ/cogHQ_elevator') elevatorModel.reparentTo(elevatorEntrance) self.setupElevator(elevatorModel) pos = self.cage.getPos() self.cagePos = [] for height in self.cageHeights: self.cagePos.append(Point3(pos[0], pos[1], height)) self.cageDoor = self.geom.find('**/cage_door') self.cage.setScale(1) self.rope = Rope.Rope(name='supportChain') self.rope.reparentTo(self.cage) self.rope.setup(2, ((self.cage, (0.15, 0.13, 16)), (self.geom, (0.23, 78, 120)))) self.rope.ropeNode.setRenderMode(RopeNode.RMBillboard) self.rope.ropeNode.setUvMode(RopeNode.UVDistance) self.rope.ropeNode.setUvDirection(0) self.rope.ropeNode.setUvScale(0.8) self.rope.setTexture(self.cage.findTexture('hq_chain')) self.rope.setTransparency(1) self.promotionMusic = base.loader.loadMusic('phase_7/audio/bgm/encntr_suit_winning_indoor.ogg') self.betweenBattleMusic = base.loader.loadMusic('phase_9/audio/bgm/encntr_toon_winning.ogg') self.battleTwoMusic = base.loader.loadMusic('phase_7/audio/bgm/encntr_suit_winning_indoor.ogg') self.geom.reparentTo(render) def unloadEnvironment(self): DistributedBossCog.DistributedBossCog.unloadEnvironment(self) self.geom.removeNode() del self.geom del self.cage self.rampA.requestFinalState() self.rampB.requestFinalState() self.rampC.requestFinalState() del self.rampA del self.rampB del self.rampC def __loadMopaths(self): self.toonsEnterA = Mopath.Mopath() self.toonsEnterA.loadFile('phase_9/paths/bossBattle-toonsEnterA') self.toonsEnterA.fFaceForward = 1 self.toonsEnterA.timeScale = 35 self.toonsEnterB = Mopath.Mopath() self.toonsEnterB.loadFile('phase_9/paths/bossBattle-toonsEnterB') self.toonsEnterB.fFaceForward = 1 self.toonsEnterB.timeScale = 35 def __unloadMopaths(self): self.toonsEnterA.reset() self.toonsEnterB.reset() def __findRamp(self, name, path): ramp = self.geom.find(path) children = ramp.getChildren() animate = ramp.attachNewNode(name) children.reparentTo(animate) fsm = ClassicFSM.ClassicFSM(name, [ State.State('extend', Functor(self.enterRampExtend, animate), Functor(self.exitRampExtend, animate), [ 'extended', 'retract', 'retracted']), State.State('extended', Functor(self.enterRampExtended, animate), Functor(self.exitRampExtended, animate), [ 'retract', 'retracted']), State.State('retract', Functor(self.enterRampRetract, animate), Functor(self.exitRampRetract, animate), [ 'extend', 'extended', 'retracted']), State.State('retracted', Functor(self.enterRampRetracted, animate), Functor(self.exitRampRetracted, animate), [ 'extend', 'extended']), State.State('off', Functor(self.enterRampOff, animate), Functor(self.exitRampOff, animate))], 'off', 'off', onUndefTransition=ClassicFSM.ClassicFSM.DISALLOW) fsm.enterInitialState() return fsm def enterRampExtend(self, animate): intervalName = self.uniqueName('extend-%s' % animate.getName()) adjustTime = 2.0 * animate.getX() / 18.0 ival = Parallel(SoundInterval(self.rampSlideSfx, node=animate), animate.posInterval(adjustTime, Point3(0, 0, 0), blendType='easeInOut', name=intervalName)) ival.start() self.storeInterval(ival, intervalName) def exitRampExtend(self, animate): intervalName = self.uniqueName('extend-%s' % animate.getName()) self.clearInterval(intervalName) def enterRampExtended(self, animate): animate.setPos(0, 0, 0) def exitRampExtended(self, animate): pass def enterRampRetract(self, animate): intervalName = self.uniqueName('retract-%s' % animate.getName()) adjustTime = 2.0 * (18 - animate.getX()) / 18.0 ival = Parallel(SoundInterval(self.rampSlideSfx, node=animate), animate.posInterval(adjustTime, Point3(18, 0, 0), blendType='easeInOut', name=intervalName)) ival.start() self.storeInterval(ival, intervalName) def exitRampRetract(self, animate): intervalName = self.uniqueName('retract-%s' % animate.getName()) self.clearInterval(intervalName) def enterRampRetracted(self, animate): animate.setPos(18, 0, 0) def exitRampRetracted(self, animate): pass def enterRampOff(self, animate): pass def exitRampOff(self, animate): pass def enterOff(self): DistributedBossCog.DistributedBossCog.enterOff(self) if self.cagedToon: self.cagedToon.clearChat() if self.rampA: self.rampA.request('off') if self.rampB: self.rampB.request('off') if self.rampC: self.rampC.request('off') def enterWaitForToons(self): DistributedBossCog.DistributedBossCog.enterWaitForToons(self) self.geom.hide() self.cagedToon.removeActive() def exitWaitForToons(self): DistributedBossCog.DistributedBossCog.exitWaitForToons(self) self.geom.show() self.cagedToon.addActive() def enterElevator(self): DistributedBossCog.DistributedBossCog.enterElevator(self) self.rampA.request('extended') self.rampB.request('extended') self.rampC.request('retracted') self.setCageIndex(0) self.reparentTo(render) self.setPosHpr(*ToontownGlobals.SellbotBossBattleOnePosHpr) self.happy = 1 self.raised = 1 self.forward = 1 self.doAnimate() self.cagedToon.removeActive() def exitElevator(self): DistributedBossCog.DistributedBossCog.exitElevator(self) self.cagedToon.addActive() def enterIntroduction(self): self.reparentTo(render) self.setPosHpr(*ToontownGlobals.SellbotBossBattleOnePosHpr) self.stopAnimate() DistributedBossCog.DistributedBossCog.enterIntroduction(self) self.rampA.request('extended') self.rampB.request('extended') self.rampC.request('retracted') self.setCageIndex(0) base.playMusic(self.promotionMusic, looping=1, volume=0.9) def exitIntroduction(self): DistributedBossCog.DistributedBossCog.exitIntroduction(self) self.promotionMusic.stop() def enterBattleOne(self): DistributedBossCog.DistributedBossCog.enterBattleOne(self) self.reparentTo(render) self.setPosHpr(*ToontownGlobals.SellbotBossBattleOnePosHpr) self.clearChat() self.cagedToon.clearChat() self.rampA.request('retract') self.rampB.request('retract') self.rampC.request('retract') if self.battleA == None or self.battleB == None: cageIndex = 1 else: cageIndex = 0 self.setCageIndex(cageIndex) return def exitBattleOne(self): DistributedBossCog.DistributedBossCog.exitBattleOne(self) def enterRollToBattleTwo(self): self.disableToonCollision() self.releaseToons() if self.arenaSide: self.rampA.request('retract') self.rampB.request('extend') else: self.rampA.request('extend') self.rampB.request('retract') self.rampC.request('retract') self.reparentTo(render) self.setCageIndex(2) self.stickBossToFloor() intervalName = 'RollToBattleTwo' seq = Sequence(self.__makeRollToBattleTwoMovie(), Func(self.__onToPrepareBattleTwo), name=intervalName) seq.start() self.storeInterval(seq, intervalName) base.playMusic(self.betweenBattleMusic, looping=1, volume=0.9) self.__showEasyBarrels() taskMgr.doMethodLater(0.5, self.enableToonCollision, 'enableToonCollision') def __onToPrepareBattleTwo(self): self.disableToonCollision() self.unstickBoss() self.setPosHpr(*ToontownGlobals.SellbotBossBattleTwoPosHpr) self.doneBarrier('RollToBattleTwo') def exitRollToBattleTwo(self): self.unstickBoss() intervalName = 'RollToBattleTwo' self.clearInterval(intervalName) self.betweenBattleMusic.stop() def disableToonCollision(self): base.localAvatar.collisionsOff() def enableToonCollision(self, task): base.localAvatar.collisionsOn() def enterPrepareBattleTwo(self): self.cleanupIntervals() self.__hideEasyBarrels() self.controlToons() self.clearChat() self.cagedToon.clearChat() self.reparentTo(render) if self.arenaSide: self.rampA.request('retract') self.rampB.request('extend') else: self.rampA.request('extend') self.rampB.request('retract') self.rampC.request('retract') self.reparentTo(render) self.setCageIndex(2) camera.reparentTo(render) camera.setPosHpr(self.cage, 0, -17, 3.3, 0, 0, 0) (localAvatar.setCameraFov(ToontownGlobals.CogHQCameraFov),) self.hide() self.acceptOnce('doneChatPage', self.__onToBattleTwo) self.cagedToon.setLocalPageChat(TTLocalizer.CagedToonPrepareBattleTwo, 1) base.playMusic(self.stingMusic, looping=0, volume=1.0) taskMgr.doMethodLater(0.5, self.enableToonCollision, 'enableToonCollision') def __onToBattleTwo(self, elapsed): self.doneBarrier('PrepareBattleTwo') taskMgr.doMethodLater(1, self.__showWaitingMessage, self.uniqueName('WaitingMessage')) def exitPrepareBattleTwo(self): self.show() taskMgr.remove(self.uniqueName('WaitingMessage')) self.ignore('doneChatPage') self.__clearOnscreenMessage() self.stingMusic.stop() def enterBattleTwo(self): self.cleanupIntervals() mult = ToontownBattleGlobals.getBossBattleCreditMultiplier(2) localAvatar.inventory.setBattleCreditMultiplier(mult) self.reparentTo(render) self.setPosHpr(*ToontownGlobals.SellbotBossBattleTwoPosHpr) self.clearChat() self.cagedToon.clearChat() self.rampA.request('retract') self.rampB.request('retract') self.rampC.request('retract') self.releaseToons() self.toonsToBattlePosition(self.toonsA, self.battleANode) self.toonsToBattlePosition(self.toonsB, self.battleBNode) if self.battleA == None or self.battleB == None: cageIndex = 3 else: cageIndex = 2 self.setCageIndex(cageIndex) base.playMusic(self.battleTwoMusic, looping=1, volume=0.9) return def exitBattleTwo(self): intervalName = self.uniqueName('cageDrop') self.clearInterval(intervalName) self.cleanupBattles() self.battleTwoMusic.stop() localAvatar.inventory.setBattleCreditMultiplier(1) def enterPrepareBattleThree(self): self.cleanupIntervals() self.controlToons() self.clearChat() self.cagedToon.clearChat() self.reparentTo(render) self.rampA.request('retract') self.rampB.request('retract') self.rampC.request('extend') self.setCageIndex(4) camera.reparentTo(render) camera.setPosHpr(self.cage, 0, -17, 3.3, 0, 0, 0) (localAvatar.setCameraFov(ToontownGlobals.CogHQCameraFov),) self.hide() self.acceptOnce('doneChatPage', self.__onToBattleThree) self.cagedToon.setLocalPageChat(TTLocalizer.CagedToonPrepareBattleThree, 1) base.playMusic(self.betweenBattleMusic, looping=1, volume=0.9) def __onToBattleThree(self, elapsed): self.doneBarrier('PrepareBattleThree') taskMgr.doMethodLater(1, self.__showWaitingMessage, self.uniqueName('WaitingMessage')) def exitPrepareBattleThree(self): self.show() taskMgr.remove(self.uniqueName('WaitingMessage')) self.ignore('doneChatPage') intervalName = 'PrepareBattleThree' self.clearInterval(intervalName) self.__clearOnscreenMessage() self.betweenBattleMusic.stop() def enterBattleThree(self): DistributedBossCog.DistributedBossCog.enterBattleThree(self) self.clearChat() self.cagedToon.clearChat() self.reparentTo(render) self.rampA.request('retract') self.rampB.request('retract') self.rampC.request('extend') self.setCageIndex(4) self.happy = 0 self.raised = 1 self.forward = 1 self.doAnimate() self.accept('enterCage', self.__touchedCage) self.accept('pieSplat', self.__pieSplat) self.accept('localPieSplat', self.__localPieSplat) self.accept('outOfPies', self.__outOfPies) self.accept('begin-pie', self.__foundPieButton) localAvatar.setCameraFov(ToontownGlobals.BossBattleCameraFov) taskMgr.doMethodLater(30, self.__howToGetPies, self.uniqueName('PieAdvice')) self.stickBossToFloor() self.bossDamageMovie = self.__makeBossDamageMovie() bossDoneEventName = self.uniqueName('DestroyedBoss') self.bossDamageMovie.setDoneEvent(bossDoneEventName) self.acceptOnce(bossDoneEventName, self.__doneBattleThree) self.resetMaxDamage() self.bossDamageToMovie = self.bossDamageMovie.getDuration() / self.bossMaxDamage self.bossDamageMovie.setT(self.bossDamage * self.bossDamageToMovie) base.playMusic(self.battleThreeMusic, looping=1, volume=0.9) def __doneBattleThree(self): self.setState('NearVictory') self.unstickBoss() def exitBattleThree(self): DistributedBossCog.DistributedBossCog.exitBattleThree(self) bossDoneEventName = self.uniqueName('DestroyedBoss') self.ignore(bossDoneEventName) taskMgr.remove(self.uniqueName('StandUp')) self.ignore('enterCage') self.ignore('pieSplat') self.ignore('localPieSplat') self.ignore('outOfPies') self.ignore('begin-pie') self.__clearOnscreenMessage() taskMgr.remove(self.uniqueName('PieAdvice')) localAvatar.setCameraFov(ToontownGlobals.CogHQCameraFov) self.__removeCageShadow() self.bossDamageMovie.finish() self.bossDamageMovie = None self.unstickBoss() taskName = 'RecoverBossDamage' taskMgr.remove(taskName) self.battleThreeMusicTime = self.battleThreeMusic.getTime() self.battleThreeMusic.stop() return def enterNearVictory(self): self.cleanupIntervals() self.reparentTo(render) self.setPos(*ToontownGlobals.SellbotBossDeathPos) self.setHpr(*ToontownGlobals.SellbotBossBattleThreeHpr) self.clearChat() self.cagedToon.clearChat() self.setCageIndex(4) self.releaseToons(finalBattle=1) self.rampA.request('retract') self.rampB.request('retract') self.rampC.request('extend') self.accept('enterCage', self.__touchedCage) self.accept('pieSplat', self.__finalPieSplat) self.accept('localPieSplat', self.__localPieSplat) self.accept('outOfPies', self.__outOfPies) localAvatar.setCameraFov(ToontownGlobals.BossBattleCameraFov) self.happy = 0 self.raised = 0 self.forward = 1 self.doAnimate() self.setDizzy(1) base.playMusic(self.battleThreeMusic, looping=1, volume=0.9, time=self.battleThreeMusicTime) def exitNearVictory(self): self.ignore('enterCage') self.ignore('pieSplat') self.ignore('localPieSplat') self.ignore('outOfPies') self.__clearOnscreenMessage() taskMgr.remove(self.uniqueName('PieAdvice')) localAvatar.setCameraFov(ToontownGlobals.CogHQCameraFov) self.__removeCageShadow() self.setDizzy(0) self.battleThreeMusicTime = self.battleThreeMusic.getTime() self.battleThreeMusic.stop() def enterVictory(self): self.cleanupIntervals() localAvatar.setCameraFov(ToontownGlobals.BossBattleCameraFov) self.reparentTo(render) self.setPos(*ToontownGlobals.SellbotBossDeathPos) self.setHpr(*ToontownGlobals.SellbotBossBattleThreeHpr) self.clearChat() self.cagedToon.clearChat() self.setCageIndex(4) self.releaseToons(finalBattle=1) self.rampA.request('retract') self.rampB.request('retract') self.rampC.request('extend') self.happy = 0 self.raised = 0 self.forward = 1 self.doAnimate('Fb_fall', now=1) self.acceptOnce(self.animDoneEvent, self.__continueVictory) base.playMusic(self.battleThreeMusic, looping=1, volume=0.9, time=self.battleThreeMusicTime) def __continueVictory(self): self.stopAnimate() self.stash() self.doneBarrier('Victory') def exitVictory(self): self.stopAnimate() self.unstash() self.__removeCageShadow() localAvatar.setCameraFov(ToontownGlobals.CogHQCameraFov) self.battleThreeMusicTime = self.battleThreeMusic.getTime() self.battleThreeMusic.stop() def enterReward(self): self.cleanupIntervals() self.clearChat() self.cagedToon.clearChat() self.stash() self.stopAnimate() self.setCageIndex(4) self.releaseToons(finalBattle=1) self.toMovieMode() self.rampA.request('retract') self.rampB.request('retract') self.rampC.request('extend') 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, 'SellbotBoss.enterReward')) ival.delayDeletes = delayDeletes ival.start() self.storeInterval(ival, intervalName) base.playMusic(self.battleThreeMusic, looping=1, volume=0.9, time=self.battleThreeMusicTime) def __doneReward(self): self.doneBarrier('Reward') self.toWalkMode() def exitReward(self): intervalName = 'RewardMovie' self.clearInterval(intervalName) self.unstash() self.rewardPanel.destroy() del self.rewardPanel self.__removeCageShadow() self.battleThreeMusicTime = 0 self.battleThreeMusic.stop() def enterEpilogue(self): self.cleanupIntervals() self.clearChat() self.cagedToon.clearChat() self.stash() self.stopAnimate() self.setCageIndex(4) self.controlToons() self.rampA.request('retract') self.rampB.request('retract') self.rampC.request('extend') self.__arrangeToonsAroundCage() camera.reparentTo(render) camera.setPosHpr(-24, 52, 27.5, -53, -13, 0) intervalName = 'EpilogueMovie' seq = Sequence(self.__makeCageOpenMovie(), name=intervalName) seq.start() self.storeInterval(seq, intervalName) self.accept('nextChatPage', self.__epilogueChatNext) self.accept('doneChatPage', self.__epilogueChatDone) base.playMusic(self.epilogueMusic, looping=1, volume=0.9) def __epilogueChatNext(self, pageNumber, elapsed): if pageNumber == 2: if self.cagedToon.style.torso[1] == 'd': track = ActorInterval(self.cagedToon, 'curtsy') else: track = ActorInterval(self.cagedToon, 'bow') track = Sequence(track, Func(self.cagedToon.loop, 'neutral')) intervalName = 'EpilogueMovieToonAnim' self.storeInterval(track, intervalName) track.start() def __epilogueChatDone(self, elapsed): self.cagedToon.setChatAbsolute(TTLocalizer.CagedToonGoodbye, CFSpeech) self.ignore('nextChatPage') self.ignore('doneChatPage') intervalName = 'EpilogueMovieToonAnim' self.clearInterval(intervalName) track = Parallel(Sequence(ActorInterval(self.cagedToon, 'wave'), Func(self.cagedToon.loop, 'neutral')), Sequence(Wait(0.5), Func(self.localToonToSafeZone))) self.storeInterval(track, intervalName) track.start() def exitEpilogue(self): self.clearInterval('EpilogueMovieToonAnim') self.unstash() self.__removeCageShadow() self.epilogueMusic.stop() def __arrangeToonsAroundCage(self): radius = 15 numToons = len(self.involvedToons) center = (numToons - 1) / 2.0 for i in range(numToons): toon = base.cr.doId2do.get(self.involvedToons[i]) if toon: angle = 270 - 15 * (i - center) radians = angle * math.pi / 180.0 x = math.cos(radians) * radius y = math.sin(radians) * radius toon.setPos(self.cage, x, y, 0) toon.setZ(18.0) toon.headsUp(self.cage) def enterFrolic(self): DistributedBossCog.DistributedBossCog.enterFrolic(self) self.setPosHpr(*ToontownGlobals.SellbotBossBattleOnePosHpr) def doorACallback(self, isOpen): if self.insidesANodePath: if isOpen: self.insidesANodePath.unstash() else: self.insidesANodePath.stash() def doorBCallback(self, isOpen): if self.insidesBNodePath: if isOpen: self.insidesBNodePath.unstash() else: self.insidesBNodePath.stash() def __toonsToPromotionPosition(self, toonIds, battleNode): points = BattleBase.BattleBase.toonPoints[len(toonIds) - 1] for i in range(len(toonIds)): toon = base.cr.doId2do.get(toonIds[i]) if toon: toon.reparentTo(render) pos, h = points[i] toon.setPosHpr(battleNode, pos[0], pos[1] + 10, pos[2], h, 0, 0) def __doobersToPromotionPosition(self, doobers, battleNode): points = BattleBase.BattleBase.toonPoints[len(doobers) - 1] for i in range(len(doobers)): suit = doobers[i] suit.fsm.request('neutral') suit.loop('neutral') pos, h = points[i] suit.setPosHpr(battleNode, pos[0], pos[1] + 10, pos[2], h, 0, 0) def __touchedCage(self, entry): self.sendUpdate('touchCage', []) self.__clearOnscreenMessage() taskMgr.remove(self.uniqueName('PieAdvice')) base.playSfx(self.piesRestockSfx) if not self.everThrownPie: taskMgr.doMethodLater(30, self.__howToThrowPies, self.uniqueName('PieAdvice')) def __outOfPies(self): self.__showOnscreenMessage(TTLocalizer.BossBattleNeedMorePies) taskMgr.doMethodLater(20, self.__howToGetPies, self.uniqueName('PieAdvice')) def __howToGetPies(self, task): self.__showOnscreenMessage(TTLocalizer.BossBattleHowToGetPies) def __howToThrowPies(self, task): self.__showOnscreenMessage(TTLocalizer.BossBattleHowToThrowPies) def __foundPieButton(self): self.everThrownPie = 1 self.__clearOnscreenMessage() taskMgr.remove(self.uniqueName('PieAdvice')) def __pieSplat(self, toon, pieCode): if base.config.GetBool('easy-vp', 0): if not self.dizzy: pieCode = ToontownGlobals.PieCodeBossInsides if pieCode == ToontownGlobals.PieCodeBossInsides: if toon == localAvatar: self.d_hitBossInsides() self.flashRed() elif pieCode == ToontownGlobals.PieCodeBossCog: if toon == localAvatar: self.d_hitBoss(1) if self.dizzy: self.flashRed() self.doAnimate('hit', now=1) def __localPieSplat(self, pieCode, entry): if pieCode != ToontownGlobals.PieCodeToon: return avatarDoId = entry.getIntoNodePath().getNetTag('avatarDoId') if avatarDoId == '': self.notify.warning('Toon %s has no avatarDoId tag.' % repr(entry.getIntoNodePath())) return doId = int(avatarDoId) if doId != localAvatar.doId: self.d_hitToon(doId) def __finalPieSplat(self, toon, pieCode): if pieCode != ToontownGlobals.PieCodeBossCog: return self.sendUpdate('finalPieSplat', []) self.ignore('pieSplat') def cagedToonBattleThree(self, index, avId): str = TTLocalizer.CagedToonBattleThree.get(index) if str: toonName = '' if avId: toon = self.cr.doId2do.get(avId) if not toon: self.cagedToon.clearChat() return toonName = toon.getName() text = str % {'toon': toonName} self.cagedToon.setChatAbsolute(text, CFSpeech | CFTimeout) else: self.cagedToon.clearChat() def cleanupAttacks(self): self.__cleanupStrafe() def __cleanupStrafe(self): if self.strafeInterval: self.strafeInterval.finish() self.strafeInterval = None return def doStrafe(self, side, direction): gearRoot = self.rotateNode.attachNewNode('gearRoot') if side == 0: gearRoot.setPos(0, -7, 3) gearRoot.setHpr(180, 0, 0) door = self.doorA else: gearRoot.setPos(0, 7, 3) door = self.doorB gearRoot.setTag('attackCode', str(ToontownGlobals.BossCogStrafeAttack)) gearModel = self.getGearFrisbee() gearModel.setScale(0.1) t = self.getBossDamage() / 100.0 gearTrack = Parallel() numGears = int(4 + 6 * t + 0.5) time = 5.0 - 4.0 * t spread = 60 * math.pi / 180.0 if direction == 1: spread = -spread dist = 50 rate = time / numGears for i in range(numGears): node = gearRoot.attachNewNode(str(i)) node.hide() node.setPos(0, 0, 0) gear = gearModel.instanceTo(node) angle = (float(i) / (numGears - 1) - 0.5) * spread x = dist * math.sin(angle) y = dist * math.cos(angle) h = random.uniform(-720, 720) gearTrack.append(Sequence(Wait(i * rate), Func(node.show), Parallel(node.posInterval(1, Point3(x, y, 0), fluid=1), node.hprInterval(1, VBase3(h, 0, 0), fluid=1), Sequence(SoundInterval(self.strafeSfx[i], volume=0.2, node=self), duration=0)), Func(node.detachNode))) seq = Sequence(Func(door.request, 'open'), Wait(0.7), gearTrack, Func(door.request, 'close')) self.__cleanupStrafe() self.strafeInterval = seq seq.start() def __showEasyBarrels(self): barrelNodes = hidden.findAllMatches('**/Distributed*Barrel-*') if not barrelNodes or barrelNodes.isEmpty(): return if render.find('barrelsRootNode'): self.notify.warning('__showEasyBarrels(): barrelsRootNode already exists') return self.barrelsRootNode = render.attachNewNode('barrelsRootNode') self.barrelsRootNode.setPos(*SellbotBossGlobals.BarrelsStartPos) if self.arenaSide == 0: self.barrelsRootNode.setHpr(180, 0, 0) else: self.barrelsRootNode.setHpr(0, 0, 0) for i, barrelNode in enumerate(barrelNodes): barrel = base.cr.doId2do.get(int(barrelNode.getNetTag('doId'))) SellbotBossGlobals.setBarrelAttr(barrel, barrel.entId) if hasattr(barrel, 'applyLabel'): barrel.applyLabel() barrel.setPosHpr(barrel.pos, barrel.hpr) barrel.reparentTo(self.barrelsRootNode) intervalName = 'MakeBarrelsAppear' seq = Sequence(LerpPosInterval(self.barrelsRootNode, 0.5, Vec3(*SellbotBossGlobals.BarrelsFinalPos), blendType='easeInOut'), name=intervalName) seq.start() self.storeInterval(seq, intervalName) def __hideEasyBarrels(self): if hasattr(self, 'barrelsRootNode'): self.barrelsRootNode.removeNode() intervalName = 'MakeBarrelsAppear' self.clearInterval(intervalName) def toonPromoted(self, promoted): self.localToonPromoted = promoted