def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedGolfSpot') self.boss = None self.index = None self.avId = 0 self.toon = None self.golfSpotSmoother = SmoothMover() self.golfSpotSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 if self.index > len(self.positions): self.notify.error('Invalid index %d' % index) self.fadeTrack = None self.setupPowerBar() self.aimStart = None self.golfSpotAdviceLabel = None self.changeSeq = 0 self.lastChangeSeq = 0 self.controlKeyAllowed = False self.flyBallTracks = {} self.splatTracks = {} self.__flyBallBubble = None self.flyBallHandler = None self.__flyBallSequenceNum = 0 self.swingInterval = None self.lastHitSequenceNum = -1 self.goingToReward = False self.gotHitByBoss = False self.releaseTrack = None self.grabTrack = None self.restoreScaleTrack = None return
def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedBanquetTable') self.boss = None self.index = -1 self.diners = {} self.dinerStatus = {} self.serviceLocs = {} self.chairLocators = {} self.sitLocators = {} self.activeIntervals = {} self.dinerStatusIndicators = {} self.preparedForPhaseFour = False self.avId = 0 self.toon = None self.pitcherSmoother = SmoothMover() self.pitcherSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 self.changeSeq = 0 self.lastChangeSeq = 0 self.pitcherAdviceLabel = None self.fireLength = 250 self.fireTrack = None self.hitObject = None self.setupPowerBar() self.aimStart = None self.toonPitcherPosition = Point3(0, -2, 0) self.allowLocalRequestControl = True self.fadeTrack = None self.grabTrack = None self.gotHitByBoss = False self.keyTTL = [] self.keyRate = 0 self.buttons = [0, 1] self.lastPowerFired = 0 self.moveSound = None self.releaseTrack = None return
class DistributedBanquetTable(DistributedObject.DistributedObject, FSM.FSM, BanquetTableBase.BanquetTableBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBanquetTable') rotationsPerSeatIndex = [90, 90, 0, 0, -90, -90, 180, 180] pitcherMinH = -360 pitcherMaxH = 360 rotateSpeed = 30 waterPowerSpeed = base.config.GetDouble('water-power-speed', 15) waterPowerExponent = base.config.GetDouble('water-power-exponent', 0.75) useNewAnimations = True TugOfWarControls = False OnlyUpArrow = True if OnlyUpArrow: BASELINE_KEY_RATE = 3 else: BASELINE_KEY_RATE = 6 UPDATE_KEY_PRESS_RATE_TASK = 'BanquetTableUpdateKeyPressRateTask' YELLOW_POWER_THRESHOLD = 0.75 RED_POWER_THRESHOLD = 0.97 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedBanquetTable') self.boss = None self.index = -1 self.diners = {} self.dinerStatus = {} self.serviceLocs = {} self.chairLocators = {} self.sitLocators = {} self.activeIntervals = {} self.dinerStatusIndicators = {} self.preparedForPhaseFour = False self.avId = 0 self.toon = None self.pitcherSmoother = SmoothMover() self.pitcherSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 self.changeSeq = 0 self.lastChangeSeq = 0 self.pitcherAdviceLabel = None self.fireLength = 250 self.fireTrack = None self.hitObject = None self.setupPowerBar() self.aimStart = None self.toonPitcherPosition = Point3(0, -2, 0) self.allowLocalRequestControl = True self.fadeTrack = None self.grabTrack = None self.gotHitByBoss = False self.keyTTL = [] self.keyRate = 0 self.buttons = [0, 1] self.lastPowerFired = 0 self.moveSound = None self.releaseTrack = None return def disable(self): DistributedObject.DistributedObject.disable(self) taskMgr.remove(self.triggerName) taskMgr.remove(self.smoothName) taskMgr.remove(self.watchControlsName) taskMgr.remove(self.pitcherAdviceName) taskMgr.remove(self.posHprBroadcastName) taskMgr.remove(self.waterPowerTaskName) if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None if self.fireTrack: self.fireTrack.finish() self.fireTrack = None self.cleanupIntervals() return def delete(self): DistributedObject.DistributedObject.delete(self) self.boss = None self.ignoreAll() for indicator in list(self.dinerStatusIndicators.values()): indicator.delete() self.dinerStatusIndicators = {} for diner in list(self.diners.values()): diner.delete() self.diners = {} self.powerBar.destroy() self.powerBar = None self.pitcherMoveSfx.stop() return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.loadAssets() self.smoothName = self.uniqueName('pitcherSmooth') self.pitcherAdviceName = self.uniqueName('pitcherAdvice') self.posHprBroadcastName = self.uniqueName('pitcherBroadcast') self.waterPowerTaskName = self.uniqueName('updateWaterPower') self.triggerName = self.uniqueName('trigger') self.watchControlsName = self.uniqueName('watchControls') def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setTable(self, self.index) def setIndex(self, index): self.index = index def setState(self, state, avId, extraInfo): self.gotHitByBoss = extraInfo if state == 'F': self.demand('Off') elif state == 'N': self.demand('On') elif state == 'I': self.demand('Inactive') elif state == 'R': self.demand('Free') elif state == 'C': self.demand('Controlled', avId) elif state == 'L': self.demand('Flat', avId) else: self.notify.error('Invalid state from AI: %s' % state) def setNumDiners(self, numDiners): self.numDiners = numDiners def setDinerInfo(self, hungryDurations, eatingDurations, dinerLevels): self.dinerInfo = {} for i in range(len(hungryDurations)): hungryDur = hungryDurations[i] eatingDur = eatingDurations[i] dinerLevel = dinerLevels[i] self.dinerInfo[i] = (hungryDur, eatingDur, dinerLevel) def loadAssets(self): self.tableGroup = loader.loadModel('phase_12/models/bossbotHQ/BanquetTableChairs') tableLocator = self.boss.geom.find('**/TableLocator_%d' % (self.index + 1)) if tableLocator.isEmpty(): self.tableGroup.reparentTo(render) self.tableGroup.setPos(0, 75, 0) else: self.tableGroup.reparentTo(tableLocator) self.tableGeom = self.tableGroup.find('**/Geometry') self.setupDiners() self.setupChairCols() self.squirtSfx = loader.loadSfx('phase_4/audio/sfx/AA_squirt_seltzer_miss.ogg') self.hitBossSfx = loader.loadSfx('phase_5/audio/sfx/SA_watercooler_spray_only.ogg') self.hitBossSoundInterval = SoundInterval(self.hitBossSfx, node=self.boss, volume=1.0) self.serveFoodSfx = loader.loadSfx('phase_4/audio/sfx/MG_sfx_travel_game_bell_for_trolley.ogg') self.pitcherMoveSfx = base.loader.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.ogg') def setupDiners(self): for i in range(self.numDiners): newDiner = self.createDiner(i) self.diners[i] = newDiner self.dinerStatus[i] = self.HUNGRY def createDiner(self, i): diner = Suit.Suit() diner.dna = SuitDNA.SuitDNA() level = self.dinerInfo[i][2] level -= 4 diner.dna.newSuitRandom(level=level, dept='c') diner.setDNA(diner.dna) diner.nametag.setNametag2d(None) diner.nametag.setNametag3d(None) if self.useNewAnimations: diner.loop('sit', fromFrame=i) else: diner.pose('landing', 0) locator = self.tableGroup.find('**/chair_%d' % (i + 1)) locatorScale = locator.getNetTransform().getScale()[0] correctHeadingNp = locator.attachNewNode('correctHeading') self.chairLocators[i] = correctHeadingNp heading = self.rotationsPerSeatIndex[i] correctHeadingNp.setH(heading) sitLocator = correctHeadingNp.attachNewNode('sitLocator') base.sitLocator = sitLocator pos = correctHeadingNp.getPos(render) if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': sitLocator.setPos(0.5, 3.65, -3.75) else: sitLocator.setZ(-2.4) sitLocator.setY(2.5) sitLocator.setX(0.5) self.sitLocators[i] = sitLocator diner.setScale(1.0 / locatorScale) diner.reparentTo(sitLocator) newLoc = NodePath('serviceLoc-%d-%d' % (self.index, i)) newLoc.reparentTo(correctHeadingNp) newLoc.setPos(0, 3.0, 1) self.serviceLocs[i] = newLoc base.serviceLoc = newLoc head = diner.find('**/joint_head') newIndicator = DinerStatusIndicator.DinerStatusIndicator(parent=head, pos=Point3(0, 0, 3.5), scale=5.0) newIndicator.wrtReparentTo(diner) self.dinerStatusIndicators[i] = newIndicator return diner def setupChairCols(self): for i in range(self.numDiners): chairCol = self.tableGroup.find('**/collision_chair_%d' % (i + 1)) colName = 'ChairCol-%d-%d' % (self.index, i) chairCol.setTag('chairIndex', str(i)) chairCol.setName(colName) chairCol.setCollideMask(ToontownGlobals.WallBitmask) self.accept('enter' + colName, self.touchedChair) def touchedChair(self, colEntry): chairIndex = int(colEntry.getIntoNodePath().getTag('chairIndex')) if chairIndex in self.dinerStatus: status = self.dinerStatus[chairIndex] if status in (self.HUNGRY, self.ANGRY): self.boss.localToonTouchedChair(self.index, chairIndex) def serveFood(self, food, chairIndex): self.removeFoodModel(chairIndex) serviceLoc = self.serviceLocs.get(chairIndex) if not food or food.isEmpty(): foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood') foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(serviceLoc) else: food.wrtReparentTo(serviceLoc) tray = food.find('**/tray') if not tray.isEmpty(): tray.hide() ivalDuration = 1.5 foodMoveIval = Parallel(SoundInterval(self.serveFoodSfx, node=food), ProjectileInterval(food, duration=ivalDuration, startPos=food.getPos(serviceLoc), endPos=serviceLoc.getPos(serviceLoc)), LerpHprInterval(food, ivalDuration, Point3(0, -360, 0))) intervalName = 'serveFood-%d-%d' % (self.index, chairIndex) foodMoveIval.start() self.activeIntervals[intervalName] = foodMoveIval def setDinerStatus(self, chairIndex, status): if chairIndex in self.dinerStatus: oldStatus = self.dinerStatus[chairIndex] self.dinerStatus[chairIndex] = status if oldStatus != status: if status == self.EATING: self.changeDinerToEating(chairIndex) elif status == self.HUNGRY: self.changeDinerToHungry(chairIndex) elif status == self.ANGRY: self.changeDinerToAngry(chairIndex) elif status == self.DEAD: self.changeDinerToDead(chairIndex) elif status == self.HIDDEN: self.changeDinerToHidden(chairIndex) def removeFoodModel(self, chairIndex): serviceLoc = self.serviceLocs.get(chairIndex) if serviceLoc: for i in range(serviceLoc.getNumChildren()): serviceLoc.getChild(0).removeNode() def changeDinerToEating(self, chairIndex): indicator = self.dinerStatusIndicators.get(chairIndex) eatingDuration = self.dinerInfo[chairIndex][1] if indicator: indicator.request('Eating', eatingDuration) diner = self.diners[chairIndex] intervalName = 'eating-%d-%d' % (self.index, chairIndex) eatInTime = 32.0 / 24.0 eatOutTime = 21.0 / 24.0 eatLoopTime = 19 / 24.0 rightHand = diner.getRightHand() waitTime = 5 loopDuration = eatingDuration - eatInTime - eatOutTime - waitTime serviceLoc = self.serviceLocs[chairIndex] def foodAttach(self = self, diner = diner): if self.serviceLocs[chairIndex].getNumChildren() < 1: return foodModel = self.serviceLocs[chairIndex].getChild(0) (foodModel.reparentTo(diner.getRightHand()),) (foodModel.setHpr(Point3(0, -94, 0)),) (foodModel.setPos(Point3(-0.15, -0.7, -0.4)),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': scaleAdj = 0.6 (foodModel.setPos(Point3(0.1, -0.25, -0.31)),) else: scaleAdj = 0.8 (foodModel.setPos(Point3(-0.25, -0.85, -0.34)),) oldScale = foodModel.getScale() newScale = oldScale * scaleAdj foodModel.setScale(newScale) def foodDetach(self = self, diner = diner): if diner.getRightHand().getNumChildren() < 1: return foodModel = diner.getRightHand().getChild(0) (foodModel.reparentTo(serviceLoc),) (foodModel.setPosHpr(0, 0, 0, 0, 0, 0),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == 'c': scaleAdj = 0.6 else: scakeAdj = 0.8 oldScale = foodModel.getScale() newScale = oldScale / scaleAdj foodModel.setScale(newScale) eatIval = Sequence(ActorInterval(diner, 'sit', duration=waitTime), ActorInterval(diner, 'sit-eat-in', startFrame=0, endFrame=6), Func(foodAttach), ActorInterval(diner, 'sit-eat-in', startFrame=6, endFrame=32), ActorInterval(diner, 'sit-eat-loop', duration=loopDuration, loop=1), ActorInterval(diner, 'sit-eat-out', startFrame=0, endFrame=12), Func(foodDetach), ActorInterval(diner, 'sit-eat-out', startFrame=12, endFrame=21)) eatIval.start() self.activeIntervals[intervalName] = eatIval def changeDinerToHungry(self, chairIndex): intervalName = 'eating-%d-%d' % (self.index, chairIndex) if intervalName in self.activeIntervals: self.activeIntervals[intervalName].finish() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Hungry', self.dinerInfo[chairIndex][0]) diner = self.diners[chairIndex] if random.choice([0, 1]): diner.loop('sit-hungry-left') else: diner.loop('sit-hungry-right') def changeDinerToAngry(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Angry') diner = self.diners[chairIndex] diner.loop('sit-angry') def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Dead') diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find('**/chair_%d' % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence(Func(self.notify.debug, 'before actorinterval sit-lose'), ActorInterval(diner, 'sit-lose'), Func(self.notify.debug, 'before deathSuit.setHpr'), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, 'before diner.hide'), Func(diner.hide), Func(self.notify.debug, 'before deathSuit.reparentTo'), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, 'befor ActorInterval lose'), ActorInterval(deathSuit, 'lose', duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, 'before remove deathsuit'), Func(removeDeathSuit, diner, deathSuit, name='remove-death-suit-%d-%d' % (chairIndex, self.index)), Func(self.notify.debug, 'diner.stash'), Func(diner.stash)) spinningSound = base.loader.loadSfx('phase_3.5/audio/sfx/Cog_Death.ogg') deathSound = base.loader.loadSfx('phase_3.5/audio/sfx/ENC_cogfall_apart.ogg') deathSoundTrack = Sequence(Wait(0.8), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.2, node=deathSuit), SoundInterval(spinningSound, duration=3.0, startTime=0.6, volume=0.8, node=deathSuit), SoundInterval(deathSound, volume=0.32, node=deathSuit)) intervalName = 'dinerDie-%d-%d' % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval def changeDinerToHidden(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Inactive') diner = self.diners[chairIndex] diner.hide() def setAllDinersToSitNeutral(self): startFrame = 0 for diner in list(self.diners.values()): if not diner.isHidden(): diner.loop('sit', fromFrame=startFrame) startFrame += 1 def cleanupIntervals(self): for interval in list(self.activeIntervals.values()): interval.finish() self.activeIntervals = {} def clearInterval(self, name, finish = 1): if name in self.activeIntervals: ival = self.activeIntervals[name] if finish: ival.finish() else: ival.pause() if name in self.activeIntervals: del self.activeIntervals[name] else: self.notify.debug('interval: %s already cleared' % name) def finishInterval(self, name): if name in self.activeIntervals: interval = self.activeIntervals[name] interval.finish() def getNotDeadInfo(self): notDeadList = [] for i in range(self.numDiners): if self.dinerStatus[i] != self.DEAD: notDeadList.append((self.index, i, 12)) return notDeadList def enterOn(self): pass def exitOn(self): pass def enterInactive(self): for chairIndex in range(self.numDiners): indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request('Inactive') self.removeFoodModel(chairIndex) def exitInactive(self): pass def enterFree(self): self.resetPowerBar() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.prepareForPhaseFour() if self.avId == localAvatar.doId: self.tableGroup.setAlphaScale(0.3) self.tableGroup.setTransparency(1) taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName) self.fadeTrack = Sequence(Func(self.tableGroup.setTransparency, 1), self.tableGroup.colorScaleInterval(0.2, VBase4(1, 1, 1, 0.3))) self.fadeTrack.start() self.allowLocalRequestControl = False else: self.allowLocalRequestControl = True self.avId = 0 return def exitFree(self): pass def touchedTable(self, colEntry): tableIndex = int(colEntry.getIntoNodePath().getTag('tableIndex')) if self.state == 'Free' and self.avId == 0 and self.allowLocalRequestControl: self.d_requestControl() def prepareForPhaseFour(self): if not self.preparedForPhaseFour: for i in range(8): chair = self.tableGroup.find('**/chair_%d' % (i + 1)) if not chair.isEmpty(): chair.hide() colChairs = self.tableGroup.findAllMatches('**/ChairCol*') for i in range(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() colChairs = self.tableGroup.findAllMatches('**/collision_chair*') for i in range(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() tableCol = self.tableGroup.find('**/collision_table') colName = 'TableCol-%d' % self.index tableCol.setTag('tableIndex', str(self.index)) tableCol.setName(colName) tableCol.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.BanquetTableBitmask) self.accept('enter' + colName, self.touchedTable) self.preparedForPhaseFour = True self.waterPitcherModel = loader.loadModel('phase_12/models/bossbotHQ/tt_m_ara_bhq_seltzerBottle') lampNode = self.tableGroup.find('**/lamp_med_5') pos = lampNode.getPos(self.tableGroup) lampNode.hide() bottleLocator = self.tableGroup.find('**/bottle_locator') pos = bottleLocator.getPos(self.tableGroup) self.waterPitcherNode = self.tableGroup.attachNewNode('pitcherNode') self.waterPitcherNode.setPos(pos) self.waterPitcherModel.reparentTo(self.waterPitcherNode) self.nozzle = self.waterPitcherModel.find('**/nozzle_tip') self.handLocator = self.waterPitcherModel.find('**/hand_locator') self.handPos = self.handLocator.getPos() def d_requestControl(self): self.sendUpdate('requestControl') def d_requestFree(self, gotHitByBoss): self.sendUpdate('requestFree', [gotHitByBoss]) def enterControlled(self, avId): self.prepareForPhaseFour() self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) self.notify.debug('grabTrack=%s' % self.grabTrack) self.pitcherCamPos = Point3(0, -50, 40) self.pitcherCamHpr = Point3(0, -21, 0) if avId == localAvatar.doId: self.boss.toMovieMode() self.__enableControlInterface() self.startPosHprBroadcast() self.grabTrack = Sequence(self.grabTrack, Func(camera.wrtReparentTo, localAvatar), LerpPosHprInterval(camera, 1, self.pitcherCamPos, self.pitcherCamHpr), Func(self.boss.toCraneMode)) if self.TugOfWarControls: self.__spawnUpdateKeyPressRateTask() self.accept('exitCrane', self.gotBossZapped) else: self.startSmooth() toon.stopSmooth() self.grabTrack.start() def exitControlled(self): self.ignore('exitCrane') if self.grabTrack: self.grabTrack.finish() self.grabTrack = None nextState = self.getCurrentOrNextState() self.notify.debug('nextState=%s' % nextState) if nextState == 'Flat': place = base.cr.playGame.getPlace() self.notify.debug('%s' % place.fsm) if self.avId == localAvatar.doId: self.__disableControlInterface() else: if self.toon and not self.toon.isDisabled(): self.toon.loop('neutral') self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: localAvatar.wrtReparentTo(render) self.__disableControlInterface() camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.goToFinalBattle() self.safeBossToFinalBattleMode() else: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) self.releaseTrack.start() return def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, 'fsm'): if place.fsm.getCurrentState().getName() == 'crane': place.setState('finalBattle') def makeToonGrabInterval(self, toon): toon.pose('leverNeutral', 0) toon.update() rightHandPos = toon.rightHand.getPos(toon) self.toonPitcherPosition = Point3(self.handPos[0] - rightHandPos[0], self.handPos[1] - rightHandPos[1], 0) destZScale = rightHandPos[2] / self.handPos[2] grabIval = Sequence(Func(toon.wrtReparentTo, self.waterPitcherNode), Func(toon.loop, 'neutral'), Parallel(ActorInterval(toon, 'jump'), Sequence(Wait(0.43), Parallel(ProjectileInterval(toon, duration=0.9, startPos=toon.getPos(self.waterPitcherNode), endPos=self.toonPitcherPosition), LerpHprInterval(toon, 0.9, Point3(0, 0, 0)), LerpScaleInterval(self.waterPitcherModel, 0.9, Point3(1, 1, destZScale))))), Func(toon.setPos, self.toonPitcherPosition), Func(toon.loop, 'leverNeutral')) return grabIval def makeToonReleaseInterval(self, toon): temp1 = self.waterPitcherNode.attachNewNode('temp1') temp1.setPos(self.toonPitcherPosition) temp2 = self.waterPitcherNode.attachNewNode('temp2') temp2.setPos(0, -10, -self.waterPitcherNode.getZ()) startPos = temp1.getPos(render) endPos = temp2.getPos(render) temp1.removeNode() temp2.removeNode() def getSlideToPos(toon = toon): return render.getRelativePoint(toon, Point3(0, -10, 0)) if self.gotHitByBoss: self.notify.debug('creating zap interval instead') grabIval = Sequence(Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1))) else: grabIval = Sequence(Func(toon.loop, 'neutral'), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'jump'), Sequence(Wait(0.43), ProjectileInterval(toon, duration=0.9, startPos=startPos, endPos=endPos)))) return grabIval def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate('clearSmoothing', [0]) def clearSmoothing(self, bogus = None): self.pitcherSmoother.clearPositions(1) def doSmoothTask(self, task): self.pitcherSmoother.computeAndApplySmoothHpr(self.waterPitcherNode) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def __enableControlInterface(self): gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=2, text=TTLocalizer.BossbotPitcherLeave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.82), command=self.__exitPitcher) self.accept('escape', self.__exitPitcher) self.accept(base.JUMP, self.__controlPressed) self.accept('control-up', self.__controlReleased) self.accept('InputState-forward', self.__upArrow) self.accept('InputState-reverse', self.__downArrow) self.accept('InputState-turnLeft', self.__leftArrow) self.accept('InputState-turnRight', self.__rightArrow) self.accept(base.MOVE_UP, self.__upArrowKeyPressed) self.accept(base.MOVE_DOWN, self.__downArrowKeyPressed) taskMgr.add(self.__watchControls, self.watchControlsName) taskMgr.doMethodLater(5, self.__displayPitcherAdvice, self.pitcherAdviceName) self.arrowVert = 0 self.arrowHorz = 0 self.powerBar.show() return def __disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self.__cleanupPitcherAdvice() self.ignore('escape') self.ignore(base.JUMP) self.ignore('control-up') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') self.ignore(base.MOVE_UP) self.ignore(base.MOVE_DOWN) self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove(self.watchControlsName) taskMgr.remove(self.waterPowerTaskName) self.resetPowerBar() self.aimStart = None self.powerBar.hide() if self.TugOfWarControls: self.__killUpdateKeyPressRateTask() self.keyTTL = [] self.__setMoveSound(None) return def __displayPitcherAdvice(self, task): if self.pitcherAdviceLabel == None: self.pitcherAdviceLabel = DirectLabel(text=TTLocalizer.BossbotPitcherAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1) return def __cleanupPitcherAdvice(self): if self.pitcherAdviceLabel: self.pitcherAdviceLabel.destroy() self.pitcherAdviceLabel = None taskMgr.remove(self.pitcherAdviceName) return def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel(relief=None, text=TTLocalizer.BossbotPitcherLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1)) self.__cleanupPitcherAdvice() return def __exitPitcher(self): self.showExiting() self.d_requestFree(False) def __controlPressed(self): self.__cleanupPitcherAdvice() if self.TugOfWarControls: if self.power: self.aimStart = 1 self.__endFireWater() elif self.state == 'Controlled': self.__beginFireWater() def __controlReleased(self): if self.TugOfWarControls: pass elif self.state == 'Controlled': self.__endFireWater() def __upArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowHorz = 1 elif self.arrowHorz > 0: self.arrowHorz = 0 def __leftArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupPitcherAdvice() if pressed: self.arrowHorz = -1 elif self.arrowHorz < 0: self.arrowHorz = 0 def __incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendPitcherPos() taskMgr.remove(taskName) taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) def __posHprBroadcast(self, task): self.d_sendPitcherPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) return Task.done def d_sendPitcherPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate('setPitcherPos', [self.changeSeq, self.waterPitcherNode.getH(), timestamp]) def setPitcherPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.pitcherSmoother.setH(h) self.pitcherSmoother.setTimestamp(local) self.pitcherSmoother.markPosition() else: self.waterPitcherNode.setH(h) def __watchControls(self, task): if self.arrowHorz: self.__movePitcher(self.arrowHorz) else: self.__setMoveSound(None) return Task.cont def __movePitcher(self, xd): dt = globalClock.getDt() h = self.waterPitcherNode.getH() - xd * self.rotateSpeed * dt h %= 360 self.notify.debug('rotSpeed=%.2f curH=%.2f xd =%.2f, dt = %.2f, h=%.2f' % (self.rotateSpeed, self.waterPitcherNode.getH(), xd, dt, h)) limitH = h self.waterPitcherNode.setH(limitH) if xd: self.__setMoveSound(self.pitcherMoveSfx) def reloadPosition(self): self.pitcherSmoother.clearPositions(0) self.pitcherSmoother.setHpr(self.waterPitcherNode.getHpr()) self.pitcherSmoother.setPhonyTimestamp() def forceToTruePosition(self): if self.pitcherSmoother.getLatestPosition(): self.pitcherSmoother.applySmoothHpr(self.waterPitcherNode) self.pitcherSmoother.clearPositions(1) def getSprayTrack(self, color, origin, target, dScaleUp, dHold, dScaleDown, horizScale = 1.0, vertScale = 1.0, parent = render): track = Sequence() SPRAY_LEN = 1.5 sprayProp = MovieUtil.globalPropPool.getProp('spray') sprayScale = hidden.attachNewNode('spray-parent') sprayRot = hidden.attachNewNode('spray-rotate') spray = sprayRot spray.setColor(color) if color[3] < 1.0: spray.setTransparency(1) def showSpray(sprayScale, sprayRot, sprayProp, origin, target, parent): if callable(origin): origin = origin() if callable(target): target = target() sprayRot.reparentTo(parent) sprayRot.clearMat() sprayScale.reparentTo(sprayRot) sprayScale.clearMat() sprayProp.reparentTo(sprayScale) sprayProp.clearMat() sprayRot.setPos(origin) sprayRot.lookAt(Point3(target)) track.append(Func(showSpray, sprayScale, sprayRot, sprayProp, origin, target, parent)) def calcTargetScale(target = target, origin = origin, horizScale = horizScale, vertScale = vertScale): if callable(target): target = target() if callable(origin): origin = origin() distance = Vec3(target - origin).length() yScale = distance / SPRAY_LEN targetScale = Point3(yScale * horizScale, yScale, yScale * vertScale) return targetScale track.append(LerpScaleInterval(sprayScale, dScaleUp, calcTargetScale, startScale=Point3(0.01, 0.01, 0.01))) track.append(Func(self.checkHitObject)) track.append(Wait(dHold)) def prepareToShrinkSpray(spray, sprayProp, origin, target): if callable(target): target = target() if callable(origin): origin = origin() sprayProp.setPos(Point3(0.0, -SPRAY_LEN, 0.0)) spray.setPos(target) track.append(Func(prepareToShrinkSpray, spray, sprayProp, origin, target)) track.append(LerpScaleInterval(sprayScale, dScaleDown, Point3(0.01, 0.01, 0.01))) def hideSpray(spray, sprayScale, sprayRot, sprayProp, propPool): sprayProp.detachNode() MovieUtil.removeProp(sprayProp) sprayRot.removeNode() sprayScale.removeNode() track.append(Func(hideSpray, spray, sprayScale, sprayRot, sprayProp, MovieUtil.globalPropPool)) return track def checkHitObject(self): if not self.hitObject: return if self.avId != base.localAvatar.doId: return tag = self.hitObject.getNetTag('pieCode') pieCode = int(tag) if pieCode == ToontownGlobals.PieCodeBossCog: self.hitBossSoundInterval.start() self.sendUpdate('waterHitBoss', [self.index]) if self.TugOfWarControls: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) else: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) def waterHitBoss(self, tableIndex): if self.index == tableIndex: self.hitBossSoundInterval.start() def setupPowerBar(self): self.powerBar = DirectWaitBar(pos=(0.0, 0, -0.94), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.2, 0.2), borderWidth=(0.02, 0.02), scale=0.25, range=1, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(0.75, 0.75, 1.0, 0.8), text='', text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05)) self.power = 0 self.powerBar['value'] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar['value'] = self.power self.powerBar['text'] = '' self.keyTTL = [] def __beginFireWater(self): if self.fireTrack and self.fireTrack.isPlaying(): return if self.aimStart != None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return time = globalClock.getFrameTime() self.aimStart = time messenger.send('wakeup') taskMgr.add(self.__updateWaterPower, self.waterPowerTaskName) return def __endFireWater(self): if self.aimStart == None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return taskMgr.remove(self.waterPowerTaskName) messenger.send('wakeup') self.aimStart = None origin = self.nozzle.getPos(render) target = self.boss.getPos(render) angle = deg2Rad(self.waterPitcherNode.getH() + 90) x = math.cos(angle) y = math.sin(angle) fireVector = Point3(x, y, 0) if self.power < 0.001: self.power = 0.001 self.lastPowerFired = self.power fireVector *= self.fireLength * self.power target = origin + fireVector segment = CollisionSegment(origin[0], origin[1], origin[2], target[0], target[1], target[2]) fromObject = render.attachNewNode(CollisionNode('pitcherColNode')) fromObject.node().addSolid(segment) fromObject.node().setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) fromObject.node().setIntoCollideMask(BitMask32.allOff()) queue = CollisionHandlerQueue() base.cTrav.addCollider(fromObject, queue) base.cTrav.traverse(render) queue.sortEntries() self.hitObject = None if queue.getNumEntries(): entry = queue.getEntry(0) target = entry.getSurfacePoint(render) self.hitObject = entry.getIntoNodePath() base.cTrav.removeCollider(fromObject) fromObject.removeNode() self.d_firingWater(origin, target) self.fireWater(origin, target) self.resetPowerBar() return def __updateWaterPower(self, task): if not self.powerBar: print('### no power bar!!!') return task.done newPower = self.__getWaterPower(globalClock.getFrameTime()) self.power = newPower self.powerBar['value'] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(0.75, 0.75, 1.0, 0.8) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(1.0, 1.0, 0.0, 0.8) else: self.powerBar['barColor'] = VBase4(1.0, 0.0, 0.0, 0.8) return task.cont def __getWaterPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.waterPowerSpeed exponent = self.waterPowerExponent if t > 1: t = t % 1 power = 1 - math.pow(1 - t, exponent) if power > 1.0: power = 1.0 return power def d_firingWater(self, origin, target): self.sendUpdate('firingWater', [origin[0], origin[1], origin[2], target[0], target[1], target[2]]) def firingWater(self, startX, startY, startZ, endX, endY, endZ): origin = Point3(startX, startY, startZ) target = Point3(endX, endY, endZ) self.fireWater(origin, target) def fireWater(self, origin, target): color = VBase4(0.75, 0.75, 1, 0.8) dScaleUp = 0.1 dHold = 0.3 dScaleDown = 0.1 horizScale = 0.1 vertScale = 0.1 sprayTrack = self.getSprayTrack(color, origin, target, dScaleUp, dHold, dScaleDown, horizScale, vertScale) duration = self.squirtSfx.length() if sprayTrack.getDuration() < duration: duration = sprayTrack.getDuration() soundTrack = SoundInterval(self.squirtSfx, node=self.waterPitcherModel, duration=duration) self.fireTrack = Parallel(sprayTrack, soundTrack) self.fireTrack.start() def getPos(self, wrt = render): return self.tableGroup.getPos(wrt) def getLocator(self): return self.tableGroup def enterFlat(self, avId): self.prepareForPhaseFour() self.resetPowerBar() self.notify.debug('enterFlat %d' % self.index) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) toon.setZ(0) self.tableGroup.setScale(1, 1, 0.01) if self.avId and self.avId == localAvatar.doId: localAvatar.b_squish(ToontownGlobals.BossCogDamageLevels[ToontownGlobals.BossCogMoveAttack]) def exitFlat(self): self.tableGroup.setScale(1.0) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: if toon == localAvatar: self.boss.toCraneMode() toon.b_setAnimState('neutral') toon.setAnimState('neutral') toon.loop('leverNeutral') def __allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence(self.tableGroup.colorScaleInterval(0.2, VBase4(1, 1, 1, 1)), Func(self.tableGroup.clearColorScale), Func(self.tableGroup.clearTransparency)) self.fadeTrack.start() self.allowLocalRequestControl = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True) def __upArrowKeyPressed(self): if self.TugOfWarControls: self.__pressHandler(0) def __downArrowKeyPressed(self): if self.TugOfWarControls: self.__pressHandler(1) def __pressHandler(self, index): if index == self.buttons[0]: self.keyTTL.insert(0, 1.0) if not self.OnlyUpArrow: self.buttons.reverse() def __spawnUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) taskMgr.doMethodLater(0.1, self.__updateKeyPressRateTask, self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def __killUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def __updateKeyPressRateTask(self, task): if self.state not in 'Controlled': return Task.done for i in range(len(self.keyTTL)): self.keyTTL[i] -= 0.1 for i in range(len(self.keyTTL)): if self.keyTTL[i] <= 0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break self.keyRate = len(self.keyTTL) keyRateDiff = self.keyRate - self.BASELINE_KEY_RATE diffPower = keyRateDiff / 300.0 if self.power < 1 and diffPower > 0: diffPower = diffPower * math.pow(1 - self.power, 1.25) newPower = self.power + diffPower if newPower > 1: newPower = 1 elif newPower < 0: newPower = 0 self.notify.debug('diffPower=%.2f keyRate = %d, newPower=%.2f' % (diffPower, self.keyRate, newPower)) self.power = newPower self.powerBar['value'] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(0.75, 0.75, 1.0, 0.8) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar['barColor'] = VBase4(1.0, 1.0, 0.0, 0.8) else: self.powerBar['barColor'] = VBase4(1.0, 0.0, 0.0, 0.8) self.__spawnUpdateKeyPressRateTask() return Task.done def __setMoveSound(self, sfx): if sfx != self.moveSound: if self.moveSound: self.moveSound.stop() self.moveSound = sfx if self.moveSound: base.playSfx(self.moveSound, looping=1, volume=0.5)
class DistributedGolfSpot(DistributedObject.DistributedObject, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGolfSpot') positions = ((-45, 100, GolfGlobals.GOLF_BALL_RADIUS), (-15, 100, GolfGlobals.GOLF_BALL_RADIUS), (15, 100, GolfGlobals.GOLF_BALL_RADIUS), (45, 100, GolfGlobals.GOLF_BALL_RADIUS)) toonGolfOffsetPos = Point3(-2, 0, -GolfGlobals.GOLF_BALL_RADIUS) toonGolfOffsetHpr = Point3(-90, 0, 0) rotateSpeed = 20 golfPowerSpeed = base.config.GetDouble('golf-power-speed', 3) golfPowerExponent = base.config.GetDouble('golf-power-exponent', 0.75) def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedGolfSpot') self.boss = None self.index = None self.avId = 0 self.toon = None self.golfSpotSmoother = SmoothMover() self.golfSpotSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 if self.index > len(self.positions): self.notify.error('Invalid index %d' % index) self.fadeTrack = None self.setupPowerBar() self.aimStart = None self.golfSpotAdviceLabel = None self.changeSeq = 0 self.lastChangeSeq = 0 self.controlKeyAllowed = False self.flyBallTracks = {} self.splatTracks = {} self.__flyBallBubble = None self.flyBallHandler = None self.__flyBallSequenceNum = 0 self.swingInterval = None self.lastHitSequenceNum = -1 self.goingToReward = False self.gotHitByBoss = False self.releaseTrack = None self.grabTrack = None self.restoreScaleTrack = None return def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setGolfSpot(self, self.index) def setIndex(self, index): self.index = index def disable(self): DistributedObject.DistributedObject.disable(self) self.ignoreAll() def delete(self): DistributedObject.DistributedObject.delete(self) self.ignoreAll() self.boss = None return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.triggerName = self.uniqueName('trigger') self.triggerEvent = 'enter%s' % self.triggerName self.smoothName = self.uniqueName('golfSpotSmooth') self.golfSpotAdviceName = self.uniqueName('golfSpotAdvice') self.posHprBroadcastName = self.uniqueName('golfSpotBroadcast') self.ballPowerTaskName = self.uniqueName('updateGolfPower') self.adjustClubTaskName = self.uniqueName('adjustClub') self.loadAssets() self.accept('flyBallHit-%d' % self.index, self.__flyBallHit) def loadAssets(self): self.root = render.attachNewNode('golfSpot-%d' % self.index) self.root.setPos(*self.positions[self.index]) self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball') self.ballColor = VBase4(1, 1, 1, 1) if self.index < len(GolfGlobals.PlayerColors): self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index]) self.ballModel.setColorScale(self.ballColor) self.ballModel.reparentTo(self.root) self.club = loader.loadModel('phase_6/models/golf/putter') self.clubLookatSpot = self.root.attachNewNode('clubLookat') self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1)) cs = CollisionSphere(0, 0, 0, 1) cs.setTangible(0) cn = CollisionNode(self.triggerName) cn.addSolid(cs) cn.setIntoCollideMask(ToontownGlobals.WallBitmask) self.trigger = self.root.attachNewNode(cn) self.trigger.stash() self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.ogg') def cleanup(self): if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None flyTracks = self.flyBallTracks.values() for track in flyTracks: track.finish() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None if self.restoreScaleTrack: self.restoreScaleTrack.finish() self.restoreScaleTrack = None self.root.removeNode() self.ballModel.removeNode() self.club.removeNode() if self.powerBar: self.powerBar.destroy() self.powerBar = None taskMgr.remove(self.triggerName) self.boss = None return def setState(self, state, avId, extraInfo): if not self.isDisabled(): self.gotHitByBoss = extraInfo if state == 'C': self.demand('Controlled', avId) elif state == 'F': self.demand('Free') elif state == 'O': self.demand('Off') else: self.notify.error('Invalid state from AI: %s' % state) def enterOff(self): pass def exitOff(self): pass def enterFree(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack = Sequence(Wait(6), self.getRestoreScaleInterval(), name='restoreScaleTrack') self.restoreScaleTrack.start() if self.avId == localAvatar.doId: if not self.isDisabled(): self.ballModel.setAlphaScale(0.3) self.ballModel.setTransparency(1) taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName) self.fadeTrack = Sequence(Func(self.ballModel.setTransparency, 1), self.ballModel.colorScaleInterval( 0.2, VBase4(1, 1, 1, 0.3)), name='fadeTrack-enterFree') self.fadeTrack.start() else: self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) self.avId = 0 return def exitFree(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack.finish() self.restoreScaleTrack = None taskMgr.remove(self.triggerName) self.ballModel.clearTransparency() self.trigger.stash() self.ignore(self.triggerEvent) return def enterControlled(self, avId): self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return self.enableControlKey() self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) if avId == localAvatar.doId: self.boss.toCraneMode() camera.reparentTo(self.root) camera.setPosHpr(0, -10, 3, 0, 0, 0) localAvatar.setPos(self.root, self.toonGolfOffsetPos) localAvatar.setHpr(self.root, self.toonGolfOffsetHpr) localAvatar.sendCurrentPosition() self.__enableControlInterface() self.startPosHprBroadcast() self.accept('exitCrane', self.gotBossZapped) self.grabTrack.start() def exitControlled(self): self.grabTrack.finish() del self.grabTrack if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if not self.ballModel.isEmpty(): if self.ballModel.isHidden(): self.notify.debug('ball is hidden scale =%s' % self.ballModel.getScale()) else: self.notify.debug('ball is showing scale=%s' % self.ballModel.getScale()) if self.toon and not self.toon.isDisabled(): self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: self.__disableControlInterface() if not self.goingToReward: camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.stopAdjustClubTask() self.releaseTrack.start() self.enableControlKey() return def __allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence(self.ballModel.colorScaleInterval( 0.2, self.ballColor), Func(self.ballModel.clearTransparency), name='fadeTrack-allowDetect') self.fadeTrack.start() self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) def __hitTrigger(self, event): self.d_requestControl() def getRestoreScaleInterval(self): return Sequence() def d_requestControl(self): self.sendUpdate('requestControl') def d_requestFree(self, gotHitByBoss): self.sendUpdate('requestFree', [gotHitByBoss]) def makeToonGrabInterval(self, toon): origPos = toon.getPos(self.root) origHpr = toon.getHpr(self.root) a = self.accomodateToon(toon) newPos = toon.getPos() newHpr = toon.getHpr() origHpr.setX(PythonUtil.fitSrcAngle2Dest(origHpr[0], newHpr[0])) self.notify.debug('toon.setPosHpr %s %s' % (origPos, origHpr)) toon.setPosHpr(origPos, origHpr) walkTime = 0.2 reach = Sequence() if reach.getDuration() < walkTime: reach = Sequence( ActorInterval(toon, 'walk', loop=1, duration=walkTime - reach.getDuration()), reach) i = Sequence( Parallel(toon.posInterval(walkTime, newPos, origPos), toon.hprInterval(walkTime, newHpr, origHpr), reach), Func(toon.stopLookAround)) if toon == base.localAvatar: i.append(Func(self.switchToAnimState, 'GolfPuttLoop')) i.append(Func(self.startAdjustClubTask)) i = Parallel(i, a) return i def accomodateToon(self, toon): toon.wrtReparentTo(self.root) toon.setPos(self.toonGolfOffsetPos) toon.setHpr(self.toonGolfOffsetHpr) return Sequence() def switchToAnimState(self, animStateName, forced=False): curAnimState = base.localAvatar.animFSM.getCurrentState() curAnimStateName = '' if curAnimState: curAnimStateName = curAnimState.getName() if curAnimStateName != animStateName or forced: base.localAvatar.b_setAnimState(animStateName) def __enableControlInterface(self): gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=2, text=TTLocalizer.BossbotGolfSpotLeave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.82), command=self.__exitGolfSpot) self.accept('escape', self.__exitGolfSpot) self.accept('control', self.__controlPressed) self.accept('control-up', self.__controlReleased) self.accept('InputState-forward', self.__upArrow) self.accept('InputState-reverse', self.__downArrow) self.accept('InputState-turnLeft', self.__leftArrow) self.accept('InputState-turnRight', self.__rightArrow) taskMgr.add(self.__watchControls, 'watchGolfSpotControls') taskMgr.doMethodLater(5, self.__displayGolfSpotAdvice, self.golfSpotAdviceName) self.arrowVert = 0 self.arrowHorz = 0 if self.powerBar: self.powerBar.show() return def __disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self.__cleanupGolfSpotAdvice() self.ignore('escape') self.ignore('control') self.ignore('control-up') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove('watchGolfSpotControls') if self.powerBar: self.powerBar.hide() else: self.notify.debug('self.powerBar is none') return def setupPowerBar(self): self.powerBar = DirectWaitBar(pos=(0.0, 0, -0.94), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.2, 0.2), borderWidth=(0.02, 0.02), scale=0.25, range=100, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(1.0, 0.0, 0.0, 1.0), text='', text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05)) self.power = 0 self.powerBar['value'] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar['value'] = self.power self.powerBar['text'] = '' def __displayGolfSpotAdvice(self, task): if self.golfSpotAdviceLabel == None: self.golfSpotAdviceLabel = DirectLabel( text=TTLocalizer.BossbotGolfSpotAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1) return def __cleanupGolfSpotAdvice(self): if self.golfSpotAdviceLabel: self.golfSpotAdviceLabel.destroy() self.golfSpotAdviceLabel = None taskMgr.remove(self.golfSpotAdviceName) return def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel( relief=None, text=TTLocalizer.BossbotGolfSpotLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1)) self.__cleanupGolfSpotAdvice() return def __exitGolfSpot(self): self.d_requestFree(False) def __controlPressed(self): if self.controlKeyAllowed: self.__beginFireBall() def __controlReleased(self): if self.controlKeyAllowed: self.__endFireBall() def __upArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = 1 self.switchToAnimState('GolfRotateLeft') elif self.arrowHorz > 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __leftArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = -1 self.switchToAnimState('GolfRotateRight') elif self.arrowHorz < 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __watchControls(self, task): if self.arrowHorz: self.__moveGolfSpot(self.arrowHorz) return Task.cont def __moveGolfSpot(self, xd): dt = globalClock.getDt() h = self.root.getH() - xd * self.rotateSpeed * dt h %= 360 limitH = h self.root.setH(limitH) def __incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def __beginFireBall(self): if self.aimStart != None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return time = globalClock.getFrameTime() self.aimStart = time messenger.send('wakeup') taskMgr.add(self.__updateBallPower, self.ballPowerTaskName) return def __endFireBall(self): if self.aimStart == None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return taskMgr.remove(self.ballPowerTaskName) self.disableControlKey() messenger.send('wakeup') self.aimStart = None power = self.power angle = self.root.getH() self.notify.debug('incrementing self.__flyBallSequenceNum') self.__flyBallSequenceNum = (self.__flyBallSequenceNum + 1) % 255 self.sendSwingInfo(power, angle, self.__flyBallSequenceNum) self.setSwingInfo(power, angle, self.__flyBallSequenceNum) self.resetPowerBar() return def __updateBallPower(self, task): if not self.powerBar: print '### no power bar!!!' return task.done newPower = self.__getBallPower(globalClock.getFrameTime()) self.power = newPower self.powerBar['value'] = newPower return task.cont def __getBallPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.golfPowerSpeed t = math.pow(t, self.golfPowerExponent) power = int(t * 100) % 200 if power > 100: power = 200 - power return power def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendGolfSpotPos() taskMgr.remove(taskName) taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) def __posHprBroadcast(self, task): self.d_sendGolfSpotPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) return Task.done def d_sendGolfSpotPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate( 'setGolfSpotPos', [self.changeSeq, self.root.getH(), timestamp]) def setGolfSpotPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.golfSpotSmoother.setH(h) self.golfSpotSmoother.setTimestamp(local) self.golfSpotSmoother.markPosition() else: self.root.setH(h) def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate('clearSmoothing', [0]) def clearSmoothing(self, bogus=None): self.golfSpotSmoother.clearPositions(1) def doSmoothTask(self, task): self.golfSpotSmoother.computeAndApplySmoothHpr(self.root) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def makeToonReleaseInterval(self, toon): def getSlideToPos(toon=toon): return render.getRelativePoint(toon, Point3(0, -5, 0)) if self.gotHitByBoss: grabIval = Sequence(Func(self.detachClub), name='makeToonReleaseInterval-gotHitByBoss') if not toon.isEmpty(): toonIval = Sequence(Func(toon.wrtReparentTo, render), Parallel( ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1)), name='makeToonReleaseInterval-toonIval') grabIval.append(toonIval) else: grabIval = Sequence(Func(self.detachClub)) if not toon.isEmpty(): toonIval = Sequence( Parallel( ActorInterval(toon, 'walk', duration=1.0, playRate=-1.0), LerpPosInterval(toon, duration=1.0, pos=Point3(-10, 0, 0))), Func(toon.wrtReparentTo, render)) grabIval.append(toonIval) if localAvatar.doId == toon.doId: if not self.goingToReward and toon.hp > 0: grabIval.append(Func(self.goToFinalBattle)) grabIval.append( Func(self.notify.debug, 'goingToFinalBattlemode')) grabIval.append(Func(self.safeBossToFinalBattleMode)) return grabIval def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, 'fsm'): curState = place.fsm.getCurrentState().getName() if place.fsm.getCurrentState().getName() == 'crane': place.setState('finalBattle') else: self.notify.debug('NOT going to final battle, state=%s' % curState) def attachClub(self, avId, pointToBall=False): club = self.club if club: av = base.cr.doId2do.get(avId) if av: av.useLOD(1000) lHand = av.getLeftHands()[0] club.setPos(0, 0, 0) club.reparentTo(lHand) netScale = club.getNetTransform().getScale()[1] counterActToonScale = lHand.find('**/counteractToonScale') if counterActToonScale.isEmpty(): counterActToonScale = lHand.attachNewNode( 'counteractToonScale') counterActToonScale.setScale(1 / netScale) self.notify.debug('creating counterActToonScale for %s' % av.getName()) club.reparentTo(counterActToonScale) club.setX(-0.25 * netScale) if pointToBall: club.lookAt(self.clubLookatSpot) def detachClub(self): if not self.club.isEmpty(): self.club.reparentTo(self.root) self.club.setZ(-20) self.club.setScale(1) def adjustClub(self): club = self.club if club: distance = club.getDistance(self.clubLookatSpot) scaleFactor = distance / 2.058 club.setScale(1, scaleFactor, 1) def startAdjustClubTask(self): taskMgr.add(self.adjustClubTask, self.adjustClubTaskName) def stopAdjustClubTask(self): taskMgr.remove(self.adjustClubTaskName) def adjustClubTask(self, task): self.attachClub(self.avId, True) self.adjustClub() return task.cont def enableControlKey(self): self.controlKeyAllowed = True def disableControlKey(self): self.controlKeyAllowed = False def sendSwingInfo(self, power, angle, sequenceNum): self.sendUpdate('setSwingInfo', [power, angle, sequenceNum]) def startBallPlayback(self, power, angle, sequenceNum): flyBall = self.ballModel.copyTo(NodePath()) flyBall.setScale(1.0) flyBallBubble = self.getFlyBallBubble().instanceTo(NodePath()) flyBallBubble.reparentTo(flyBall) flyBall.setTag('pieSequence', str(sequenceNum)) flyBall.setTag('throwerId', str(self.avId)) t = power / 100.0 t = 1.0 - t dist = 300 - 200 * t time = 1.5 + 0.5 * t proj = ProjectileInterval(None, startPos=Point3(0, 0, 0), endPos=Point3(0, dist, 0), duration=time) relVel = proj.startVel def getVelocity(root=self.root, relVel=relVel): return render.getRelativeVector(root, relVel) fly = Sequence( Func(flyBall.reparentTo, render), Func(flyBall.setPosHpr, self.root, 0, 0, 0, 0, 0, 0), Func(base.cTrav.addCollider, flyBallBubble, self.flyBallHandler), ProjectileInterval(flyBall, startVel=getVelocity, duration=3), Func(flyBall.detachNode), Func(base.cTrav.removeCollider, flyBallBubble), Func(self.notify.debug, 'removed collider'), Func(self.flyBallFinishedFlying, sequenceNum)) flyWithSound = Parallel(fly, SoundInterval(self.hitBallSfx, node=self.root), name='flyWithSound') self.notify.debug('starting flyball track') flyWithSound.start() self.flyBallTracks[sequenceNum] = flyWithSound return def setSwingInfo(self, power, angle, sequenceNum): av = base.cr.doId2do.get(self.avId) self.swingInterval = Sequence() if av: self.stopAdjustClubTask() self.swingInterval = Sequence( ActorInterval(av, 'swing-putt', startFrame=0, endFrame=GolfGlobals.BALL_CONTACT_FRAME), Func(self.startBallPlayback, power, angle, sequenceNum), Func(self.ballModel.hide), ActorInterval(av, 'swing-putt', startFrame=GolfGlobals.BALL_CONTACT_FRAME, endFrame=24), Func(self.ballModel.setScale, 0.1), Func(self.ballModel.show), LerpScaleInterval(self.ballModel, 1.0, Point3(1, 1, 1)), Func(self.enableControlKey)) if av == localAvatar: self.swingInterval.append( Func(self.switchToAnimState, 'GolfPuttLoop', True)) self.swingInterval.start() def getFlyBallBubble(self): if self.__flyBallBubble == None: bubble = CollisionSphere(0, 0, 0, GolfGlobals.GOLF_BALL_RADIUS) node = CollisionNode('flyBallBubble') node.addSolid(bubble) node.setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) node.setIntoCollideMask(BitMask32.allOff()) self.__flyBallBubble = NodePath(node) self.flyBallHandler = CollisionHandlerEvent() self.flyBallHandler.addInPattern('flyBallHit-%d' % self.index) return self.__flyBallBubble def __flyBallHit(self, entry): print entry def flyBallFinishedFlying(self, sequence): if self.flyBallTracks.has_key(sequence): del self.flyBallTracks[sequence] def __finishFlyBallTrack(self, sequence): if self.flyBallTracks.has_key(sequence): flyBallTrack = self.flyBallTracks[sequence] del self.flyBallTracks[sequence] flyBallTrack.finish() def flyBallFinishedSplatting(self, sequence): if self.splatTracks.has_key(sequence): del self.splatTracks[sequence] def __flyBallHit(self, entry): if not entry.hasSurfacePoint() or not entry.hasInto(): return if not entry.getInto().isTangible(): return sequence = int(entry.getFromNodePath().getNetTag('pieSequence')) self.__finishFlyBallTrack(sequence) if self.splatTracks.has_key(sequence): splatTrack = self.splatTracks[sequence] del self.splatTracks[sequence] splatTrack.finish() flyBallCode = 0 flyBallCodeStr = entry.getIntoNodePath().getNetTag('pieCode') if flyBallCodeStr: flyBallCode = int(flyBallCodeStr) pos = entry.getSurfacePoint(render) timestamp32 = globalClockDelta.getFrameNetworkTime(bits=32) throwerId = int(entry.getFromNodePath().getNetTag('throwerId')) splat = self.getFlyBallSplatInterval(pos[0], pos[1], pos[2], flyBallCode, throwerId) splat = Sequence(splat, Func(self.flyBallFinishedSplatting, sequence)) self.splatTracks[sequence] = splat splat.start() self.notify.debug( 'doId=%d into=%s flyBallCode=%d, throwerId=%d' % (self.doId, entry.getIntoNodePath(), flyBallCode, throwerId)) if flyBallCode == ToontownGlobals.PieCodeBossCog and self.avId == localAvatar.doId and self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum self.boss.d_ballHitBoss(10) elif flyBallCode == ToontownGlobals.PieCodeToon and self.avId == localAvatar.doId and self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum 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: pass def getFlyBallSplatInterval(self, x, y, z, flyBallCode, throwerId): from toontown.toonbase import ToontownBattleGlobals from toontown.battle import BattleProps splatName = 'dust' splat = BattleProps.globalPropPool.getProp(splatName) splat.setBillboardPointWorld(2) color = ToontownGlobals.PieCodeColors.get(flyBallCode) if color: splat.setColor(*color) if flyBallCode == ToontownGlobals.PieCodeBossCog: self.notify.debug('changing color to %s' % self.ballColor) splat.setColor(self.ballColor) sound = loader.loadSfx('phase_11/audio/sfx/LB_evidence_miss.ogg') vol = 1.0 if flyBallCode == ToontownGlobals.PieCodeBossCog: sound = loader.loadSfx('phase_4/audio/sfx/Golf_Hit_Barrier_1.ogg') soundIval = SoundInterval(sound, node=splat, volume=vol) if flyBallCode == ToontownGlobals.PieCodeBossCog and localAvatar.doId == throwerId: vol = 1.0 soundIval = SoundInterval(sound, node=localAvatar, volume=vol) ival = Parallel( Func(splat.reparentTo, render), Func(splat.setPos, x, y, z), soundIval, Sequence(ActorInterval(splat, splatName), Func(splat.detachNode))) return ival def setGoingToReward(self): self.goingToReward = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True)
class DistributedBanquetTable(DistributedObject.DistributedObject, FSM.FSM, BanquetTableBase.BanquetTableBase): notify = DirectNotifyGlobal.directNotify.newCategory("DistributedBanquetTable") rotationsPerSeatIndex = [90, 90, 0, 0, -90, -90, 180, 180] pitcherMinH = -360 pitcherMaxH = 360 rotateSpeed = 30 waterPowerSpeed = base.config.GetDouble("water-power-speed", 15) waterPowerExponent = base.config.GetDouble("water-power-exponent", 0.75) useNewAnimations = True TugOfWarControls = False OnlyUpArrow = True if OnlyUpArrow: BASELINE_KEY_RATE = 3 else: BASELINE_KEY_RATE = 6 UPDATE_KEY_PRESS_RATE_TASK = "BanquetTableUpdateKeyPressRateTask" YELLOW_POWER_THRESHOLD = 0.75 RED_POWER_THRESHOLD = 0.96999999999999997 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, "DistributedBanquetTable") self.boss = None self.index = -1 self.diners = {} self.dinerStatus = {} self.serviceLocs = {} self.chairLocators = {} self.sitLocators = {} self.activeIntervals = {} self.dinerStatusIndicators = {} self.preparedForPhaseFour = False self.avId = 0 self.toon = None self.pitcherSmoother = SmoothMover() self.pitcherSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self._DistributedBanquetTable__broadcastPeriod = 0.20000000000000001 self.changeSeq = 0 self.lastChangeSeq = 0 self.pitcherAdviceLabel = None self.fireLength = 250 self.fireTrack = None self.hitObject = None self.setupPowerBar() self.aimStart = None self.toonPitcherPosition = Point3(0, -2, 0) self.allowLocalRequestControl = True self.fadeTrack = None self.grabTrack = None self.gotHitByBoss = False self.keyTTL = [] self.keyRate = 0 self.buttons = [0, 1] self.lastPowerFired = 0 self.moveSound = None self.releaseTrack = None def disable(self): DistributedObject.DistributedObject.disable(self) taskMgr.remove(self.triggerName) taskMgr.remove(self.smoothName) taskMgr.remove(self.watchControlsName) taskMgr.remove(self.pitcherAdviceName) taskMgr.remove(self.posHprBroadcastName) taskMgr.remove(self.waterPowerTaskName) if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None if self.fireTrack: self.fireTrack.finish() self.fireTrack = None self.cleanupIntervals() def delete(self): DistributedObject.DistributedObject.delete(self) self.boss = None self.ignoreAll() for indicator in self.dinerStatusIndicators.values(): indicator.delete() self.dinerStatusIndicators = {} for diner in self.diners.values(): diner.delete() self.diners = {} self.powerBar.destroy() self.powerBar = None self.pitcherMoveSfx.stop() def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.loadAssets() self.smoothName = self.uniqueName("pitcherSmooth") self.pitcherAdviceName = self.uniqueName("pitcherAdvice") self.posHprBroadcastName = self.uniqueName("pitcherBroadcast") self.waterPowerTaskName = self.uniqueName("updateWaterPower") self.triggerName = self.uniqueName("trigger") self.watchControlsName = self.uniqueName("watchControls") def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setTable(self, self.index) def setIndex(self, index): self.index = index def setState(self, state, avId, extraInfo): self.gotHitByBoss = extraInfo if state == "F": self.demand("Off") elif state == "N": self.demand("On") elif state == "I": self.demand("Inactive") elif state == "R": self.demand("Free") elif state == "C": self.demand("Controlled", avId) elif state == "L": self.demand("Flat", avId) else: self.notify.error("Invalid state from AI: %s" % state) def setNumDiners(self, numDiners): self.numDiners = numDiners def setDinerInfo(self, hungryDurations, eatingDurations, dinerLevels): self.dinerInfo = {} for i in xrange(len(hungryDurations)): hungryDur = hungryDurations[i] eatingDur = eatingDurations[i] dinerLevel = dinerLevels[i] self.dinerInfo[i] = (hungryDur, eatingDur, dinerLevel) def loadAssets(self): self.tableGroup = loader.loadModel("phase_12/models/bossbotHQ/BanquetTableChairs") tableLocator = self.boss.geom.find("**/TableLocator_%d" % (self.index + 1)) if tableLocator.isEmpty(): self.tableGroup.reparentTo(render) self.tableGroup.setPos(0, 75, 0) else: self.tableGroup.reparentTo(tableLocator) self.tableGeom = self.tableGroup.find("**/Geometry") self.setupDiners() self.setupChairCols() self.squirtSfx = loader.loadSfx("phase_4/audio/sfx/AA_squirt_seltzer_miss.mp3") self.hitBossSfx = loader.loadSfx("phase_5/audio/sfx/SA_watercooler_spray_only.mp3") self.hitBossSoundInterval = SoundInterval(self.hitBossSfx, node=self.boss, volume=1.0) self.serveFoodSfx = loader.loadSfx("phase_4/audio/sfx/MG_sfx_travel_game_bell_for_trolley.mp3") self.pitcherMoveSfx = base.loadSfx("phase_4/audio/sfx/MG_cannon_adjust.mp3") def setupDiners(self): for i in xrange(self.numDiners): newDiner = self.createDiner(i) self.diners[i] = newDiner self.dinerStatus[i] = self.HUNGRY def createDiner(self, i): diner = Suit.Suit() diner.dna = SuitDNA.SuitDNA() level = self.dinerInfo[i][2] level -= 4 diner.dna.newSuitRandom(level=level, dept="c") diner.setDNA(diner.dna) if self.useNewAnimations: diner.loop("sit", fromFrame=i) else: diner.pose("landing", 0) locator = self.tableGroup.find("**/chair_%d" % (i + 1)) locatorScale = locator.getNetTransform().getScale()[0] correctHeadingNp = locator.attachNewNode("correctHeading") self.chairLocators[i] = correctHeadingNp heading = self.rotationsPerSeatIndex[i] correctHeadingNp.setH(heading) sitLocator = correctHeadingNp.attachNewNode("sitLocator") base.sitLocator = sitLocator pos = correctHeadingNp.getPos(render) if SuitDNA.getSuitBodyType(diner.dna.name) == "c": sitLocator.setPos(0.5, 3.6499999999999999, -3.75) else: sitLocator.setZ(-2.3999999999999999) sitLocator.setY(2.5) sitLocator.setX(0.5) self.sitLocators[i] = sitLocator diner.setScale(1.0 / locatorScale) diner.reparentTo(sitLocator) newLoc = NodePath("serviceLoc-%d-%d" % (self.index, i)) newLoc.reparentTo(correctHeadingNp) newLoc.setPos(0, 3.0, 1) self.serviceLocs[i] = newLoc base.serviceLoc = newLoc head = diner.find("**/joint_head") newIndicator = DinerStatusIndicator.DinerStatusIndicator(parent=head, pos=Point3(0, 0, 3.5), scale=5.0) newIndicator.wrtReparentTo(diner) self.dinerStatusIndicators[i] = newIndicator return diner def setupChairCols(self): for i in xrange(self.numDiners): chairCol = self.tableGroup.find("**/collision_chair_%d" % (i + 1)) colName = "ChairCol-%d-%d" % (self.index, i) chairCol.setTag("chairIndex", str(i)) chairCol.setName(colName) chairCol.setCollideMask(ToontownGlobals.WallBitmask) self.accept("enter" + colName, self.touchedChair) def touchedChair(self, colEntry): chairIndex = int(colEntry.getIntoNodePath().getTag("chairIndex")) if chairIndex in self.dinerStatus: status = self.dinerStatus[chairIndex] if status in (self.HUNGRY, self.ANGRY): self.boss.localToonTouchedChair(self.index, chairIndex) def serveFood(self, food, chairIndex): self.removeFoodModel(chairIndex) serviceLoc = self.serviceLocs.get(chairIndex) if not food or food.isEmpty(): foodModel = loader.loadModel("phase_12/models/bossbotHQ/canoffood") foodModel.setScale(ToontownGlobals.BossbotFoodModelScale) foodModel.reparentTo(serviceLoc) else: food.wrtReparentTo(serviceLoc) tray = food.find("**/tray") if not tray.isEmpty(): tray.hide() ivalDuration = 1.5 foodMoveIval = Parallel( SoundInterval(self.serveFoodSfx, node=food), ProjectileInterval( food, duration=ivalDuration, startPos=food.getPos(serviceLoc), endPos=serviceLoc.getPos(serviceLoc) ), LerpHprInterval(food, ivalDuration, Point3(0, -360, 0)), ) intervalName = "serveFood-%d-%d" % (self.index, chairIndex) foodMoveIval.start() self.activeIntervals[intervalName] = foodMoveIval def setDinerStatus(self, chairIndex, status): if chairIndex in self.dinerStatus: oldStatus = self.dinerStatus[chairIndex] self.dinerStatus[chairIndex] = status if oldStatus != status: if status == self.EATING: self.changeDinerToEating(chairIndex) elif status == self.HUNGRY: self.changeDinerToHungry(chairIndex) elif status == self.ANGRY: self.changeDinerToAngry(chairIndex) elif status == self.DEAD: self.changeDinerToDead(chairIndex) elif status == self.HIDDEN: self.changeDinerToHidden(chairIndex) def removeFoodModel(self, chairIndex): serviceLoc = self.serviceLocs.get(chairIndex) if serviceLoc: for i in xrange(serviceLoc.getNumChildren()): serviceLoc.getChild(0).removeNode() def changeDinerToEating(self, chairIndex): indicator = self.dinerStatusIndicators.get(chairIndex) eatingDuration = self.dinerInfo[chairIndex][1] if indicator: indicator.request("Eating", eatingDuration) diner = self.diners[chairIndex] intervalName = "eating-%d-%d" % (self.index, chairIndex) eatInTime = 32.0 / 24.0 eatOutTime = 21.0 / 24.0 eatLoopTime = 19 / 24.0 rightHand = diner.getRightHand() waitTime = 5 loopDuration = eatingDuration - eatInTime - eatOutTime - waitTime serviceLoc = self.serviceLocs[chairIndex] def foodAttach(self=self, diner=diner): foodModel = self.serviceLocs[chairIndex].getChild(0) (foodModel.reparentTo(diner.getRightHand()),) (foodModel.setHpr(Point3(0, -94, 0)),) (foodModel.setPos(Point3(-0.14999999999999999, -0.69999999999999996, -0.40000000000000002)),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == "c": scaleAdj = 0.59999999999999998 (foodModel.setPos(Point3(0.10000000000000001, -0.25, -0.31)),) else: scaleAdj = 0.80000000000000004 (foodModel.setPos(Point3(-0.25, -0.84999999999999998, -0.34000000000000002)),) oldScale = foodModel.getScale() newScale = oldScale * scaleAdj foodModel.setScale(newScale) def foodDetach(self=self, diner=diner): foodModel = diner.getRightHand().getChild(0) (foodModel.reparentTo(serviceLoc),) (foodModel.setPosHpr(0, 0, 0, 0, 0, 0),) scaleAdj = 1 if SuitDNA.getSuitBodyType(diner.dna.name) == "c": scaleAdj = 0.59999999999999998 else: scakeAdj = 0.80000000000000004 oldScale = foodModel.getScale() newScale = oldScale / scaleAdj foodModel.setScale(newScale) eatIval = Sequence( ActorInterval(diner, "sit", duration=waitTime), ActorInterval(diner, "sit-eat-in", startFrame=0, endFrame=6), Func(foodAttach), ActorInterval(diner, "sit-eat-in", startFrame=6, endFrame=32), ActorInterval(diner, "sit-eat-loop", duration=loopDuration, loop=1), ActorInterval(diner, "sit-eat-out", startFrame=0, endFrame=12), Func(foodDetach), ActorInterval(diner, "sit-eat-out", startFrame=12, endFrame=21), ) eatIval.start() self.activeIntervals[intervalName] = eatIval def changeDinerToHungry(self, chairIndex): intervalName = "eating-%d-%d" % (self.index, chairIndex) if intervalName in self.activeIntervals: self.activeIntervals[intervalName].finish() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Hungry", self.dinerInfo[chairIndex][0]) diner = self.diners[chairIndex] if random.choice([0, 1]): diner.loop("sit-hungry-left") else: diner.loop("sit-hungry-right") def changeDinerToAngry(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Angry") diner = self.diners[chairIndex] diner.loop("sit-angry") def changeDinerToDead(self, chairIndex): def removeDeathSuit(suit, deathSuit): if not deathSuit.isEmpty(): deathSuit.detachNode() suit.cleanupLoseActor() self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Dead") diner = self.diners[chairIndex] deathSuit = diner locator = self.tableGroup.find("**/chair_%d" % (chairIndex + 1)) deathSuit = diner.getLoseActor() ival = Sequence( Func(self.notify.debug, "before actorinterval sit-lose"), ActorInterval(diner, "sit-lose"), Func(self.notify.debug, "before deathSuit.setHpr"), Func(deathSuit.setHpr, diner.getHpr()), Func(self.notify.debug, "before diner.hide"), Func(diner.hide), Func(self.notify.debug, "before deathSuit.reparentTo"), Func(deathSuit.reparentTo, self.chairLocators[chairIndex]), Func(self.notify.debug, "befor ActorInterval lose"), ActorInterval(deathSuit, "lose", duration=MovieUtil.SUIT_LOSE_DURATION), Func(self.notify.debug, "before remove deathsuit"), Func(removeDeathSuit, diner, deathSuit, name="remove-death-suit-%d-%d" % (chairIndex, self.index)), Func(self.notify.debug, "diner.stash"), Func(diner.stash), ) spinningSound = base.loadSfx("phase_3.5/audio/sfx/Cog_Death.mp3") deathSound = base.loadSfx("phase_3.5/audio/sfx/ENC_cogfall_apart.mp3") deathSoundTrack = Sequence( Wait(0.80000000000000004), SoundInterval(spinningSound, duration=1.2, startTime=1.5, volume=0.20000000000000001, node=deathSuit), SoundInterval( spinningSound, duration=3.0, startTime=0.59999999999999998, volume=0.80000000000000004, node=deathSuit ), SoundInterval(deathSound, volume=0.32000000000000001, node=deathSuit), ) intervalName = "dinerDie-%d-%d" % (self.index, chairIndex) deathIval = Parallel(ival, deathSoundTrack) deathIval.start() self.activeIntervals[intervalName] = deathIval def changeDinerToHidden(self, chairIndex): self.removeFoodModel(chairIndex) indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Inactive") diner = self.diners[chairIndex] diner.hide() def setAllDinersToSitNeutral(self): startFrame = 0 for diner in self.diners.values(): if not diner.isHidden(): diner.loop("sit", fromFrame=startFrame) startFrame += 1 continue def cleanupIntervals(self): for interval in self.activeIntervals.values(): interval.finish() self.activeIntervals = {} def clearInterval(self, name, finish=1): if self.activeIntervals.has_key(name): ival = self.activeIntervals[name] if finish: ival.finish() else: ival.pause() if self.activeIntervals.has_key(name): del self.activeIntervals[name] else: self.notify.debug("interval: %s already cleared" % name) def finishInterval(self, name): if self.activeIntervals.has_key(name): interval = self.activeIntervals[name] interval.finish() def getNotDeadInfo(self): notDeadList = [] for i in xrange(self.numDiners): if self.dinerStatus[i] != self.DEAD: notDeadList.append((self.index, i, 12)) continue return notDeadList def enterOn(self): pass def exitOn(self): pass def enterInactive(self): for chairIndex in xrange(self.numDiners): indicator = self.dinerStatusIndicators.get(chairIndex) if indicator: indicator.request("Inactive") self.removeFoodModel(chairIndex) def exitInactive(self): pass def enterFree(self): self.resetPowerBar() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.prepareForPhaseFour() if self.avId == localAvatar.doId: self.tableGroup.setAlphaScale(0.29999999999999999) self.tableGroup.setTransparency(1) taskMgr.doMethodLater(5, self._DistributedBanquetTable__allowDetect, self.triggerName) self.fadeTrack = Sequence( Func(self.tableGroup.setTransparency, 1), self.tableGroup.colorScaleInterval(0.20000000000000001, VBase4(1, 1, 1, 0.29999999999999999)), ) self.fadeTrack.start() self.allowLocalRequestControl = False else: self.allowLocalRequestControl = True self.avId = 0 def exitFree(self): pass def touchedTable(self, colEntry): tableIndex = int(colEntry.getIntoNodePath().getTag("tableIndex")) if self.state == "Free" and self.avId == 0 and self.allowLocalRequestControl: self.d_requestControl() def prepareForPhaseFour(self): if not self.preparedForPhaseFour: for i in xrange(8): chair = self.tableGroup.find("**/chair_%d" % (i + 1)) if not chair.isEmpty(): chair.hide() colChairs = self.tableGroup.findAllMatches("**/ChairCol*") for i in xrange(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() colChairs = self.tableGroup.findAllMatches("**/collision_chair*") for i in xrange(colChairs.getNumPaths()): col = colChairs.getPath(i) col.stash() tableCol = self.tableGroup.find("**/collision_table") colName = "TableCol-%d" % self.index tableCol.setTag("tableIndex", str(self.index)) tableCol.setName(colName) tableCol.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.BanquetTableBitmask) self.accept("enter" + colName, self.touchedTable) self.preparedForPhaseFour = True self.waterPitcherModel = loader.loadModel("phase_12/models/bossbotHQ/tt_m_ara_bhq_seltzerBottle") lampNode = self.tableGroup.find("**/lamp_med_5") pos = lampNode.getPos(self.tableGroup) lampNode.hide() bottleLocator = self.tableGroup.find("**/bottle_locator") pos = bottleLocator.getPos(self.tableGroup) self.waterPitcherNode = self.tableGroup.attachNewNode("pitcherNode") self.waterPitcherNode.setPos(pos) self.waterPitcherModel.reparentTo(self.waterPitcherNode) self.waterPitcherModel.ls() self.nozzle = self.waterPitcherModel.find("**/nozzle_tip") self.handLocator = self.waterPitcherModel.find("**/hand_locator") self.handPos = self.handLocator.getPos() def d_requestControl(self): self.sendUpdate("requestControl") def d_requestFree(self, gotHitByBoss): self.sendUpdate("requestFree", [gotHitByBoss]) def enterControlled(self, avId): self.prepareForPhaseFour() self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return None self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) self.notify.debug("grabTrack=%s" % self.grabTrack) self.pitcherCamPos = Point3(0, -50, 40) self.pitcherCamHpr = Point3(0, -21, 0) if avId == localAvatar.doId: self.boss.toMovieMode() self._DistributedBanquetTable__enableControlInterface() self.startPosHprBroadcast() self.grabTrack = Sequence( self.grabTrack, Func(camera.wrtReparentTo, localAvatar), LerpPosHprInterval(camera, 1, self.pitcherCamPos, self.pitcherCamHpr), Func(self.boss.toCraneMode), ) if self.TugOfWarControls: self._DistributedBanquetTable__spawnUpdateKeyPressRateTask() self.accept("exitCrane", self.gotBossZapped) else: self.startSmooth() toon.stopSmooth() self.grabTrack.start() def exitControlled(self): self.ignore("exitCrane") if self.grabTrack: self.grabTrack.finish() self.grabTrack = None nextState = self.getCurrentOrNextState() self.notify.debug("nextState=%s" % nextState) if nextState == "Flat": place = base.cr.playGame.getPlace() self.notify.debug("%s" % place.fsm) if self.avId == localAvatar.doId: self._DistributedBanquetTable__disableControlInterface() elif self.toon and not self.toon.isDisabled(): self.toon.loop("neutral") self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: localAvatar.wrtReparentTo(render) self._DistributedBanquetTable__disableControlInterface() camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.goToFinalBattle() self.safeBossToFinalBattleMode() else: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) self.releaseTrack.start() def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, "fsm"): if place.fsm.getCurrentState().getName() == "crane": place.setState("finalBattle") def makeToonGrabInterval(self, toon): toon.pose("leverNeutral", 0) toon.update() rightHandPos = toon.rightHand.getPos(toon) self.toonPitcherPosition = Point3(self.handPos[0] - rightHandPos[0], self.handPos[1] - rightHandPos[1], 0) destZScale = rightHandPos[2] / self.handPos[2] grabIval = Sequence( Func(toon.wrtReparentTo, self.waterPitcherNode), Func(toon.loop, "neutral"), Parallel( ActorInterval(toon, "jump"), Sequence( Wait(0.42999999999999999), Parallel( ProjectileInterval( toon, duration=0.90000000000000002, startPos=toon.getPos(self.waterPitcherNode), endPos=self.toonPitcherPosition, ), LerpHprInterval(toon, 0.90000000000000002, Point3(0, 0, 0)), LerpScaleInterval(self.waterPitcherModel, 0.90000000000000002, Point3(1, 1, destZScale)), ), ), ), Func(toon.setPos, self.toonPitcherPosition), Func(toon.loop, "leverNeutral"), ) return grabIval def makeToonReleaseInterval(self, toon): temp1 = self.waterPitcherNode.attachNewNode("temp1") temp1.setPos(self.toonPitcherPosition) temp2 = self.waterPitcherNode.attachNewNode("temp2") temp2.setPos(0, -10, -self.waterPitcherNode.getZ()) startPos = temp1.getPos(render) endPos = temp2.getPos(render) temp1.removeNode() temp2.removeNode() def getSlideToPos(toon=toon): return render.getRelativePoint(toon, Point3(0, -10, 0)) if self.gotHitByBoss: self.notify.debug("creating zap interval instead") grabIval = Sequence( Func(toon.loop, "neutral"), Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, "slip-backward"), toon.posInterval(0.5, getSlideToPos, fluid=1)), ) else: grabIval = Sequence( Func(toon.loop, "neutral"), Func(toon.wrtReparentTo, render), Parallel( ActorInterval(toon, "jump"), Sequence( Wait(0.42999999999999999), ProjectileInterval(toon, duration=0.90000000000000002, startPos=startPos, endPos=endPos), ), ), ) return grabIval def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate("clearSmoothing", [0]) def clearSmoothing(self, bogus=None): self.pitcherSmoother.clearPositions(1) def doSmoothTask(self, task): self.pitcherSmoother.computeAndApplySmoothHpr(self.waterPitcherNode) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def _DistributedBanquetTable__enableControlInterface(self): gui = loader.loadModel("phase_3.5/models/gui/avatar_panel_gui") self.closeButton = DirectButton( image=( gui.find("**/CloseBtn_UP"), gui.find("**/CloseBtn_DN"), gui.find("**/CloseBtn_Rllvr"), gui.find("**/CloseBtn_UP"), ), relief=None, scale=2, text=TTLocalizer.BossbotPitcherLeave, text_scale=0.040000000000000001, text_pos=(0, -0.070000000000000007), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.81999999999999995), command=self._DistributedBanquetTable__exitPitcher, ) self.accept("escape", self._DistributedBanquetTable__exitPitcher) self.accept("control", self._DistributedBanquetTable__controlPressed) self.accept("control-up", self._DistributedBanquetTable__controlReleased) self.accept("InputState-forward", self._DistributedBanquetTable__upArrow) self.accept("InputState-reverse", self._DistributedBanquetTable__downArrow) self.accept("InputState-turnLeft", self._DistributedBanquetTable__leftArrow) self.accept("InputState-turnRight", self._DistributedBanquetTable__rightArrow) self.accept("arrow_up", self._DistributedBanquetTable__upArrowKeyPressed) self.accept("arrow_down", self._DistributedBanquetTable__downArrowKeyPressed) taskMgr.add(self._DistributedBanquetTable__watchControls, self.watchControlsName) taskMgr.doMethodLater(5, self._DistributedBanquetTable__displayPitcherAdvice, self.pitcherAdviceName) self.arrowVert = 0 self.arrowHorz = 0 self.powerBar.show() def _DistributedBanquetTable__disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self._DistributedBanquetTable__cleanupPitcherAdvice() self.ignore("escape") self.ignore("control") self.ignore("control-up") self.ignore("InputState-forward") self.ignore("InputState-reverse") self.ignore("InputState-turnLeft") self.ignore("InputState-turnRight") self.ignore("arrow_up") self.ignore("arrow_down") self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove(self.watchControlsName) taskMgr.remove(self.waterPowerTaskName) self.resetPowerBar() self.aimStart = None self.powerBar.hide() if self.TugOfWarControls: self._DistributedBanquetTable__killUpdateKeyPressRateTask() self.keyTTL = [] self._DistributedBanquetTable__setMoveSound(None) def _DistributedBanquetTable__displayPitcherAdvice(self, task): if self.pitcherAdviceLabel == None: self.pitcherAdviceLabel = DirectLabel( text=TTLocalizer.BossbotPitcherAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.68999999999999995), scale=0.10000000000000001, ) def _DistributedBanquetTable__cleanupPitcherAdvice(self): if self.pitcherAdviceLabel: self.pitcherAdviceLabel.destroy() self.pitcherAdviceLabel = None taskMgr.remove(self.pitcherAdviceName) def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel( relief=None, text=TTLocalizer.BossbotPitcherLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.059999999999999998, text_fg=VBase4(1, 1, 1, 1), ) self._DistributedBanquetTable__cleanupPitcherAdvice() def _DistributedBanquetTable__exitPitcher(self): self.showExiting() self.d_requestFree(False) def _DistributedBanquetTable__controlPressed(self): self._DistributedBanquetTable__cleanupPitcherAdvice() if self.TugOfWarControls: if self.power: self.aimStart = 1 self._DistributedBanquetTable__endFireWater() elif self.state == "Controlled": self._DistributedBanquetTable__beginFireWater() def _DistributedBanquetTable__controlReleased(self): if self.TugOfWarControls: pass 1 if self.state == "Controlled": self._DistributedBanquetTable__endFireWater() def _DistributedBanquetTable__upArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def _DistributedBanquetTable__downArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def _DistributedBanquetTable__rightArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowHorz = 1 elif self.arrowHorz > 0: self.arrowHorz = 0 def _DistributedBanquetTable__leftArrow(self, pressed): self._DistributedBanquetTable__incrementChangeSeq() self._DistributedBanquetTable__cleanupPitcherAdvice() if pressed: self.arrowHorz = -1 elif self.arrowHorz < 0: self.arrowHorz = 0 def _DistributedBanquetTable__incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendPitcherPos() taskMgr.remove(taskName) taskMgr.doMethodLater( self._DistributedBanquetTable__broadcastPeriod, self._DistributedBanquetTable__posHprBroadcast, taskName ) def _DistributedBanquetTable__posHprBroadcast(self, task): self.d_sendPitcherPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater( self._DistributedBanquetTable__broadcastPeriod, self._DistributedBanquetTable__posHprBroadcast, taskName ) return Task.done def d_sendPitcherPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate("setPitcherPos", [self.changeSeq, self.waterPitcherNode.getH(), timestamp]) def setPitcherPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.pitcherSmoother.setH(h) self.pitcherSmoother.setTimestamp(local) self.pitcherSmoother.markPosition() else: self.waterPitcherNode.setH(h) def _DistributedBanquetTable__watchControls(self, task): if self.arrowHorz: self._DistributedBanquetTable__movePitcher(self.arrowHorz) else: self._DistributedBanquetTable__setMoveSound(None) return Task.cont def _DistributedBanquetTable__movePitcher(self, xd): dt = globalClock.getDt() h = self.waterPitcherNode.getH() - xd * self.rotateSpeed * dt h %= 360 self.notify.debug( "rotSpeed=%.2f curH=%.2f xd =%.2f, dt = %.2f, h=%.2f" % (self.rotateSpeed, self.waterPitcherNode.getH(), xd, dt, h) ) limitH = h self.waterPitcherNode.setH(limitH) if xd: self._DistributedBanquetTable__setMoveSound(self.pitcherMoveSfx) def reloadPosition(self): self.pitcherSmoother.clearPositions(0) self.pitcherSmoother.setHpr(self.waterPitcherNode.getHpr()) self.pitcherSmoother.setPhonyTimestamp() def forceToTruePosition(self): if self.pitcherSmoother.getLatestPosition(): self.pitcherSmoother.applySmoothHpr(self.waterPitcherNode) self.pitcherSmoother.clearPositions(1) def getSprayTrack( self, color, origin, target, dScaleUp, dHold, dScaleDown, horizScale=1.0, vertScale=1.0, parent=render ): track = Sequence() SPRAY_LEN = 1.5 sprayProp = MovieUtil.globalPropPool.getProp("spray") sprayScale = hidden.attachNewNode("spray-parent") sprayRot = hidden.attachNewNode("spray-rotate") spray = sprayRot spray.setColor(color) if color[3] < 1.0: spray.setTransparency(1) def showSpray(sprayScale, sprayRot, sprayProp, origin, target, parent): if callable(origin): origin = origin() if callable(target): target = target() sprayRot.reparentTo(parent) sprayRot.clearMat() sprayScale.reparentTo(sprayRot) sprayScale.clearMat() sprayProp.reparentTo(sprayScale) sprayProp.clearMat() sprayRot.setPos(origin) sprayRot.lookAt(Point3(target)) track.append(Func(showSpray, sprayScale, sprayRot, sprayProp, origin, target, parent)) def calcTargetScale(target=target, origin=origin, horizScale=horizScale, vertScale=vertScale): if callable(target): target = target() if callable(origin): origin = origin() distance = Vec3(target - origin).length() yScale = distance / SPRAY_LEN targetScale = Point3(yScale * horizScale, yScale, yScale * vertScale) return targetScale track.append(LerpScaleInterval(sprayScale, dScaleUp, calcTargetScale, startScale=Point3(0.01, 0.01, 0.01))) track.append(Func(self.checkHitObject)) track.append(Wait(dHold)) def prepareToShrinkSpray(spray, sprayProp, origin, target): if callable(target): target = target() if callable(origin): origin = origin() sprayProp.setPos(Point3(0.0, -SPRAY_LEN, 0.0)) spray.setPos(target) track.append(Func(prepareToShrinkSpray, spray, sprayProp, origin, target)) track.append(LerpScaleInterval(sprayScale, dScaleDown, Point3(0.01, 0.01, 0.01))) def hideSpray(spray, sprayScale, sprayRot, sprayProp, propPool): sprayProp.detachNode() MovieUtil.removeProp(sprayProp) sprayRot.removeNode() sprayScale.removeNode() track.append(Func(hideSpray, spray, sprayScale, sprayRot, sprayProp, MovieUtil.globalPropPool)) return track def checkHitObject(self): if not self.hitObject: return None if self.avId != base.localAvatar.doId: return None tag = self.hitObject.getNetTag("pieCode") pieCode = int(tag) if pieCode == ToontownGlobals.PieCodeBossCog: self.hitBossSoundInterval.start() self.sendUpdate("waterHitBoss", [self.index]) if self.TugOfWarControls: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) else: damage = 1 if self.lastPowerFired < self.YELLOW_POWER_THRESHOLD: damage = 1 elif self.lastPowerFired < self.RED_POWER_THRESHOLD: damage = 2 else: damage = 3 self.boss.d_hitBoss(damage) def waterHitBoss(self, tableIndex): if self.index == tableIndex: self.hitBossSoundInterval.start() def setupPowerBar(self): self.powerBar = DirectWaitBar( pos=(0.0, 0, -0.93999999999999995), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.20000000000000001, 0.20000000000000001), borderWidth=(0.02, 0.02), scale=0.25, range=1, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(0.75, 0.75, 1.0, 0.80000000000000004), text="", text_scale=0.26000000000000001, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.050000000000000003), ) self.power = 0 self.powerBar["value"] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar["value"] = self.power self.powerBar["text"] = "" self.keyTTL = [] def _DistributedBanquetTable__beginFireWater(self): if self.fireTrack and self.fireTrack.isPlaying(): return None if self.aimStart != None: return None if not self.state == "Controlled": return None if not self.avId == localAvatar.doId: return None time = globalClock.getFrameTime() self.aimStart = time messenger.send("wakeup") taskMgr.add(self._DistributedBanquetTable__updateWaterPower, self.waterPowerTaskName) def _DistributedBanquetTable__endFireWater(self): if self.aimStart == None: return None if not self.state == "Controlled": return None if not self.avId == localAvatar.doId: return None taskMgr.remove(self.waterPowerTaskName) messenger.send("wakeup") self.aimStart = None origin = self.nozzle.getPos(render) target = self.boss.getPos(render) angle = deg2Rad(self.waterPitcherNode.getH() + 90) x = math.cos(angle) y = math.sin(angle) fireVector = Point3(x, y, 0) if self.power < 0.001: self.power = 0.001 self.lastPowerFired = self.power fireVector *= self.fireLength * self.power target = origin + fireVector segment = CollisionSegment(origin[0], origin[1], origin[2], target[0], target[1], target[2]) fromObject = render.attachNewNode(CollisionNode("pitcherColNode")) fromObject.node().addSolid(segment) fromObject.node().setFromCollideMask( ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask ) fromObject.node().setIntoCollideMask(BitMask32.allOff()) queue = CollisionHandlerQueue() base.cTrav.addCollider(fromObject, queue) base.cTrav.traverse(render) queue.sortEntries() self.hitObject = None if queue.getNumEntries(): entry = queue.getEntry(0) target = entry.getSurfacePoint(render) self.hitObject = entry.getIntoNodePath() base.cTrav.removeCollider(fromObject) fromObject.removeNode() self.d_firingWater(origin, target) self.fireWater(origin, target) self.resetPowerBar() def _DistributedBanquetTable__updateWaterPower(self, task): if not self.powerBar: print "### no power bar!!!" return task.done newPower = self._DistributedBanquetTable__getWaterPower(globalClock.getFrameTime()) self.power = newPower self.powerBar["value"] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(0.75, 0.75, 1.0, 0.80000000000000004) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(1.0, 1.0, 0.0, 0.80000000000000004) else: self.powerBar["barColor"] = VBase4(1.0, 0.0, 0.0, 0.80000000000000004) return task.cont def _DistributedBanquetTable__getWaterPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.waterPowerSpeed exponent = self.waterPowerExponent if t > 1: t = t % 1 power = 1 - math.pow(1 - t, exponent) if power > 1.0: power = 1.0 return power def d_firingWater(self, origin, target): self.sendUpdate("firingWater", [origin[0], origin[1], origin[2], target[0], target[1], target[2]]) def firingWater(self, startX, startY, startZ, endX, endY, endZ): origin = Point3(startX, startY, startZ) target = Point3(endX, endY, endZ) self.fireWater(origin, target) def fireWater(self, origin, target): color = VBase4(0.75, 0.75, 1, 0.80000000000000004) dScaleUp = 0.10000000000000001 dHold = 0.29999999999999999 dScaleDown = 0.10000000000000001 horizScale = 0.10000000000000001 vertScale = 0.10000000000000001 sprayTrack = self.getSprayTrack(color, origin, target, dScaleUp, dHold, dScaleDown, horizScale, vertScale) duration = self.squirtSfx.length() if sprayTrack.getDuration() < duration: duration = sprayTrack.getDuration() soundTrack = SoundInterval(self.squirtSfx, node=self.waterPitcherModel, duration=duration) self.fireTrack = Parallel(sprayTrack, soundTrack) self.fireTrack.start() def getPos(self, wrt=render): return self.tableGroup.getPos(wrt) def getLocator(self): return self.tableGroup def enterFlat(self, avId): self.prepareForPhaseFour() self.resetPowerBar() self.notify.debug("enterFlat %d" % self.index) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: toon.wrtReparentTo(render) toon.setZ(0) self.tableGroup.setScale(1, 1, 0.01) if self.avId and self.avId == localAvatar.doId: localAvatar.b_squish(ToontownGlobals.BossCogDamageLevels[ToontownGlobals.BossCogMoveAttack]) def exitFlat(self): self.tableGroup.setScale(1.0) if self.avId: toon = base.cr.doId2do.get(self.avId) if toon: if toon == localAvatar: self.boss.toCraneMode() toon.b_setAnimState("neutral") toon.setAnimState("neutral") toon.loop("leverNeutral") def _DistributedBanquetTable__allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence( self.tableGroup.colorScaleInterval(0.20000000000000001, VBase4(1, 1, 1, 1)), Func(self.tableGroup.clearColorScale), Func(self.tableGroup.clearTransparency), ) self.fadeTrack.start() self.allowLocalRequestControl = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True) def _DistributedBanquetTable__upArrowKeyPressed(self): if self.TugOfWarControls: self._DistributedBanquetTable__pressHandler(0) def _DistributedBanquetTable__downArrowKeyPressed(self): if self.TugOfWarControls: self._DistributedBanquetTable__pressHandler(1) def _DistributedBanquetTable__pressHandler(self, index): if index == self.buttons[0]: self.keyTTL.insert(0, 1.0) if not self.OnlyUpArrow: self.buttons.reverse() def _DistributedBanquetTable__spawnUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) taskMgr.doMethodLater( 0.10000000000000001, self._DistributedBanquetTable__updateKeyPressRateTask, self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK), ) def _DistributedBanquetTable__killUpdateKeyPressRateTask(self): taskMgr.remove(self.taskName(self.UPDATE_KEY_PRESS_RATE_TASK)) def _DistributedBanquetTable__updateKeyPressRateTask(self, task): if self.state not in "Controlled": return Task.done for i in range(len(self.keyTTL)): self.keyTTL[i] -= 0.10000000000000001 for i in range(len(self.keyTTL)): if self.keyTTL[i] <= 0: a = self.keyTTL[0:i] del self.keyTTL self.keyTTL = a break continue self.keyRate = len(self.keyTTL) keyRateDiff = self.keyRate - self.BASELINE_KEY_RATE diffPower = keyRateDiff / 300.0 if self.power < 1 and diffPower > 0: diffPower = diffPower * math.pow(1 - self.power, 1.25) newPower = self.power + diffPower if newPower > 1: newPower = 1 elif newPower < 0: newPower = 0 self.notify.debug("diffPower=%.2f keyRate = %d, newPower=%.2f" % (diffPower, self.keyRate, newPower)) self.power = newPower self.powerBar["value"] = newPower if self.power < self.YELLOW_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(0.75, 0.75, 1.0, 0.80000000000000004) elif self.power < self.RED_POWER_THRESHOLD: self.powerBar["barColor"] = VBase4(1.0, 1.0, 0.0, 0.80000000000000004) else: self.powerBar["barColor"] = VBase4(1.0, 0.0, 0.0, 0.80000000000000004) self._DistributedBanquetTable__spawnUpdateKeyPressRateTask() return Task.done def _DistributedBanquetTable__setMoveSound(self, sfx): if sfx != self.moveSound: if self.moveSound: self.moveSound.stop() self.moveSound = sfx if self.moveSound: base.playSfx(self.moveSound, looping=1, volume=0.5)
class DistributedGolfSpot(DistributedObject.DistributedObject, FSM.FSM): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedGolfSpot') positions = ((-45, 100, GolfGlobals.GOLF_BALL_RADIUS), (-15, 100, GolfGlobals.GOLF_BALL_RADIUS), (15, 100, GolfGlobals.GOLF_BALL_RADIUS), (45, 100, GolfGlobals.GOLF_BALL_RADIUS)) toonGolfOffsetPos = Point3(-2, 0, -GolfGlobals.GOLF_BALL_RADIUS) toonGolfOffsetHpr = Point3(-90, 0, 0) rotateSpeed = 20 golfPowerSpeed = base.config.GetDouble('golf-power-speed', 3) golfPowerExponent = base.config.GetDouble('golf-power-exponent', 0.75) def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) FSM.FSM.__init__(self, 'DistributedGolfSpot') self.boss = None self.index = None self.avId = 0 self.toon = None self.golfSpotSmoother = SmoothMover() self.golfSpotSmoother.setSmoothMode(SmoothMover.SMOn) self.smoothStarted = 0 self.__broadcastPeriod = 0.2 if self.index > len(self.positions): self.notify.error('Invalid index %d' % index) self.fadeTrack = None self.setupPowerBar() self.aimStart = None self.golfSpotAdviceLabel = None self.changeSeq = 0 self.lastChangeSeq = 0 self.controlKeyAllowed = False self.flyBallTracks = {} self.splatTracks = {} self.__flyBallBubble = None self.flyBallHandler = None self.__flyBallSequenceNum = 0 self.swingInterval = None self.lastHitSequenceNum = -1 self.goingToReward = False self.gotHitByBoss = False self.releaseTrack = None self.grabTrack = None self.restoreScaleTrack = None return def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] self.boss.setGolfSpot(self, self.index) def setIndex(self, index): self.index = index def disable(self): DistributedObject.DistributedObject.disable(self) self.ignoreAll() def delete(self): DistributedObject.DistributedObject.delete(self) self.ignoreAll() self.boss = None return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.triggerName = self.uniqueName('trigger') self.triggerEvent = 'enter%s' % self.triggerName self.smoothName = self.uniqueName('golfSpotSmooth') self.golfSpotAdviceName = self.uniqueName('golfSpotAdvice') self.posHprBroadcastName = self.uniqueName('golfSpotBroadcast') self.ballPowerTaskName = self.uniqueName('updateGolfPower') self.adjustClubTaskName = self.uniqueName('adjustClub') self.loadAssets() self.accept('flyBallHit-%d' % self.index, self.__flyBallHit) def loadAssets(self): self.root = render.attachNewNode('golfSpot-%d' % self.index) self.root.setPos(*self.positions[self.index]) self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball') self.ballColor = VBase4(1, 1, 1, 1) if self.index < len(GolfGlobals.PlayerColors): self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index]) self.ballModel.setColorScale(self.ballColor) self.ballModel.reparentTo(self.root) self.club = loader.loadModel('phase_6/models/golf/putter') self.clubLookatSpot = self.root.attachNewNode('clubLookat') self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1)) cs = CollisionSphere(0, 0, 0, 1) cs.setTangible(0) cn = CollisionNode(self.triggerName) cn.addSolid(cs) cn.setIntoCollideMask(ToontownGlobals.WallBitmask) self.trigger = self.root.attachNewNode(cn) self.trigger.stash() self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.ogg') def cleanup(self): if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if self.releaseTrack: self.releaseTrack.finish() self.releaseTrack = None flyTracks = self.flyBallTracks.values() for track in flyTracks: track.finish() if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None if self.restoreScaleTrack: self.restoreScaleTrack.finish() self.restoreScaleTrack = None self.root.removeNode() self.ballModel.removeNode() self.club.removeNode() if self.powerBar: self.powerBar.destroy() self.powerBar = None taskMgr.remove(self.triggerName) self.boss = None return def setState(self, state, avId, extraInfo): if not self.isDisabled(): self.gotHitByBoss = extraInfo if state == 'C': self.demand('Controlled', avId) elif state == 'F': self.demand('Free') elif state == 'O': self.demand('Off') else: self.notify.error('Invalid state from AI: %s' % state) def enterOff(self): pass def exitOff(self): pass def enterFree(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack = Sequence(Wait(6), self.getRestoreScaleInterval(), name='restoreScaleTrack') self.restoreScaleTrack.start() if self.avId == localAvatar.doId: if not self.isDisabled(): self.ballModel.setAlphaScale(0.3) self.ballModel.setTransparency(1) taskMgr.doMethodLater(5, self.__allowDetect, self.triggerName) self.fadeTrack = Sequence(Func(self.ballModel.setTransparency, 1), self.ballModel.colorScaleInterval(0.2, VBase4(1, 1, 1, 0.3)), name='fadeTrack-enterFree') self.fadeTrack.start() else: self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) self.avId = 0 return def exitFree(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None self.restoreScaleTrack.finish() self.restoreScaleTrack = None taskMgr.remove(self.triggerName) self.ballModel.clearTransparency() self.trigger.stash() self.ignore(self.triggerEvent) return def enterControlled(self, avId): self.avId = avId toon = base.cr.doId2do.get(avId) if not toon: return self.enableControlKey() self.toon = toon self.grabTrack = self.makeToonGrabInterval(toon) if avId == localAvatar.doId: self.boss.toCraneMode() camera.reparentTo(self.root) camera.setPosHpr(0, -10, 3, 0, 0, 0) localAvatar.setPos(self.root, self.toonGolfOffsetPos) localAvatar.setHpr(self.root, self.toonGolfOffsetHpr) localAvatar.sendCurrentPosition() self.__enableControlInterface() self.startPosHprBroadcast() self.accept('exitCrane', self.gotBossZapped) self.grabTrack.start() def exitControlled(self): self.grabTrack.finish() del self.grabTrack if self.swingInterval: self.swingInterval.finish() self.swingInterval = None if not self.ballModel.isEmpty(): if self.ballModel.isHidden(): self.notify.debug('ball is hidden scale =%s' % self.ballModel.getScale()) else: self.notify.debug('ball is showing scale=%s' % self.ballModel.getScale()) if self.toon and not self.toon.isDisabled(): self.toon.startSmooth() self.releaseTrack = self.makeToonReleaseInterval(self.toon) self.stopPosHprBroadcast() self.stopSmooth() if self.avId == localAvatar.doId: self.__disableControlInterface() if not self.goingToReward: camera.reparentTo(base.localAvatar) camera.setPos(base.localAvatar.cameraPositions[0][0]) camera.setHpr(0, 0, 0) self.stopAdjustClubTask() self.releaseTrack.start() self.enableControlKey() return def __allowDetect(self, task): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = Sequence(self.ballModel.colorScaleInterval(0.2, self.ballColor), Func(self.ballModel.clearTransparency), name='fadeTrack-allowDetect') self.fadeTrack.start() self.trigger.unstash() self.accept(self.triggerEvent, self.__hitTrigger) def __hitTrigger(self, event): self.d_requestControl() def getRestoreScaleInterval(self): return Sequence() def d_requestControl(self): self.sendUpdate('requestControl') def d_requestFree(self, gotHitByBoss): self.sendUpdate('requestFree', [gotHitByBoss]) def makeToonGrabInterval(self, toon): origPos = toon.getPos(self.root) origHpr = toon.getHpr(self.root) a = self.accomodateToon(toon) newPos = toon.getPos() newHpr = toon.getHpr() origHpr.setX(PythonUtil.fitSrcAngle2Dest(origHpr[0], newHpr[0])) self.notify.debug('toon.setPosHpr %s %s' % (origPos, origHpr)) toon.setPosHpr(origPos, origHpr) walkTime = 0.2 reach = Sequence() if reach.getDuration() < walkTime: reach = Sequence(ActorInterval(toon, 'walk', loop=1, duration=walkTime - reach.getDuration()), reach) i = Sequence(Parallel(toon.posInterval(walkTime, newPos, origPos), toon.hprInterval(walkTime, newHpr, origHpr), reach), Func(toon.stopLookAround)) if toon == base.localAvatar: i.append(Func(self.switchToAnimState, 'GolfPuttLoop')) i.append(Func(self.startAdjustClubTask)) i = Parallel(i, a) return i def accomodateToon(self, toon): toon.wrtReparentTo(self.root) toon.setPos(self.toonGolfOffsetPos) toon.setHpr(self.toonGolfOffsetHpr) return Sequence() def switchToAnimState(self, animStateName, forced = False): curAnimState = base.localAvatar.animFSM.getCurrentState() curAnimStateName = '' if curAnimState: curAnimStateName = curAnimState.getName() if curAnimStateName != animStateName or forced: base.localAvatar.b_setAnimState(animStateName) def __enableControlInterface(self): gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=2, text=TTLocalizer.BossbotGolfSpotLeave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(1.05, 0, -0.82), command=self.__exitGolfSpot) self.accept('escape', self.__exitGolfSpot) self.accept('control', self.__controlPressed) self.accept('control-up', self.__controlReleased) self.accept('InputState-forward', self.__upArrow) self.accept('InputState-reverse', self.__downArrow) self.accept('InputState-turnLeft', self.__leftArrow) self.accept('InputState-turnRight', self.__rightArrow) taskMgr.add(self.__watchControls, 'watchGolfSpotControls') taskMgr.doMethodLater(5, self.__displayGolfSpotAdvice, self.golfSpotAdviceName) self.arrowVert = 0 self.arrowHorz = 0 if self.powerBar: self.powerBar.show() return def __disableControlInterface(self): if self.closeButton: self.closeButton.destroy() self.closeButton = None self.__cleanupGolfSpotAdvice() self.ignore('escape') self.ignore('control') self.ignore('control-up') self.ignore('InputState-forward') self.ignore('InputState-reverse') self.ignore('InputState-turnLeft') self.ignore('InputState-turnRight') self.arrowVert = 0 self.arrowHorz = 0 taskMgr.remove('watchGolfSpotControls') if self.powerBar: self.powerBar.hide() else: self.notify.debug('self.powerBar is none') return def setupPowerBar(self): self.powerBar = DirectWaitBar(pos=(0.0, 0, -0.94), relief=DGG.SUNKEN, frameSize=(-2.0, 2.0, -0.2, 0.2), borderWidth=(0.02, 0.02), scale=0.25, range=100, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(1.0, 0.0, 0.0, 1.0), text='', text_scale=0.26, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05)) self.power = 0 self.powerBar['value'] = self.power self.powerBar.hide() def resetPowerBar(self): self.power = 0 self.powerBar['value'] = self.power self.powerBar['text'] = '' def __displayGolfSpotAdvice(self, task): if self.golfSpotAdviceLabel == None: self.golfSpotAdviceLabel = DirectLabel(text=TTLocalizer.BossbotGolfSpotAdvice, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0, 0, 0.69), scale=0.1) return def __cleanupGolfSpotAdvice(self): if self.golfSpotAdviceLabel: self.golfSpotAdviceLabel.destroy() self.golfSpotAdviceLabel = None taskMgr.remove(self.golfSpotAdviceName) return def showExiting(self): if self.closeButton: self.closeButton.destroy() self.closeButton = DirectLabel(relief=None, text=TTLocalizer.BossbotGolfSpotLeaving, pos=(1.05, 0, -0.88), text_pos=(0, 0), text_scale=0.06, text_fg=VBase4(1, 1, 1, 1)) self.__cleanupGolfSpotAdvice() return def __exitGolfSpot(self): self.d_requestFree(False) def __controlPressed(self): if self.controlKeyAllowed: self.__beginFireBall() def __controlReleased(self): if self.controlKeyAllowed: self.__endFireBall() def __upArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = 1 elif self.arrowVert > 0: self.arrowVert = 0 def __downArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowVert = -1 elif self.arrowVert < 0: self.arrowVert = 0 def __rightArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = 1 self.switchToAnimState('GolfRotateLeft') elif self.arrowHorz > 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __leftArrow(self, pressed): self.__incrementChangeSeq() self.__cleanupGolfSpotAdvice() if pressed: self.arrowHorz = -1 self.switchToAnimState('GolfRotateRight') elif self.arrowHorz < 0: self.arrowHorz = 0 self.switchToAnimState('GolfPuttLoop') def __watchControls(self, task): if self.arrowHorz: self.__moveGolfSpot(self.arrowHorz) return Task.cont def __moveGolfSpot(self, xd): dt = globalClock.getDt() h = self.root.getH() - xd * self.rotateSpeed * dt h %= 360 limitH = h self.root.setH(limitH) def __incrementChangeSeq(self): self.changeSeq = self.changeSeq + 1 & 255 def __beginFireBall(self): if self.aimStart != None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return time = globalClock.getFrameTime() self.aimStart = time messenger.send('wakeup') taskMgr.add(self.__updateBallPower, self.ballPowerTaskName) return def __endFireBall(self): if self.aimStart == None: return if not self.state == 'Controlled': return if not self.avId == localAvatar.doId: return taskMgr.remove(self.ballPowerTaskName) self.disableControlKey() messenger.send('wakeup') self.aimStart = None power = self.power angle = self.root.getH() self.notify.debug('incrementing self.__flyBallSequenceNum') self.__flyBallSequenceNum = (self.__flyBallSequenceNum + 1) % 255 self.sendSwingInfo(power, angle, self.__flyBallSequenceNum) self.setSwingInfo(power, angle, self.__flyBallSequenceNum) self.resetPowerBar() return def __updateBallPower(self, task): if not self.powerBar: print '### no power bar!!!' return task.done newPower = self.__getBallPower(globalClock.getFrameTime()) self.power = newPower self.powerBar['value'] = newPower return task.cont def __getBallPower(self, time): elapsed = max(time - self.aimStart, 0.0) t = elapsed / self.golfPowerSpeed t = math.pow(t, self.golfPowerExponent) power = int(t * 100) % 200 if power > 100: power = 200 - power return power def stopPosHprBroadcast(self): taskName = self.posHprBroadcastName taskMgr.remove(taskName) def startPosHprBroadcast(self): taskName = self.posHprBroadcastName self.b_clearSmoothing() self.d_sendGolfSpotPos() taskMgr.remove(taskName) taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) def __posHprBroadcast(self, task): self.d_sendGolfSpotPos() taskName = self.posHprBroadcastName taskMgr.doMethodLater(self.__broadcastPeriod, self.__posHprBroadcast, taskName) return Task.done def d_sendGolfSpotPos(self): timestamp = globalClockDelta.getFrameNetworkTime() self.sendUpdate('setGolfSpotPos', [self.changeSeq, self.root.getH(), timestamp]) def setGolfSpotPos(self, changeSeq, h, timestamp): self.changeSeq = changeSeq if self.smoothStarted: now = globalClock.getFrameTime() local = globalClockDelta.networkToLocalTime(timestamp, now) self.golfSpotSmoother.setH(h) self.golfSpotSmoother.setTimestamp(local) self.golfSpotSmoother.markPosition() else: self.root.setH(h) def b_clearSmoothing(self): self.d_clearSmoothing() self.clearSmoothing() def d_clearSmoothing(self): self.sendUpdate('clearSmoothing', [0]) def clearSmoothing(self, bogus = None): self.golfSpotSmoother.clearPositions(1) def doSmoothTask(self, task): self.golfSpotSmoother.computeAndApplySmoothHpr(self.root) return Task.cont def startSmooth(self): if not self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.reloadPosition() taskMgr.add(self.doSmoothTask, taskName) self.smoothStarted = 1 def stopSmooth(self): if self.smoothStarted: taskName = self.smoothName taskMgr.remove(taskName) self.forceToTruePosition() self.smoothStarted = 0 def makeToonReleaseInterval(self, toon): def getSlideToPos(toon = toon): return render.getRelativePoint(toon, Point3(0, -5, 0)) if self.gotHitByBoss: grabIval = Sequence(Func(self.detachClub), name='makeToonReleaseInterval-gotHitByBoss') if not toon.isEmpty(): toonIval = Sequence(Func(toon.wrtReparentTo, render), Parallel(ActorInterval(toon, 'slip-backward'), toon.posInterval(0.5, getSlideToPos, fluid=1)), name='makeToonReleaseInterval-toonIval') grabIval.append(toonIval) else: grabIval = Sequence(Func(self.detachClub)) if not toon.isEmpty(): toonIval = Sequence(Parallel(ActorInterval(toon, 'walk', duration=1.0, playRate=-1.0), LerpPosInterval(toon, duration=1.0, pos=Point3(-10, 0, 0))), Func(toon.wrtReparentTo, render)) grabIval.append(toonIval) if localAvatar.doId == toon.doId: if not self.goingToReward and toon.hp > 0: grabIval.append(Func(self.goToFinalBattle)) grabIval.append(Func(self.notify.debug, 'goingToFinalBattlemode')) grabIval.append(Func(self.safeBossToFinalBattleMode)) return grabIval def safeBossToFinalBattleMode(self): if self.boss: self.boss.toFinalBattleMode() def goToFinalBattle(self): if self.cr: place = self.cr.playGame.getPlace() if place and hasattr(place, 'fsm'): curState = place.fsm.getCurrentState().getName() if place.fsm.getCurrentState().getName() == 'crane': place.setState('finalBattle') else: self.notify.debug('NOT going to final battle, state=%s' % curState) def attachClub(self, avId, pointToBall = False): club = self.club if club: av = base.cr.doId2do.get(avId) if av: av.useLOD(1000) lHand = av.getLeftHands()[0] club.setPos(0, 0, 0) club.reparentTo(lHand) netScale = club.getNetTransform().getScale()[1] counterActToonScale = lHand.find('**/counteractToonScale') if counterActToonScale.isEmpty(): counterActToonScale = lHand.attachNewNode('counteractToonScale') counterActToonScale.setScale(1 / netScale) self.notify.debug('creating counterActToonScale for %s' % av.getName()) club.reparentTo(counterActToonScale) club.setX(-0.25 * netScale) if pointToBall: club.lookAt(self.clubLookatSpot) def detachClub(self): if not self.club.isEmpty(): self.club.reparentTo(self.root) self.club.setZ(-20) self.club.setScale(1) def adjustClub(self): club = self.club if club: distance = club.getDistance(self.clubLookatSpot) scaleFactor = distance / 2.058 club.setScale(1, scaleFactor, 1) def startAdjustClubTask(self): taskMgr.add(self.adjustClubTask, self.adjustClubTaskName) def stopAdjustClubTask(self): taskMgr.remove(self.adjustClubTaskName) def adjustClubTask(self, task): self.attachClub(self.avId, True) self.adjustClub() return task.cont def enableControlKey(self): self.controlKeyAllowed = True def disableControlKey(self): self.controlKeyAllowed = False def sendSwingInfo(self, power, angle, sequenceNum): self.sendUpdate('setSwingInfo', [power, angle, sequenceNum]) def startBallPlayback(self, power, angle, sequenceNum): flyBall = self.ballModel.copyTo(NodePath()) flyBall.setScale(1.0) flyBallBubble = self.getFlyBallBubble().instanceTo(NodePath()) flyBallBubble.reparentTo(flyBall) flyBall.setTag('pieSequence', str(sequenceNum)) flyBall.setTag('throwerId', str(self.avId)) t = power / 100.0 t = 1.0 - t dist = 300 - 200 * t time = 1.5 + 0.5 * t proj = ProjectileInterval(None, startPos=Point3(0, 0, 0), endPos=Point3(0, dist, 0), duration=time) relVel = proj.startVel def getVelocity(root = self.root, relVel = relVel): return render.getRelativeVector(root, relVel) fly = Sequence(Func(flyBall.reparentTo, render), Func(flyBall.setPosHpr, self.root, 0, 0, 0, 0, 0, 0), Func(base.cTrav.addCollider, flyBallBubble, self.flyBallHandler), ProjectileInterval(flyBall, startVel=getVelocity, duration=3), Func(flyBall.detachNode), Func(base.cTrav.removeCollider, flyBallBubble), Func(self.notify.debug, 'removed collider'), Func(self.flyBallFinishedFlying, sequenceNum)) flyWithSound = Parallel(fly, SoundInterval(self.hitBallSfx, node=self.root), name='flyWithSound') self.notify.debug('starting flyball track') flyWithSound.start() self.flyBallTracks[sequenceNum] = flyWithSound return def setSwingInfo(self, power, angle, sequenceNum): av = base.cr.doId2do.get(self.avId) self.swingInterval = Sequence() if av: self.stopAdjustClubTask() self.swingInterval = Sequence(ActorInterval(av, 'swing-putt', startFrame=0, endFrame=GolfGlobals.BALL_CONTACT_FRAME), Func(self.startBallPlayback, power, angle, sequenceNum), Func(self.ballModel.hide), ActorInterval(av, 'swing-putt', startFrame=GolfGlobals.BALL_CONTACT_FRAME, endFrame=24), Func(self.ballModel.setScale, 0.1), Func(self.ballModel.show), LerpScaleInterval(self.ballModel, 1.0, Point3(1, 1, 1)), Func(self.enableControlKey)) if av == localAvatar: self.swingInterval.append(Func(self.switchToAnimState, 'GolfPuttLoop', True)) self.swingInterval.start() def getFlyBallBubble(self): if self.__flyBallBubble == None: bubble = CollisionSphere(0, 0, 0, GolfGlobals.GOLF_BALL_RADIUS) node = CollisionNode('flyBallBubble') node.addSolid(bubble) node.setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) node.setIntoCollideMask(BitMask32.allOff()) self.__flyBallBubble = NodePath(node) self.flyBallHandler = CollisionHandlerEvent() self.flyBallHandler.addInPattern('flyBallHit-%d' % self.index) return self.__flyBallBubble def __flyBallHit(self, entry): print entry def flyBallFinishedFlying(self, sequence): if self.flyBallTracks.has_key(sequence): del self.flyBallTracks[sequence] def __finishFlyBallTrack(self, sequence): if self.flyBallTracks.has_key(sequence): flyBallTrack = self.flyBallTracks[sequence] del self.flyBallTracks[sequence] flyBallTrack.finish() def flyBallFinishedSplatting(self, sequence): if self.splatTracks.has_key(sequence): del self.splatTracks[sequence] def __flyBallHit(self, entry): if not entry.hasSurfacePoint() or not entry.hasInto(): return if not entry.getInto().isTangible(): return sequence = int(entry.getFromNodePath().getNetTag('pieSequence')) self.__finishFlyBallTrack(sequence) if self.splatTracks.has_key(sequence): splatTrack = self.splatTracks[sequence] del self.splatTracks[sequence] splatTrack.finish() flyBallCode = 0 flyBallCodeStr = entry.getIntoNodePath().getNetTag('pieCode') if flyBallCodeStr: flyBallCode = int(flyBallCodeStr) pos = entry.getSurfacePoint(render) timestamp32 = globalClockDelta.getFrameNetworkTime(bits=32) throwerId = int(entry.getFromNodePath().getNetTag('throwerId')) splat = self.getFlyBallSplatInterval(pos[0], pos[1], pos[2], flyBallCode, throwerId) splat = Sequence(splat, Func(self.flyBallFinishedSplatting, sequence)) self.splatTracks[sequence] = splat splat.start() self.notify.debug('doId=%d into=%s flyBallCode=%d, throwerId=%d' % (self.doId, entry.getIntoNodePath(), flyBallCode, throwerId)) if flyBallCode == ToontownGlobals.PieCodeBossCog and self.avId == localAvatar.doId and self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum self.boss.d_ballHitBoss(1) elif flyBallCode == ToontownGlobals.PieCodeToon and self.avId == localAvatar.doId and self.lastHitSequenceNum != self.__flyBallSequenceNum: self.lastHitSequenceNum = self.__flyBallSequenceNum 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: pass def getFlyBallSplatInterval(self, x, y, z, flyBallCode, throwerId): from toontown.toonbase import ToontownBattleGlobals from toontown.battle import BattleProps splatName = 'dust' splat = BattleProps.globalPropPool.getProp(splatName) splat.setBillboardPointWorld(2) color = ToontownGlobals.PieCodeColors.get(flyBallCode) if color: splat.setColor(*color) if flyBallCode == ToontownGlobals.PieCodeBossCog: self.notify.debug('changing color to %s' % self.ballColor) splat.setColor(self.ballColor) sound = loader.loadSfx('phase_11/audio/sfx/LB_evidence_miss.ogg') vol = 1.0 if flyBallCode == ToontownGlobals.PieCodeBossCog: sound = loader.loadSfx('phase_4/audio/sfx/Golf_Hit_Barrier_1.ogg') soundIval = SoundInterval(sound, node=splat, volume=vol) if flyBallCode == ToontownGlobals.PieCodeBossCog and localAvatar.doId == throwerId: vol = 1.0 soundIval = SoundInterval(sound, node=localAvatar, volume=vol) ival = Parallel(Func(splat.reparentTo, render), Func(splat.setPos, x, y, z), soundIval, Sequence(ActorInterval(splat, splatName), Func(splat.detachNode))) return ival def setGoingToReward(self): self.goingToReward = True def gotBossZapped(self): self.showExiting() self.d_requestFree(True)
def __init__(self, scenefile, capturefile=None, showstats=False, screenshot_dir=None): self.scenefile = scenefile self.capturefile = capturefile self.scene = scene.Scene.fromfile(scenefile) self.unique_models = set(m.slug for m in self.scene) self.multiplexer = pool.MultiplexPool() self.screenshot_dir = screenshot_dir print '%d objects in scene, %d unique' % (len(self.scene), len(self.unique_models)) # turns on lazy loading of textures p3d.loadPrcFileData('', 'preload-textures 0') p3d.loadPrcFileData('', 'preload-simple-textures 1') p3d.loadPrcFileData('', 'compressed-textures 1') p3d.loadPrcFileData('', 'allow-incomplete-render 0') # window size to 1024x768 p3d.loadPrcFileData('', 'win-size 1024 768') ShowBase.ShowBase.__init__(self) # background color sky blue self.win.setClearColorActive(True) self.win.setClearColor(p3d.VBase4(0.5294, 0.8078, 0.9215, 0)) # create a nodepath for each unique model self.unique_nodepaths = dict((m, p3d.NodePath(m)) for m in self.unique_models) self.rigid_body_combiners = {} self.rigid_body_combiner_np = {} for m in self.unique_models: #rbc = p3d.RigidBodyCombiner(m) rbc = p3d.NodePath(m) self.rigid_body_combiners[m] = rbc np = p3d.NodePath(rbc) np.reparentTo(self.render) self.rigid_body_combiner_np[m] = np # find out how many objects are going to be instanced for each node self.instance_count = collections.defaultdict(int) for model in self.scene: self.instance_count[model.slug] += 1 # then instance each unique model to its instantiation in the actual scene self.nodepaths = {} self.obj_bounds = {} self.nodepaths_byslug = collections.defaultdict(list) for model in self.scene: unique_np = self.unique_nodepaths[model.slug] node_name = model.slug + "_%.7g_%.7g_%.7g" % (model.x, model.y, model.z) if self.instance_count[model.slug] == 1: unique_np.setName(node_name) unique_np.reparentTo(self.render) np = unique_np else: np = self.rigid_body_combiner_np[model.slug].attachNewNode(node_name) self.nodepaths[model] = np self.nodepaths_byslug[model.slug].append(np) np.setPos(model.x, model.y, model.z) np.setScale(model.scale, model.scale, model.scale) q = p3d.Quat() q.setI(model.orient_x) q.setJ(model.orient_y) q.setK(model.orient_z) q.setR(model.orient_w) np.setQuat(q) self.obj_bounds[np] = p3d.BoundingSphere(np.getPos(), np.getScale()[0]) #for rbc in self.rigid_body_combiners.itervalues(): # rbc.collect() self.waiting = [] self.pm_waiting = collections.defaultdict(list) self.models_loaded = set() self.loading_priority = 2147483647 for m in self.unique_models: t = metadata.MetadataDownloadTask(m) self.multiplexer.add_task(t) self.disableMouse() pcore.attachLights(self.render) self.render.setShaderAuto() self.render.setTransparency(p3d.TransparencyAttrib.MNone) self.camLens.setFar(sys.maxint) self.camLens.setNear(8.0) self.render.setAntialias(p3d.AntialiasAttrib.MAuto) self.showstats = showstats if showstats: self.num_metadata_loaded = 0 self.num_models_loaded = 0 self.num_texture_updates = 0 self.num_mesh_refinements = 0 self.total_texture_updates = 0 self.total_mesh_refinements = 0 self.txtMetadataLoaded = gui.OnscreenText.OnscreenText(text='', style=1, pos=(0.01, -0.05), parent=self.a2dTopLeft, align=p3d.TextNode.ALeft, scale=0.05, fg=(0.1, 0.1, 0.1, 1), shadow=(0.9, 0.9, 0.9, 1)) self.txtUniqueLoaded = gui.OnscreenText.OnscreenText(text='', style=1, pos=(0.01, -0.11), parent=self.a2dTopLeft, align=p3d.TextNode.ALeft, scale=0.05, fg=(0.1, 0.1, 0.1, 1), shadow=(0.9, 0.9, 0.9, 1)) self.txtTextureUpdates = gui.OnscreenText.OnscreenText(text='', style=1, pos=(0.01, -0.17), parent=self.a2dTopLeft, align=p3d.TextNode.ALeft, scale=0.05, fg=(0.1, 0.1, 0.1, 1), shadow=(0.9, 0.9, 0.9, 1)) self.txtMeshRefinements = gui.OnscreenText.OnscreenText(text='', style=1, pos=(0.01, -0.23), parent=self.a2dTopLeft, align=p3d.TextNode.ALeft, scale=0.05, fg=(0.1, 0.1, 0.1, 1), shadow=(0.9, 0.9, 0.9, 1)) self.update_stats() self.globalClock = p3d.ClockObject.getGlobalClock() self.smooth_mover = SmoothMover() self.smooth_mover.setPredictionMode(SmoothMover.PMOn) self.smooth_mover.setSmoothMode(SmoothMover.SMOn) self.smooth_mover.setMaxPositionAge(10.0) self.smooth_mover.setAcceptClockSkew(False) self.smooth_mover.setDelay(0) self.pandastate = katasked.panda.PandaState(self.cam, self.unique_nodepaths, self.nodepaths, self.smooth_mover, self.globalClock, self.obj_bounds) if self.capturefile is not None: self.capturedata = json.load(self.capturefile) self.duration = self.capturedata['duration'] self.positions = self.capturedata['positions'] self.rotations = self.capturedata['rotations'] self.curve_creator = motioncap.CreateNurbsCurve() for pos, rot in zip(self.positions, self.rotations): self.curve_creator.addPoint(pos, rot) self.mopath = self.curve_creator.getMotionPath() self.interval = MopathInterval.MopathInterval(self.mopath, self.cam, duration=self.duration, name="Camera Replay") else: controls.KeyboardMovement() controls.MouseCamera() self.update_camera_predictor_task = self.taskMgr.doMethodLater(0.1, self.update_camera_predictor, 'update_camera_predictor') self.update_priority_task = self.taskMgr.doMethodLater(0.5, self.check_pool, 'check_pool') self.load_waiting_task = self.taskMgr.doMethodLater(0.1, self.load_waiting, 'load_waiting')
class ProgressiveLoader(ShowBase.ShowBase): def __init__(self, scenefile, capturefile=None, showstats=False, screenshot_dir=None): self.scenefile = scenefile self.capturefile = capturefile self.scene = scene.Scene.fromfile(scenefile) self.unique_models = set(m.slug for m in self.scene) self.multiplexer = pool.MultiplexPool() self.screenshot_dir = screenshot_dir print '%d objects in scene, %d unique' % (len(self.scene), len(self.unique_models)) # turns on lazy loading of textures p3d.loadPrcFileData('', 'preload-textures 0') p3d.loadPrcFileData('', 'preload-simple-textures 1') p3d.loadPrcFileData('', 'compressed-textures 1') p3d.loadPrcFileData('', 'allow-incomplete-render 0') # window size to 1024x768 p3d.loadPrcFileData('', 'win-size 1024 768') ShowBase.ShowBase.__init__(self) # background color sky blue self.win.setClearColorActive(True) self.win.setClearColor(p3d.VBase4(0.5294, 0.8078, 0.9215, 0)) # create a nodepath for each unique model self.unique_nodepaths = dict((m, p3d.NodePath(m)) for m in self.unique_models) self.rigid_body_combiners = {} self.rigid_body_combiner_np = {} for m in self.unique_models: #rbc = p3d.RigidBodyCombiner(m) rbc = p3d.NodePath(m) self.rigid_body_combiners[m] = rbc np = p3d.NodePath(rbc) np.reparentTo(self.render) self.rigid_body_combiner_np[m] = np # find out how many objects are going to be instanced for each node self.instance_count = collections.defaultdict(int) for model in self.scene: self.instance_count[model.slug] += 1 # then instance each unique model to its instantiation in the actual scene self.nodepaths = {} self.obj_bounds = {} self.nodepaths_byslug = collections.defaultdict(list) for model in self.scene: unique_np = self.unique_nodepaths[model.slug] node_name = model.slug + "_%.7g_%.7g_%.7g" % (model.x, model.y, model.z) if self.instance_count[model.slug] == 1: unique_np.setName(node_name) unique_np.reparentTo(self.render) np = unique_np else: np = self.rigid_body_combiner_np[model.slug].attachNewNode(node_name) self.nodepaths[model] = np self.nodepaths_byslug[model.slug].append(np) np.setPos(model.x, model.y, model.z) np.setScale(model.scale, model.scale, model.scale) q = p3d.Quat() q.setI(model.orient_x) q.setJ(model.orient_y) q.setK(model.orient_z) q.setR(model.orient_w) np.setQuat(q) self.obj_bounds[np] = p3d.BoundingSphere(np.getPos(), np.getScale()[0]) #for rbc in self.rigid_body_combiners.itervalues(): # rbc.collect() self.waiting = [] self.pm_waiting = collections.defaultdict(list) self.models_loaded = set() self.loading_priority = 2147483647 for m in self.unique_models: t = metadata.MetadataDownloadTask(m) self.multiplexer.add_task(t) self.disableMouse() pcore.attachLights(self.render) self.render.setShaderAuto() self.render.setTransparency(p3d.TransparencyAttrib.MNone) self.camLens.setFar(sys.maxint) self.camLens.setNear(8.0) self.render.setAntialias(p3d.AntialiasAttrib.MAuto) self.showstats = showstats if showstats: self.num_metadata_loaded = 0 self.num_models_loaded = 0 self.num_texture_updates = 0 self.num_mesh_refinements = 0 self.total_texture_updates = 0 self.total_mesh_refinements = 0 self.txtMetadataLoaded = gui.OnscreenText.OnscreenText(text='', style=1, pos=(0.01, -0.05), parent=self.a2dTopLeft, align=p3d.TextNode.ALeft, scale=0.05, fg=(0.1, 0.1, 0.1, 1), shadow=(0.9, 0.9, 0.9, 1)) self.txtUniqueLoaded = gui.OnscreenText.OnscreenText(text='', style=1, pos=(0.01, -0.11), parent=self.a2dTopLeft, align=p3d.TextNode.ALeft, scale=0.05, fg=(0.1, 0.1, 0.1, 1), shadow=(0.9, 0.9, 0.9, 1)) self.txtTextureUpdates = gui.OnscreenText.OnscreenText(text='', style=1, pos=(0.01, -0.17), parent=self.a2dTopLeft, align=p3d.TextNode.ALeft, scale=0.05, fg=(0.1, 0.1, 0.1, 1), shadow=(0.9, 0.9, 0.9, 1)) self.txtMeshRefinements = gui.OnscreenText.OnscreenText(text='', style=1, pos=(0.01, -0.23), parent=self.a2dTopLeft, align=p3d.TextNode.ALeft, scale=0.05, fg=(0.1, 0.1, 0.1, 1), shadow=(0.9, 0.9, 0.9, 1)) self.update_stats() self.globalClock = p3d.ClockObject.getGlobalClock() self.smooth_mover = SmoothMover() self.smooth_mover.setPredictionMode(SmoothMover.PMOn) self.smooth_mover.setSmoothMode(SmoothMover.SMOn) self.smooth_mover.setMaxPositionAge(10.0) self.smooth_mover.setAcceptClockSkew(False) self.smooth_mover.setDelay(0) self.pandastate = katasked.panda.PandaState(self.cam, self.unique_nodepaths, self.nodepaths, self.smooth_mover, self.globalClock, self.obj_bounds) if self.capturefile is not None: self.capturedata = json.load(self.capturefile) self.duration = self.capturedata['duration'] self.positions = self.capturedata['positions'] self.rotations = self.capturedata['rotations'] self.curve_creator = motioncap.CreateNurbsCurve() for pos, rot in zip(self.positions, self.rotations): self.curve_creator.addPoint(pos, rot) self.mopath = self.curve_creator.getMotionPath() self.interval = MopathInterval.MopathInterval(self.mopath, self.cam, duration=self.duration, name="Camera Replay") else: controls.KeyboardMovement() controls.MouseCamera() self.update_camera_predictor_task = self.taskMgr.doMethodLater(0.1, self.update_camera_predictor, 'update_camera_predictor') self.update_priority_task = self.taskMgr.doMethodLater(0.5, self.check_pool, 'check_pool') self.load_waiting_task = self.taskMgr.doMethodLater(0.1, self.load_waiting, 'load_waiting') def run(self): if self.screenshot_dir is not None: self.start_time = None self.screenshot_info = [] self.screenshot_task = self.taskMgr.doMethodLater(0, self.trigger_screenshot, 'screenshot_task', sort=-1) if self.capturefile is not None: self.interval.start() self.taskMgr.doMethodLater(self.duration + 2.0, self.finished, 'exiter') ShowBase.ShowBase.run(self) def update_camera_predictor(self, task): curtime = self.globalClock.getFrameTime() self.smooth_mover.setPos(self.cam.getPos()) self.smooth_mover.setHpr(self.cam.getHpr()) self.smooth_mover.setTimestamp(curtime) self.smooth_mover.markPosition() return task.again def check_pool(self, task): t0 = time.time() finished_tasks = self.multiplexer.poll(self.pandastate) t1 = time.time() time_took = t1-t0 time_wait = time_took * 2.0 time_wait = min(time_wait, 1) time_wait = max(time_wait, 0.1) task.delayTime = time_wait if len(finished_tasks) == 0 and self.multiplexer.empty(): print print 'FINISHED LOADING' print return task.done for t in finished_tasks: if isinstance(t, meshtask.MeshLoadTask): self.loader.loadModel(t.bam_file, callback=self.model_loaded, extraArgs=[t.modelslug], priority=self.loading_priority) elif isinstance(t, texturetask.TextureDownloadTask): self.loader.loadModel(t.bam_file, callback=self.texture_loaded, extraArgs=[t.modelslug], priority=self.loading_priority) elif isinstance(t, refinementtask.MeshRefinementDownloadTask): if t.modelslug in self.models_loaded: self.waiting.append((LOAD_TYPE.MESH_REFINEMENT, t.modelslug, t.pm_refinements)) else: self.pm_waiting[t.modelslug].append(t.pm_refinements) elif isinstance(t, metadata.MetadataDownloadTask): if self.showstats: self.num_metadata_loaded += 1 progressive = t.metadata['metadata']['types']['progressive'] byte_ranges = progressive['mipmaps']['./atlas.jpg']['byte_ranges'] baselevel = len(byte_ranges) for i, levelinfo in enumerate(byte_ranges): if levelinfo['width'] >= 128 or levelinfo['height'] >= 128: baselevel = i break self.total_texture_updates += len(byte_ranges[baselevel+1:]) if 'progressive_stream_size' in progressive: self.total_mesh_refinements += int(math.ceil(progressive['progressive_stream_size'] / float(percepfilter.PM_CHUNK_SIZE))) self.update_stats() self.loading_priority -= 1 return task.again def model_loaded(self, modelpath, modelslug): self.models_loaded.add(modelslug) self.waiting.append((LOAD_TYPE.INITIAL_MODEL, modelpath, modelslug)) for pm_refinements in self.pm_waiting[modelslug]: self.waiting.append((LOAD_TYPE.MESH_REFINEMENT, modelslug, pm_refinements)) del self.pm_waiting[modelslug] def texture_loaded(self, modelpath, modelslug): newtex = modelpath.getChild(0).getTexture() np = self.unique_nodepaths[modelslug] self.waiting.append((LOAD_TYPE.TEXTURE_UPDATE, np, newtex)) def load_waiting(self, task): time_wait = 0.1 if len(self.waiting) > 0: t0 = time.time() args = self.waiting.pop(0) if args[0] == LOAD_TYPE.INITIAL_MODEL: modelpath, modelslug = args[1], args[2] np = self.unique_nodepaths[modelslug] modelnode = modelpath.getChild(0) geomnode = modelnode.getChild(0) trans = modelnode.getTransform() geomnode.setTransform(trans) self.unique_nodepaths[modelslug] = geomnode if self.instance_count[modelslug] == 1: geomnode.reparentTo(np) else: for instance_np in self.nodepaths_byslug[modelslug]: geomnode.instanceTo(instance_np) #self.rigid_body_combiners[modelslug].collect() if self.showstats: self.num_models_loaded += 1 self.update_stats() elif args[0] == LOAD_TYPE.TEXTURE_UPDATE: np, newtex = args[1], args[2] np.setTextureOff(1) np.setTexture(newtex, 1) if self.showstats: self.num_texture_updates += 1 self.update_stats() elif args[0] == LOAD_TYPE.MESH_REFINEMENT: modelslug, pm_refinements = args[1], args[2] np = self.unique_nodepaths[modelslug] pdae_updater.update_nodepath(np.node(), pm_refinements) #if self.instance_count[modelslug] > 1: # self.rigid_body_combiners[modelslug].collect() if self.showstats: self.num_mesh_refinements += 1 self.update_stats() t1 = time.time() time_took = t1-t0 time_wait = time_took * 2.0 time_wait = min(time_wait, 1) time_wait = max(time_wait, 0.1) task.delayTime = time_wait return task.again def trigger_screenshot(self, task): if self.start_time is None: self.start_time = self.globalClock.getLongTime() task.delayTime = 1.0 return task.again run_time = self.globalClock.getLongTime() - self.start_time fname = ('%07.2f' % run_time) + '.tiff' self.screenshot_info.append({'filename': fname, 'position': list(self.cam.getPos()), 'hpr': list(self.cam.getHpr())}) self.win.saveScreenshot(os.path.join(self.screenshot_dir, 'realtime', fname)) return task.again def finished(self, task): if self.screenshot_dir is not None: with open(os.path.join(self.screenshot_dir, 'info.json'), 'w') as f: json.dump(self.screenshot_info, f, indent=2) sys.exit(len(self.screenshot_info)) sys.exit(0) def update_stats(self): self.txtMetadataLoaded.setText('Metadata Loaded: %d/%d' % (self.num_metadata_loaded, len(self.unique_models))) self.txtUniqueLoaded.setText('Base Mesh Loaded: %d/%d' % (self.num_models_loaded, len(self.unique_models))) self.txtTextureUpdates.setText('Texture Updates: %d/%d' % (self.num_texture_updates, self.total_texture_updates)) self.txtMeshRefinements.setText('Mesh Refinements: %d/%d' % (self.num_mesh_refinements, self.total_mesh_refinements))