def loadFood(self, foodIndex): self.foodNum += 1 if foodIndex in self.foodModelDict: foodModel = self.foodModelDict[foodIndex] foodModel.reparentTo(self.foodNodes[foodIndex]) colNp = foodModel.find('**/FoodCol*') colNp.setTag('foodNum', str(self.foodNum)) else: foodModelScale = ToontownGlobals.BossbotFoodModelScale foodModel = loader.loadModel('phase_12/models/bossbotHQ/canoffood') foodModel.setScale(foodModelScale) foodModel.reparentTo(self.foodNodes[foodIndex]) target = CollisionTube(4, 0, 0, -4, 0, 0, 2) target.setTangible(0) colName = 'FoodCol-%d-%d' % (self.index, foodIndex) targetNode = CollisionNode(colName) targetNode.addSolid(target) targetNode.setCollideMask(ToontownGlobals.WallBitmask) targetNodePath = foodModel.attachNewNode(targetNode) targetNodePath.setScale(1.0 / foodModelScale) targetNodePath.setTag('foodIndex', str(foodIndex)) targetNodePath.setTag('beltIndex', str(self.index)) targetNodePath.setTag('foodNum', str(self.foodNum)) targetNodePath.setZ(targetNodePath.getZ() - 1.5) self.accept('enter' + colName, self.touchedFood) self.foodModelDict[foodIndex] = foodModel
def loadToonup(self, toonupIndex): self.toonupNum += 1 if toonupIndex in self.toonupModelDict: toonupModel = self.toonupModelDict[toonupIndex] toonupModel.reparentTo(self.foodNodes[toonupIndex]) colNp = toonupModel.find('**/ToonupCol*') colNp.setTag('toonupNum', str(self.toonupNum)) else: toonupModelScale = self.ToonupScales[toonupIndex] modelName = self.ToonupModels[toonupIndex] toonupModel = loader.loadModel(modelName) self.foodNodes[toonupIndex].setZ(self.beltHeight - 0.10000000000000001) toonupModel.setZ(self.ToonupZOffsets[toonupIndex]) toonupModel.setScale(toonupModelScale) toonupModel.reparentTo(self.foodNodes[toonupIndex]) target = CollisionTube(4, 0, 0, -4, 0, 0, 2) target.setTangible(0) colName = 'ToonupCol-%d-%d' % (self.index, toonupIndex) targetNode = CollisionNode(colName) targetNode.addSolid(target) targetNode.setCollideMask(ToontownGlobals.WallBitmask) targetNodePath = toonupModel.attachNewNode(targetNode) targetNodePath.setScale(1.0 / toonupModelScale) targetNodePath.setTag('toonupIndex', str(toonupIndex)) targetNodePath.setTag('beltIndex', str(self.index)) targetNodePath.setTag('toonupNum', str(self.toonupNum)) targetNodePath.setZ(targetNodePath.getZ() - 1.5 / toonupModelScale) self.accept('enter' + colName, self.touchedToonup) self.toonupModelDict[toonupIndex] = toonupModel
def loadToonup(self, toonupIndex): self.toonupNum += 1 if toonupIndex in self.toonupModelDict: toonupModel = self.toonupModelDict[toonupIndex] toonupModel.reparentTo(self.foodNodes[toonupIndex]) colNp = toonupModel.find('**/ToonupCol*') colNp.setTag('toonupNum', str(self.toonupNum)) else: toonupModelScale = self.ToonupScales[toonupIndex] modelName = self.ToonupModels[toonupIndex] toonupModel = loader.loadModel(modelName) self.foodNodes[toonupIndex].setZ(self.beltHeight - 0.1) toonupModel.setZ(self.ToonupZOffsets[toonupIndex]) toonupModel.setScale(toonupModelScale) toonupModel.reparentTo(self.foodNodes[toonupIndex]) target = CollisionTube(4, 0, 0, -4, 0, 0, 2) target.setTangible(0) colName = 'ToonupCol-%d-%d' % (self.index, toonupIndex) targetNode = CollisionNode(colName) targetNode.addSolid(target) targetNode.setCollideMask(ToontownGlobals.WallBitmask) targetNodePath = toonupModel.attachNewNode(targetNode) targetNodePath.setScale(1.0 / toonupModelScale) targetNodePath.setTag('toonupIndex', str(toonupIndex)) targetNodePath.setTag('beltIndex', str(self.index)) targetNodePath.setTag('toonupNum', str(self.toonupNum)) targetNodePath.setZ(targetNodePath.getZ() - 1.5 / toonupModelScale) self.accept('enter' + colName, self.touchedToonup) self.toonupModelDict[toonupIndex] = toonupModel
class Agent: def __init__(self, model, run, walk, startPos, scale, select,ralph,saysome): self.actor = Actor(model, {"run":run, "walk":walk}) self.actor.reparentTo(render) self.actor.setScale(scale) self.actor.setPos(startPos) self.actor.setHpr(90,0,0) self.playerGUI = saysome self.myralph = ralph self.setAI() self.cTrav = CollisionTraverser() self.groundRay = CollisionRay(0,0,1000,0,0,-1) self.groundCol = CollisionNode('dinoRay') self.groundCol.addSolid(self.groundRay) self.groundCol.setFromCollideMask(BitMask32.bit(1)) self.groundCol.setIntoCollideMask(BitMask32.allOff()) self.groundColNp = self.actor.attachNewNode(self.groundCol) self.groundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.groundColNp, self.groundHandler) self.sphere = CollisionSphere(0,0,5,13) self.spherecol = CollisionNode('dinoSphere') self.spherecol.addSolid(self.sphere) self.spherecol.setCollideMask(BitMask32.bit(1)) self.dinocolhs = self.actor.attachNewNode(self.spherecol) #self.dinocolhs.show() #self.groundColNp.show() #self.cTrav.showCollisions(render) def setAI(self): #Creating AI World self.AIworld = AIWorld(render) self.AIchar = AICharacter("seeker",self.actor, 380, 50, 250) self.AIworld.addAiChar(self.AIchar) self.AIbehaviors = self.AIchar.getAiBehaviors() self.AIbehaviors.pursue(self.myralph) self.actor.loop('run') #AI World update taskMgr.add(self.AIUpdate,"AIUpdate") #to update the AIWorld def AIUpdate(self,task): if self.playerGUI.getpausevalue(): self.AIworld.update() return Task.cont def setControl(self, control, value): self.controlMap[control] = value def getactor(self): return self.actor
class DistributedLawbotCannon(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLawbotCannon') LOCAL_CANNON_MOVE_TASK = 'localCannonMoveTask' FIRE_KEY = 'control' UP_KEY = 'arrow_up' DOWN_KEY = 'arrow_down' LEFT_KEY = 'arrow_left' RIGHT_KEY = 'arrow_right' HIT_GROUND = 0 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.index = None self.avId = 0 self.av = None self.localToonShooting = 0 self.cannonsActive = 0 self.cannonLocation = None self.cannonPostion = None self.cannon = None self.madeGui = 0 self.jurorToon = None self.toonModel = None self.toonHead = None self.toonScale = None self.dustCloud = None self.hitBumper = 0 self.hitTarget = 0 self.lastPos = Vec3(0, 0, 0) self.lastVel = Vec3(0, 0, 0) self.vel = Vec3(0, 0, 0) self.landingPos = Vec3(0, 0, 0) self.t = 0 self.lastT = 0 self.deltaT = 0 self.hitTrack = None self.flyColNode = None self.flyColNodePath = None self.localAvId = base.localAvatar.doId self.model_Created = 0 return def disable(self): taskMgr.remove(self.uniqueName('fireCannon')) taskMgr.remove(self.uniqueName('shootTask')) self.__stopFlyTask(self.avId) taskMgr.remove(self.uniqueName('flyTask')) self.ignoreAll() self.setMovie(CannonGlobals.CANNON_MOVIE_CLEAR, 0, 0) self.nodePath.detachNode() self.__unmakeGui() if self.hitTrack: self.hitTrack.finish() del self.hitTrack self.hitTrack = None DistributedObject.DistributedObject.disable(self) return def delete(self): self.offstage() self.unload() DistributedObject.DistributedObject.delete(self) def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.boss.cannons[self.index] = self def generateInit(self): DistributedObject.DistributedObject.generateInit(self) self.nodePath = NodePath(self.uniqueName('Cannon')) self.load() self.activateCannons() def setPosHpr(self, x, y, z, h, p, r): self.nodePath.setPosHpr(x, y, z, h, p, r) def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] def getSphereRadius(self): return 1.5 def getParentNodePath(self): return render def setIndex(self, index): self.index = index def load(self): self.cannon = loader.loadModel('phase_4/models/minigames/toon_cannon') self.collSphere = CollisionSphere(0, 0, 0, self.getSphereRadius()) self.dustCloud = DustCloud.DustCloud(render) self.dustCloud.setBillboardPointEye() self.collSphere.setTangible(1) self.collNode = CollisionNode(self.uniqueName('CannonSphere')) self.collNode.setCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.nodePath.attachNewNode(self.collNode) self.cannon.reparentTo(self.nodePath) self.kartColNode = CollisionNode(self.uniqueName('KartColNode')) self.kartNode = self.nodePath.attachNewNode(self.kartColNode) self.sndCannonMove = base.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.ogg') self.sndCannonFire = base.loadSfx('phase_4/audio/sfx/MG_cannon_fire_alt.ogg') self.sndHitGround = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg') self.sndHitChair = base.loadSfx('phase_11/audio/sfx/LB_toon_jury.ogg') self.cannon.hide() self.flashingLabel = None return def unload(self): if self.cannon: self.cannon.removeNode() del self.cannon if self.dustCloud != None: self.dustCloud.destroy() del self.dustCloud del self.sndCannonMove del self.sndCannonFire del self.sndHitGround del self.sndHitChair if self.av: self.__resetToon(self.av) self.av.loop('neutral') self.av.setPlayRate(1.0, 'run') if self.toonHead != None: self.toonHead.stopBlink() self.toonHead.stopLookAroundNow() self.toonHead.delete() del self.toonHead if self.toonModel != None: self.toonModel.removeNode() del self.toonModel if self.jurorToon != None: self.jurorToon.delete() del self.jurorToon del self.toonScale return def activateCannons(self): if not self.cannonsActive: self.cannonsActive = 1 self.onstage() self.nodePath.reparentTo(self.getParentNodePath()) self.accept(self.uniqueName('enterCannonSphere'), self.__handleEnterSphere) def onstage(self): self.__createCannon() self.cannon.reparentTo(self.nodePath) self.dustCloud.reparentTo(render) def offstage(self): if self.cannon: self.cannon.reparentTo(hidden) if self.dustCloud: self.dustCloud.reparentTo(hidden) self.dustCloud.stop() def __createCannon(self): self.barrel = self.cannon.find('**/cannon') self.cannonLocation = Point3(0, 0, 0.025) self.cannonPosition = [0, CANNON_ANGLE_MIN] self.cannon.setPos(self.cannonLocation) self.__updateCannonPosition(self.avId) def updateCannonPosition(self, avId, zRot, angle): if avId != self.localAvId: self.cannonPosition = [zRot, angle] self.__updateCannonPosition(avId) def __updateCannonPosition(self, avId): self.cannon.setHpr(self.cannonPosition[0], 0.0, 0.0) self.barrel.setHpr(0.0, self.cannonPosition[1], 0.0) maxP = 90 newP = self.barrel.getP() yScale = 1 - 0.5 * float(newP) / maxP shadow = self.cannon.find('**/square_drop_shadow') shadow.setScale(1, yScale, 1) def __handleEnterSphere(self, collEntry): self.d_requestEnter() def d_requestEnter(self): self.sendUpdate('requestEnter', []) def setMovie(self, mode, avId, extraInfo): wasLocalToon = self.localToonShooting self.avId = avId if mode == CannonGlobals.CANNON_MOVIE_CLEAR: self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_LANDED: self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_FORCE_EXIT: self.exitCannon(self.avId) self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_LOAD: if self.avId == base.localAvatar.doId: self.cannonBallsLeft = extraInfo base.cr.playGame.getPlace().setState('crane') base.localAvatar.setTeleportAvailable(0) self.localToonShooting = 1 self.__makeGui() camera.reparentTo(self.barrel) camera.setPos(0.5, -2, 2.5) camera.setHpr(0, 0, 0) self.boss.toonEnteredCannon(self.avId, self.index) if self.cr.doId2do.has_key(self.avId): self.av = self.cr.doId2do[self.avId] self.acceptOnce(self.av.uniqueName('disable'), self.__avatarGone) self.av.loop('neutral') self.av.stopSmooth() self.__destroyToonModels() self.__createToonModels() self.av.setPosHpr(3, 0, 0, 90, 0, 0) self.av.reparentTo(self.cannon) else: self.notify.warning('Unknown avatar %d in cannon %d' % (self.avId, self.doId)) else: self.notify.warning('unhandled case, mode = %d' % mode) def __avatarGone(self): self.setMovie(CannonGlobals.CANNON_MOVIE_CLEAR, 0, 0) def __makeGui(self): if self.madeGui: return NametagGlobals.setMasterArrowsOn(0) guiModel = 'phase_4/models/gui/cannon_game_gui' cannonGui = loader.loadModel(guiModel) self.aimPad = DirectFrame(image=cannonGui.find('**/CannonFire_PAD'), relief=None, pos=(0.7, 0, -0.553333), scale=0.8) cannonGui.removeNode() self.fireButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Fire_Btn_UP'), (guiModel, '**/Fire_Btn_DN'), (guiModel, '**/Fire_Btn_RLVR')), relief=None, pos=(0.0115741, 0, 0.00505051), scale=1.0, command=self.__firePressed) self.upButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0115741, 0, 0.221717)) self.downButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0136112, 0, -0.210101), image_hpr=(0, 0, 180)) self.leftButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(-0.199352, 0, -0.000505269), image_hpr=(0, 0, -90)) self.rightButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.219167, 0, -0.00101024), image_hpr=(0, 0, 90)) guiClose = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') cannonBallText = '%d/%d' % (self.cannonBallsLeft, ToontownGlobals.LawbotBossCannonBallMax) self.cannonBallLabel = DirectLabel(parent=self.aimPad, text=cannonBallText, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0.475, 0.0, -0.35), scale=0.25) if self.cannonBallsLeft < 5: if self.flashingLabel: self.flashingLabel.stop() flashingTrack = Sequence() for i in range(10): flashingTrack.append(LerpColorScaleInterval(self.cannonBallLabel, 0.5, VBase4(1, 0, 0, 1))) flashingTrack.append(LerpColorScaleInterval(self.cannonBallLabel, 0.5, VBase4(1, 1, 1, 1))) self.flashingLabel = flashingTrack self.flashingLabel.start() self.aimPad.setColor(1, 1, 1, 0.9) def bindButton(button, upHandler, downHandler): button.bind(DGG.B1PRESS, lambda x, handler = upHandler: handler()) button.bind(DGG.B1RELEASE, lambda x, handler = downHandler: handler()) bindButton(self.upButton, self.__upPressed, self.__upReleased) bindButton(self.downButton, self.__downPressed, self.__downReleased) bindButton(self.leftButton, self.__leftPressed, self.__leftReleased) bindButton(self.rightButton, self.__rightPressed, self.__rightReleased) self.__enableAimInterface() self.madeGui = 1 return def __unmakeGui(self): self.notify.debug('__unmakeGui') if not self.madeGui: return if self.flashingLabel: self.flashingLabel.finish() self.flashingLabel = None NametagGlobals.setMasterArrowsOn(1) self.__disableAimInterface() self.upButton.unbind(DGG.B1PRESS) self.upButton.unbind(DGG.B1RELEASE) self.downButton.unbind(DGG.B1PRESS) self.downButton.unbind(DGG.B1RELEASE) self.leftButton.unbind(DGG.B1PRESS) self.leftButton.unbind(DGG.B1RELEASE) self.rightButton.unbind(DGG.B1PRESS) self.rightButton.unbind(DGG.B1RELEASE) self.aimPad.destroy() del self.aimPad del self.fireButton del self.upButton del self.downButton del self.leftButton del self.rightButton self.madeGui = 0 return def __enableAimInterface(self): self.aimPad.show() self.accept(self.FIRE_KEY, self.__fireKeyPressed) self.accept(self.UP_KEY, self.__upKeyPressed) self.accept(self.DOWN_KEY, self.__downKeyPressed) self.accept(self.LEFT_KEY, self.__leftKeyPressed) self.accept(self.RIGHT_KEY, self.__rightKeyPressed) self.__spawnLocalCannonMoveTask() def __disableAimInterface(self): self.aimPad.hide() self.ignore(self.FIRE_KEY) self.ignore(self.UP_KEY) self.ignore(self.DOWN_KEY) self.ignore(self.LEFT_KEY) self.ignore(self.RIGHT_KEY) self.ignore(self.FIRE_KEY + '-up') self.ignore(self.UP_KEY + '-up') self.ignore(self.DOWN_KEY + '-up') self.ignore(self.LEFT_KEY + '-up') self.ignore(self.RIGHT_KEY + '-up') self.__killLocalCannonMoveTask() def __fireKeyPressed(self): self.ignore(self.FIRE_KEY) self.accept(self.FIRE_KEY + '-up', self.__fireKeyReleased) self.__firePressed() def __upKeyPressed(self): self.ignore(self.UP_KEY) self.accept(self.UP_KEY + '-up', self.__upKeyReleased) self.__upPressed() def __downKeyPressed(self): self.ignore(self.DOWN_KEY) self.accept(self.DOWN_KEY + '-up', self.__downKeyReleased) self.__downPressed() def __leftKeyPressed(self): self.ignore(self.LEFT_KEY) self.accept(self.LEFT_KEY + '-up', self.__leftKeyReleased) self.__leftPressed() def __rightKeyPressed(self): self.ignore(self.RIGHT_KEY) self.accept(self.RIGHT_KEY + '-up', self.__rightKeyReleased) self.__rightPressed() def __fireKeyReleased(self): self.ignore(self.FIRE_KEY + '-up') self.accept(self.FIRE_KEY, self.__fireKeyPressed) def __leftKeyReleased(self): self.ignore(self.LEFT_KEY + '-up') self.accept(self.LEFT_KEY, self.__leftKeyPressed) self.__leftReleased() def __rightKeyReleased(self): self.ignore(self.RIGHT_KEY + '-up') self.accept(self.RIGHT_KEY, self.__rightKeyPressed) self.__rightReleased() def __upKeyReleased(self): self.ignore(self.UP_KEY + '-up') self.accept(self.UP_KEY, self.__upKeyPressed) self.__upReleased() def __downKeyReleased(self): self.ignore(self.DOWN_KEY + '-up') self.accept(self.DOWN_KEY, self.__downKeyPressed) self.__downReleased() def __leaveCannon(self): self.notify.debug('__leaveCannon') self.sendUpdate('requestLeave') def __firePressed(self): self.notify.debug('fire pressed') if not self.boss.state == 'BattleTwo': self.notify.debug('boss is in state=%s, not firing' % self.boss.state) return self.__broadcastLocalCannonPosition() self.__unmakeGui() self.sendUpdate('setCannonLit', [self.cannonPosition[0], self.cannonPosition[1]]) def __upPressed(self): self.notify.debug('up pressed') self.upPressed = self.__enterControlActive(self.upPressed) def __downPressed(self): self.notify.debug('down pressed') self.downPressed = self.__enterControlActive(self.downPressed) def __leftPressed(self): self.notify.debug('left pressed') self.leftPressed = self.__enterControlActive(self.leftPressed) def __rightPressed(self): self.notify.debug('right pressed') self.rightPressed = self.__enterControlActive(self.rightPressed) def __upReleased(self): self.notify.debug('up released') self.upPressed = self.__exitControlActive(self.upPressed) def __downReleased(self): self.notify.debug('down released') self.downPressed = self.__exitControlActive(self.downPressed) def __leftReleased(self): self.notify.debug('left released') self.leftPressed = self.__exitControlActive(self.leftPressed) def __rightReleased(self): self.notify.debug('right released') self.rightPressed = self.__exitControlActive(self.rightPressed) def __enterControlActive(self, control): return control + 1 def __exitControlActive(self, control): return max(0, control - 1) def __spawnLocalCannonMoveTask(self): self.leftPressed = 0 self.rightPressed = 0 self.upPressed = 0 self.downPressed = 0 self.cannonMoving = 0 task = Task(self.__localCannonMoveTask) task.lastPositionBroadcastTime = 0.0 taskMgr.add(task, self.LOCAL_CANNON_MOVE_TASK) def __killLocalCannonMoveTask(self): taskMgr.remove(self.LOCAL_CANNON_MOVE_TASK) if self.cannonMoving: self.sndCannonMove.stop() def __localCannonMoveTask(self, task): pos = self.cannonPosition oldRot = pos[0] oldAng = pos[1] rotVel = 0 if self.leftPressed: rotVel += CANNON_ROTATION_VEL if self.rightPressed: rotVel -= CANNON_ROTATION_VEL pos[0] += rotVel * globalClock.getDt() if pos[0] < CANNON_ROTATION_MIN: pos[0] = CANNON_ROTATION_MIN elif pos[0] > CANNON_ROTATION_MAX: pos[0] = CANNON_ROTATION_MAX angVel = 0 if self.upPressed: angVel += CANNON_ANGLE_VEL if self.downPressed: angVel -= CANNON_ANGLE_VEL pos[1] += angVel * globalClock.getDt() if pos[1] < CANNON_ANGLE_MIN: pos[1] = CANNON_ANGLE_MIN elif pos[1] > CANNON_ANGLE_MAX: pos[1] = CANNON_ANGLE_MAX if oldRot != pos[0] or oldAng != pos[1]: if self.cannonMoving == 0: self.cannonMoving = 1 base.playSfx(self.sndCannonMove, looping=1) self.__updateCannonPosition(self.localAvId) if task.time - task.lastPositionBroadcastTime > CANNON_MOVE_UPDATE_FREQ: task.lastPositionBroadcastTime = task.time self.__broadcastLocalCannonPosition() elif self.cannonMoving: self.cannonMoving = 0 self.sndCannonMove.stop() self.__broadcastLocalCannonPosition() return Task.cont def __broadcastLocalCannonPosition(self): self.sendUpdate('setCannonPosition', [self.cannonPosition[0], self.cannonPosition[1]]) def __updateCannonPosition(self, avId): self.cannon.setHpr(self.cannonPosition[0], 0.0, 0.0) self.barrel.setHpr(0.0, self.cannonPosition[1], 0.0) maxP = 90 newP = self.barrel.getP() yScale = 1 - 0.5 * float(newP) / maxP shadow = self.cannon.find('**/square_drop_shadow') shadow.setScale(1, yScale, 1) def __createToonModels(self): self.model_Created = 1 self.jurorToon = NPCToons.createLocalNPC(ToontownGlobals.LawbotBossBaseJurorNpcId + self.index) self.toonScale = self.jurorToon.getScale() jurorToonParent = render.attachNewNode('toonOriginChange') self.jurorToon.wrtReparentTo(jurorToonParent) self.jurorToon.setPosHpr(0, 0, -(self.jurorToon.getHeight() / 2.0), 0, -90, 0) self.toonModel = jurorToonParent self.toonHead = ToonHead.ToonHead() self.toonHead.setupHead(self.jurorToon.style) self.toonHead.reparentTo(hidden) self.__loadToonInCannon() def __destroyToonModels(self): if (0): self.av.dropShadow.show() if self.dropShadow != None: self.dropShadow.removeNode() self.dropShadow = None self.hitBumper = 0 self.hitTarget = 0 self.angularVel = 0 self.vel = Vec3(0, 0, 0) self.lastVel = Vec3(0, 0, 0) self.lastPos = Vec3(0, 0, 0) self.landingPos = Vec3(0, 0, 0) self.t = 0 self.lastT = 0 self.deltaT = 0 self.av = None self.lastWakeTime = 0 self.localToonShooting = 0 if self.toonHead != None: self.toonHead.reparentTo(hidden) self.toonHead.stopBlink() self.toonHead.stopLookAroundNow() self.toonHead = None if self.toonModel != None: self.toonModel.removeNode() self.toonModel = None if self.jurorToon != None: self.jurorToon.delete() self.jurorToon = None self.model_Created = 0 return def __loadToonInCannon(self): self.toonModel.reparentTo(hidden) self.toonHead.startBlink() self.toonHead.startLookAround() self.toonHead.reparentTo(self.barrel) self.toonHead.setPosHpr(0, 6, 0, 0, -45, 0) sc = self.toonScale self.toonHead.setScale(render, sc[0], sc[1], sc[2]) def exitCannon(self, avId): self.__unmakeGui() if self.avId == avId: self.av.reparentTo(render) self.__resetToonToCannon(self.av) def __resetToonToCannon(self, avatar): pos = None if not avatar: if self.avId: avatar = base.cr.doId2do.get(self.avId, None) if avatar: if hasattr(self, 'cannon') and self.cannon: avatar.reparentTo(self.cannon) avatar.setPosHpr(3, 0, 0, 90, 0, 0) avatar.wrtReparentTo(render) self.__resetToon(avatar) return def __resetToon(self, avatar, pos = None): if avatar: self.__stopCollisionHandler(avatar) self.__setToonUpright(avatar, pos) if self.localToonShooting: self.notify.debug('toon setting position to %s' % pos) if pos: base.localAvatar.setPos(pos) camera.reparentTo(avatar) camera.setPos(self.av.cameraPositions[0][0]) place = base.cr.playGame.getPlace() if place: place.setState('finalBattle') self.b_setLanded() def __stopCollisionHandler(self, avatar): if avatar: avatar.loop('neutral') if self.flyColNode: self.flyColNode = None if avatar == base.localAvatar: avatar.collisionsOn() self.flyColSphere = None if self.flyColNodePath: base.cTrav.removeCollider(self.flyColNodePath) self.flyColNodePath.removeNode() self.flyColNodePath = None self.handler = None return def __setToonUpright(self, avatar, pos = None): if avatar: if not pos: pos = avatar.getPos(render) avatar.setPos(render, pos) avatar.loop('neutral') def b_setLanded(self): self.d_setLanded() def d_setLanded(self): if self.localToonShooting: self.sendUpdate('setLanded', []) def setLanded(self): self.removeAvFromCannon() def removeAvFromCannon(self): if self.av != None: self.__stopCollisionHandler(self.av) self.av.resetLOD() place = base.cr.playGame.getPlace() if self.av == base.localAvatar: if place: place.setState('finalBattle') self.av.loop('neutral') self.av.setPlayRate(1.0, 'run') if self.av.getParent().getName() == 'toonOriginChange': self.av.wrtReparentTo(render) self.__setToonUpright(self.av) if self.av == base.localAvatar: self.av.startPosHprBroadcast() self.av.startSmooth() self.av.setScale(1, 1, 1) self.ignore(self.av.uniqueName('disable')) self.__destroyToonModels() return def setCannonWillFire(self, avId, fireTime, zRot, angle, timestamp): self.notify.debug('setCannonWillFire: ' + str(avId) + ': zRot=' + str(zRot) + ', angle=' + str(angle) + ', time=' + str(fireTime)) if not self.model_Created: self.notify.warning("We walked into the zone mid-flight, so we won't see it") return self.cannonPosition[0] = zRot self.cannonPosition[1] = angle self.__updateCannonPosition(avId) task = Task(self.__fireCannonTask) task.avId = avId ts = globalClockDelta.localElapsedTime(timestamp) task.fireTime = fireTime - ts if task.fireTime < 0.0: task.fireTime = 0.0 taskMgr.add(task, self.taskName('fireCannon')) def __fireCannonTask(self, task): launchTime = task.fireTime avId = task.avId if self.toonHead == None or not self.boss.state == 'BattleTwo': return Task.done startPos, startHpr, startVel, trajectory, timeOfImpact, hitWhat = self.__calcFlightResults(avId, launchTime) self.notify.debug('start position: ' + str(startPos)) self.notify.debug('start velocity: ' + str(startVel)) self.notify.debug('time of launch: ' + str(launchTime)) self.notify.debug('time of impact: ' + str(timeOfImpact)) self.notify.debug('location of impact: ' + str(trajectory.getPos(timeOfImpact))) head = self.toonHead head.stopBlink() head.stopLookAroundNow() head.reparentTo(hidden) juror = self.toonModel juror.reparentTo(render) juror.setPos(startPos) barrelHpr = self.barrel.getHpr(render) juror.setHpr(startHpr) self.jurorToon.loop('swim') self.jurorToon.setPosHpr(0, 0, -(self.jurorToon.getHeight() / 2.0), 0, 0, 0) info = {} info['avId'] = avId info['trajectory'] = trajectory info['launchTime'] = launchTime info['timeOfImpact'] = timeOfImpact info['hitWhat'] = hitWhat info['toon'] = self.toonModel info['hRot'] = self.cannonPosition[0] info['haveWhistled'] = 0 info['maxCamPullback'] = CAMERA_PULLBACK_MIN if self.localToonShooting: camera.reparentTo(juror) camera.setP(45.0) camera.setZ(-10.0) self.flyColSphere = CollisionSphere(0, 0, self.av.getHeight() / 2.0, 1.0) self.flyColNode = CollisionNode(self.uniqueName('flySphere')) self.flyColNode.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.FloorBitmask | ToontownGlobals.PieBitmask) self.flyColNode.addSolid(self.flyColSphere) self.flyColNodePath = self.jurorToon.attachNewNode(self.flyColNode) self.flyColNodePath.setColor(1, 0, 0, 1) self.handler = CollisionHandlerEvent() self.handler.setInPattern(self.uniqueName('cannonHit')) base.cTrav.addCollider(self.flyColNodePath, self.handler) self.accept(self.uniqueName('cannonHit'), self.__handleCannonHit) shootTask = Task(self.__shootTask, self.taskName('shootTask')) flyTask = Task(self.__flyTask, self.taskName('flyTask')) shootTask.info = info flyTask.info = info seqTask = Task.sequence(shootTask, flyTask) taskMgr.add(seqTask, self.taskName('flyingToon') + '-' + str(avId)) self.acceptOnce(self.uniqueName('stopFlyTask'), self.__stopFlyTask) return Task.done def __toRadians(self, angle): return angle * 2.0 * math.pi / 360.0 def __toDegrees(self, angle): return angle * 360.0 / (2.0 * math.pi) def __calcFlightResults(self, avId, launchTime): head = self.toonHead startPos = head.getPos(render) startHpr = head.getHpr(render) hpr = self.barrel.getHpr(render) rotation = self.__toRadians(hpr[0]) angle = self.__toRadians(hpr[1]) horizVel = INITIAL_VELOCITY * math.cos(angle) xVel = horizVel * -math.sin(rotation) yVel = horizVel * math.cos(rotation) zVel = INITIAL_VELOCITY * math.sin(angle) startVel = Vec3(xVel, yVel, zVel) trajectory = Trajectory.Trajectory(launchTime, startPos, startVel) self.trajectory = trajectory timeOfImpact, hitWhat = self.__calcToonImpact(trajectory) return startPos, startHpr, startVel, trajectory, 3 * timeOfImpact, hitWhat def __calcToonImpact(self, trajectory): t_groundImpact = trajectory.checkCollisionWithGround(GROUND_PLANE_MIN) if t_groundImpact >= trajectory.getStartTime(): return (t_groundImpact, self.HIT_GROUND) else: self.notify.error('__calcToonImpact: toon never impacts ground?') return (0.0, self.HIT_GROUND) def __handleCannonHit(self, collisionEntry): if self.av == None or self.flyColNode == None: return interPt = collisionEntry.getSurfacePoint(render) hitNode = collisionEntry.getIntoNode().getName() fromNodePath = collisionEntry.getFromNodePath() intoNodePath = collisionEntry.getIntoNodePath() ignoredHits = ['NearBoss'] for nodeName in ignoredHits: if hitNode == nodeName: return self.__stopFlyTask(self.avId) self.__stopCollisionHandler(self.jurorToon) if self.localToonShooting: camera.wrtReparentTo(render) pos = interPt hpr = self.jurorToon.getHpr() track = Sequence() if self.localToonShooting: pass chairlist = ['trigger-chair'] for index in range(len(ToontownGlobals.LawbotBossChairPosHprs)): chairlist.append('Chair-%s' % index) if hitNode in chairlist: track.append(Func(self.__hitChair, self.jurorToon, pos)) track.append(Wait(1.0)) track.append(Func(self.__setToonUpright, self.av)) if self.av == base.localAvatar: strs = hitNode.split('-') chairNum = int(strs[1]) self.boss.sendUpdate('hitChair', [chairNum, self.index]) else: track.append(Func(self.__hitGround, self.jurorToon, pos)) track.append(Wait(1.0)) track.append(Func(self.__setToonUpright, self.av)) track.append(Func(self.b_setLanded)) if self.localToonShooting: pass if self.hitTrack: self.hitTrack.finish() self.hitTrack = track self.hitTrack.start() return def enterCannonHit(self, collisionEntry): pass def __shootTask(self, task): base.playSfx(self.sndCannonFire) return Task.done def __flyTask(self, task): toon = task.info['toon'] if toon.isEmpty(): self.__resetToonToCannon(self.av) return Task.done curTime = task.time + task.info['launchTime'] t = min(curTime, task.info['timeOfImpact']) self.lastT = self.t self.t = t deltaT = self.t - self.lastT self.deltaT = deltaT if t >= task.info['timeOfImpact']: self.__resetToonToCannon(self.av) return Task.done pos = task.info['trajectory'].getPos(t) toon.setFluidPos(pos) vel = task.info['trajectory'].getVel(t) run = math.sqrt(vel[0] * vel[0] + vel[1] * vel[1]) rise = vel[2] theta = self.__toDegrees(math.atan(rise / run)) toon.setHpr(self.cannon.getH(render), -90 + theta, 0) view = 2 lookAt = task.info['toon'].getPos(render) hpr = task.info['toon'].getHpr(render) if self.localToonShooting: if view == 0: camera.wrtReparentTo(render) camera.lookAt(lookAt) elif view == 1: camera.reparentTo(render) camera.setPos(render, 100, 100, 35.25) camera.lookAt(render, lookAt) elif view == 2: if hpr[1] > -90: camera.setPos(0, 0, -30) if camera.getZ() < lookAt[2]: camera.setZ(render, lookAt[2] + 10) camera.lookAt(Point3(0, 0, 0)) return Task.cont def __stopFlyTask(self, avId): taskMgr.remove(self.taskName('flyingToon') + '-' + str(avId)) def __hitGround(self, avatar, pos, extraArgs = []): hitP = avatar.getPos(render) h = self.barrel.getH(render) avatar.setPos(pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) avatar.setHpr(h, -135, 0) self.dustCloud.setPos(render, pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) self.dustCloud.setScale(0.35) self.dustCloud.play() base.playSfx(self.sndHitGround) avatar.hide() def __hitChair(self, avatar, pos, extraArgs = []): hitP = avatar.getPos(render) h = self.barrel.getH(render) avatar.setPos(pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) avatar.setHpr(h, -135, 0) self.dustCloud.setPos(render, pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) self.dustCloud.setScale(0.35) self.dustCloud.play() base.playSfx(self.sndHitGround) base.playSfx(self.sndHitChair) avatar.hide() def generateCannonAppearTrack(self, avatar): self.cannon.setScale(0.1) self.cannon.show() kartTrack = Parallel(Sequence(ActorInterval(avatar, 'feedPet'), Func(avatar.loop, 'neutral')), Sequence(Func(self.cannon.reparentTo, avatar.rightHand), Wait(2.1), Func(self.cannon.wrtReparentTo, render), Func(self.cannon.setShear, 0, 0, 0), Parallel(LerpHprInterval(self.cannon, hpr=self.nodePath.getHpr(render), duration=1.2), ProjectileInterval(self.cannon, endPos=self.nodePath.getPos(render), duration=1.2, gravityMult=0.45)), Wait(0.2), Sequence(LerpScaleInterval(self.cannon, scale=Point3(1.1, 1.1, 0.1), duration=0.2), LerpScaleInterval(self.cannon, scale=Point3(0.9, 0.9, 0.1), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 0.1), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 1.1), duration=0.2), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 0.9), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 1.0), duration=0.1), Func(self.cannon.wrtReparentTo, self.nodePath)))) return kartTrack
class DistributedPartyTrampolineActivity(DistributedPartyActivity): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyTrampolineActivity') def __init__(self, cr, doJellyBeans = True, doTricks = False, texture = None): DistributedPartyTrampolineActivity.notify.debug('__init__') DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityTypes.GuestInitiated, wantLever=False, wantRewardGui=True) self.doJellyBeans = doJellyBeans self.doTricks = doTricks self.texture = texture self.toon = None self.trampHeight = 3.6 self.trampK = 400.0 self.normalTrampB = 2.5 self.leavingTrampB = 8.0 self.trampB = self.normalTrampB self.g = -32.0 self.jumpBoost = 330.0 self.beginningBoost = 500.0 self.beginningBoostThreshold = self.trampHeight + 1.5 self.earlyJumpThreshold = 75.0 self.boingThreshold = 300.0 self.turnFactor = 120.0 self.stepDT = 0.001 self.targetCameraPos = Point3(0.0, 40.0, 10.0) self.cameraSpeed = 2.0 self.hopOffPos = Point3(16.0, 0.0, 0.0) self.indicatorFactor = 0.0095 self.dropShadowCutoff = 15.0 self.minHeightForText = 15.0 self.heightTextOffset = -0.065 self.beanOffset = 0.5 self.guiBeanOffset = -0.02 self.jumpTextShown = False self.toonJumped = False self.turnLeft = False self.turnRight = False self.leavingTrampoline = False self.toonVelocity = 0.0 self.topHeight = 0.0 self.lastPeak = 0.0 self.beginRoundInterval = None self.hopOnAnim = None self.hopOffAnim = None self.flashTextInterval = None self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus self.jellyBeanStartHeight = 20.0 self.jellyBeanStopHeight = 90.0 self.jellyBeanColors = [VBase4(1.0, 0.5, 0.5, 1.0), VBase4(0.5, 1.0, 0.5, 1.0), VBase4(0.5, 1.0, 1.0, 1.0), VBase4(1.0, 1.0, 0.4, 1.0), VBase4(0.4, 0.4, 1.0, 1.0), VBase4(1.0, 0.5, 1.0, 1.0)] delta = (self.jellyBeanStopHeight - self.jellyBeanStartHeight) / (self.numJellyBeans - 1) self.jellyBeanPositions = [ self.jellyBeanStartHeight + n * delta for n in xrange(self.numJellyBeans) ] self.doSimulateStep = False return def load(self): DistributedPartyTrampolineActivity.notify.debug('load') DistributedPartyActivity.load(self) self.loadModels() self.loadCollision() self.loadGUI() self.loadSounds() self.loadIntervals() self.activityFSM = TrampolineActivityFSM(self) self.activityFSM.request('Idle') self.animFSM = TrampolineAnimFSM(self) self.setBestHeightInfo('', 0) def loadModels(self): self.tramp = self.root.attachNewNode(self.uniqueName('tramp')) self.trampActor = Actor('phase_13/models/parties/trampoline_model', {'emptyAnim': 'phase_13/models/parties/trampoline_anim'}) self.trampActor.reparentTo(self.tramp) if self.texture: reskinNode = self.tramp.find('**/trampoline/__Actor_modelRoot/-GeomNode') reskinNode.setTexture(loader.loadTexture(self.texture), 100) self.surface = NodePath(self.uniqueName('trampSurface')) self.surface.reparentTo(self.tramp) self.surface.setZ(self.trampHeight) self.trampActor.controlJoint(self.surface, 'modelRoot', 'trampoline_joint1') self.sign.setPos(PartyGlobals.TrampolineSignOffset) self.beans = [ loader.loadModelCopy('phase_4/models/props/jellybean4') for i in xrange(self.numJellyBeans) ] for bean in self.beans: bean.find('**/jellybean').setP(-35.0) bean.setScale(3.0) bean.setTransparency(True) bean.reparentTo(self.tramp) bean.stash() self.beans[-1].setScale(8.0) def loadCollision(self): collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4) collTube.setTangible(True) self.trampolineCollision = CollisionNode(self.uniqueName('TrampolineCollision')) self.trampolineCollision.addSolid(collTube) self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask | OTPGlobals.WallBitmask) self.trampolineCollisionNP = self.tramp.attachNewNode(self.trampolineCollision) collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0) collSphere.setTangible(False) self.trampolineTrigger = CollisionNode(self.uniqueName('TrampolineTrigger')) self.trampolineTrigger.addSolid(collSphere) self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask) self.trampolineTriggerNP = self.tramp.attachNewNode(self.trampolineTrigger) self.accept('enter%s' % self.uniqueName('TrampolineTrigger'), self.onTrampolineTrigger) def loadGUI(self): self.gui = loader.loadModel('phase_13/models/parties/trampolineGUI') self.gui.reparentTo(base.a2dTopLeft) self.gui.setPos(0.115, 0, -1) self.gui.hide() self.toonIndicator = self.gui.find('**/trampolineGUI_MovingBar') jumpLineLocator = self.gui.find('**/jumpLine_locator') guiBean = self.gui.find('**/trampolineGUI_GreenJellyBean') self.gui.find('**/trampolineGUI_GreenJellyBean').stash() self.guiBeans = [ guiBean.instanceUnderNode(jumpLineLocator, self.uniqueName('guiBean%d' % i)) for i in xrange(self.numJellyBeans) ] self.guiBeans[-1].setScale(1.5) heightTextNode = TextNode(self.uniqueName('TrampolineActivity.heightTextNode')) heightTextNode.setFont(ToontownGlobals.getSignFont()) heightTextNode.setAlign(TextNode.ALeft) heightTextNode.setText('0.0') heightTextNode.setShadow(0.05, 0.05) heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0) heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0) self.heightText = jumpLineLocator.attachNewNode(heightTextNode) self.heightText.setX(0.15) self.heightText.setScale(0.1) self.heightText.setAlphaScale(0.0) self.quitEarlyButtonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui') quitEarlyUp = self.quitEarlyButtonModels.find('**//InventoryButtonUp') quitEarlyDown = self.quitEarlyButtonModels.find('**/InventoryButtonDown') quitEarlyRollover = self.quitEarlyButtonModels.find('**/InventoryButtonRollover') self.quitEarlyButton = DirectButton(parent=base.a2dTopRight, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-0.183, 0, -0.4), scale=0.09, command=self.leaveTrampoline) self.quitEarlyButton.stash() self.flashText = OnscreenText(text='', pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True) self.timer = PartyUtils.getNewToontownTimer() self.timer.posInTopRightCorner() return def loadSounds(self): self.jellyBeanSound = base.loadSfx('phase_4/audio/sfx/sparkly.ogg') self.boingSound = base.loadSfx('phase_4/audio/sfx/target_trampoline_2.ogg') self.whistleSound = base.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg') def loadIntervals(self): def prepareHeightText(): self.heightText.node().setText(TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ())) self.heightText.setZ(self.indicatorFactor * self.toon.getZ() + self.heightTextOffset) self.heightTextInterval = Sequence(Func(prepareHeightText), LerpFunc(self.heightText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0)) def unload(self): DistributedPartyTrampolineActivity.notify.debug('unload') if self.hopOnAnim and self.hopOnAnim.isPlaying(): self.hopOnAnim.finish() if self.hopOffAnim and self.hopOffAnim.isPlaying(): self.hopOffAnim.finish() if self.beginRoundInterval and self.beginRoundInterval.isPlaying(): self.beginRoundInterval.finish() if self.flashTextInterval and self.flashTextInterval.isPlaying(): self.flashTextInterval.finish() if self.heightTextInterval and self.heightTextInterval.isPlaying(): self.heightTextInterval.finish() self.timer.stop() DistributedPartyActivity.unload(self) taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask')) taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask')) self.ignoreAll() del self.heightTextInterval del self.beginRoundInterval del self.hopOnAnim del self.hopOffAnim del self.flashTextInterval if hasattr(self, 'beanAnims'): self.cleanupJellyBeans() self.quitEarlyButton.destroy() del self.quitEarlyButton del self.gui del self.activityFSM del self.animFSM return def setBestHeightInfo(self, toonName, height): self.bestHeightInfo = (toonName, height) DistributedPartyTrampolineActivity.notify.debug('%s has the best height of %d' % (toonName, height)) if height > 0: self.setSignNote(TTLocalizer.PartyTrampolineBestHeight % self.bestHeightInfo) else: self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet) def leaveTrampoline(self): if self.toon != None and self.toon.doId == base.localAvatar.doId: self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp) self.leavingTrampoline = True self.timer.reset() self.trampB = self.leavingTrampB self.ignore('control') self.quitEarlyButton.stash() self.gui.hide() return def requestAnim(self, request): self.animFSM.request(request) def b_requestAnim(self, request): self.requestAnim(request) self.sendUpdate('requestAnim', [request]) def requestAnimEcho(self, request): if self.toon != None and self.toon.doId != base.localAvatar.doId: self.requestAnim(request) return def removeBeans(self, beansToRemove): for i in beansToRemove: height, bean, guiBean, beanAnim = self.beanDetails[i] guiBean.stash() if i in self.beansToCollect: self.beansToCollect.remove(i) else: self.notify.warning('removeBeans avoided a crash, %d not in self.beansToCollect' % i) self.poofBean(bean, beanAnim) def b_removeBeans(self, beansToRemove): self.removeBeans(beansToRemove) self.sendUpdate('removeBeans', [beansToRemove]) def removeBeansEcho(self, beansToRemove): if self.toon != None and self.toon.doId != base.localAvatar.doId: self.removeBeans(beansToRemove) return def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny) base.cr.playGame.getPlace().fsm.request('walk') def exitRequestDenied(self, reason): DistributedPartyActivity.exitRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny) def setState(self, newState, timestamp): DistributedPartyTrampolineActivity.notify.debug('setState( newState=%s, ... )' % newState) DistributedPartyActivity.setState(self, newState, timestamp) self.activityFSM.request(newState) def startIdle(self): DistributedPartyTrampolineActivity.notify.debug('startIdle') def finishIdle(self): DistributedPartyTrampolineActivity.notify.debug('finishIdle') def startRules(self): DistributedPartyTrampolineActivity.notify.debug('startRules') if self.doJellyBeans: self.setupJellyBeans() if self.toon != None and self.toon.doId == base.localAvatar.doId: self.acquireToon() return def startActive(self): DistributedPartyTrampolineActivity.notify.debug('startActive') if self.toon != None and self.toon.doId == base.localAvatar.doId: base.setCellsActive(base.bottomCells, True) self.accept('arrow_left', self.onLeft) self.accept('arrow_left-up', self.onLeftUp) self.accept('arrow_right', self.onRight) self.accept('arrow_right-up', self.onRightUp) self.beginRoundInterval = Sequence(Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady), Wait(1.2), Func(self.flashMessage, TTLocalizer.PartyTrampolineGo), Func(self.beginRound)) self.beginRoundInterval.start() return def finishActive(self): DistributedPartyTrampolineActivity.notify.debug('finishActive') if self.doJellyBeans: self.cleanupJellyBeans() def setupJellyBeans(self): self.beanAnims = [] self.beansToCollect = [] self.beanDetails = [] self.numBeansCollected = 0 for i in xrange(self.numJellyBeans): bean = self.beans[i] guiBean = self.guiBeans[i] height = self.jellyBeanPositions[i] color = random.choice(self.jellyBeanColors) bean.find('**/jellybean').setColor(color) if self.toon.doId == base.localAvatar.doId: bean.setAlphaScale(1.0) else: bean.setAlphaScale(0.5) guiBean.setColor(color) bean.setZ(height + self.toon.getHeight() + self.beanOffset) guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset) bean.setH(0.0) bean.unstash() guiBean.unstash() beanAnim = bean.hprInterval(1.5, VBase3((i % 2 * 2 - 1) * 360.0, 0.0, 0.0)) beanAnim.loop() self.beanAnims.append(beanAnim) self.beanDetails.append((height, bean, guiBean, beanAnim)) self.beansToCollect = range(self.numJellyBeans) def cleanupJellyBeans(self): for bean in self.beans: bean.stash() for guiBean in self.guiBeans: guiBean.stash() if hasattr(self, 'beanAnims'): for beanAnim in self.beanAnims: beanAnim.finish() del self.beanAnims del self.beansToCollect def beginRound(self): base.playSfx(self.whistleSound) self.timer.setTime(PartyGlobals.TrampolineDuration) self.timer.countdown(PartyGlobals.TrampolineDuration) self.timer.show() self.gui.show() self.quitEarlyButton.unstash() self.notify.debug('Accepting contorl') self.accept('control', self.onJump) self.notify.debug('setting simulate step to true') self.doSimulateStep = True def acquireToon(self): self.toon.disableSmartCameraViews() self.toon.stopUpdateSmartCamera() camera.wrtReparentTo(render) self.toon.dropShadow.reparentTo(hidden) self.toon.startPosHprBroadcast(period=0.2) self.toonAcceleration = 0.0 self.toonVelocity = 0.0 self.topHeight = 0.0 self.trampB = self.normalTrampB self.leavingTrampoline = False self.hopOnAnim = Sequence(Func(self.toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, Point3(0.0, 0.0, self.trampHeight), 5.0, self.tramp), Func(self.postHopOn)) self.hopOnAnim.start() def postHopOn(self): self.toon.setH(self.toon.getH() + 90.0) self.toon.dropShadow.reparentTo(self.surface) self.timeLeftToSimulate = 0.0 self.doSimulateStep = False taskMgr.add(self.updateTask, self.uniqueName('TrampolineActivity.updateTask')) base.setCellsActive(base.leftCells, False) base.setCellsActive(base.bottomCells, False) DistributedPartyActivity.startRules(self) def releaseToon(self): self._hideFlashMessage() self.ignore('arrow_left') self.ignore('arrow_left-up') self.ignore('arrow_right') self.ignore('arrow_right-up') taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask')) self.hopOffAnim = Sequence(self.toon.hprInterval(0.5, VBase3(-90.0, 0.0, 0.0), other=self.tramp), Func(self.toon.b_setAnimState, 'jump', 1.0), Func(self.toon.dropShadow.reparentTo, hidden), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0, self.tramp), Func(self.postHopOff)) self.hopOffAnim.start() def postHopOff(self): base.setCellsActive(base.leftCells, True) self.timer.stop() self.timer.hide() self.toon.dropShadow.reparentTo(self.toon.getShadowJoint()) self.toon.dropShadow.setAlphaScale(1.0) self.toon.dropShadow.setScale(1.0) self.b_requestAnim('Off') camera.reparentTo(base.localAvatar) base.localAvatar.startUpdateSmartCamera() base.localAvatar.enableSmartCameraViews() base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex) place = base.cr.playGame.getPlace() if self.doJellyBeans: self.sendUpdate('awardBeans', [self.numBeansCollected, int(self.topHeight)]) if int(self.topHeight) > self.bestHeightInfo[1]: self.sendUpdate('reportHeightInformation', [int(self.topHeight)]) self.d_toonExitDemand() def onTrampolineTrigger(self, collEntry): if self.activityFSM.state == 'Idle' and self.toon == None and base.cr.playGame.getPlace().fsm.getCurrentState().getName() == 'walk': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() else: self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied, duration=2.0) return def onJump(self): self.notify.debug('got onJump') if self.toon != None and self.toon.getZ() < self.trampHeight: self.toonJumped = True self.b_requestAnim('Jump') else: self.notify.debug('z is less than tramp height') return def onLeft(self): self.turnLeft = True def onLeftUp(self): self.turnLeft = False def onRight(self): self.turnRight = True def onRightUp(self): self.turnRight = False def handleToonJoined(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonJoined') self.toon = self.getAvatar(toonId) if self.toon != None and not self.toon.isEmpty(): self.oldJumpSquatPlayRate = self.toon.getPlayRate('jump-squat') self.oldJumpLandPlayRate = self.toon.getPlayRate('jump-land') self.toon.setPlayRate(2.5, 'jump-squat') self.toon.setPlayRate(2.0, 'jump-land') self.turnLeft = False self.turnRight = False self.activityFSM.request('Rules') if self.toon.doId != base.localAvatar.doId: taskMgr.add(self.remoteUpdateTask, self.uniqueName('TrampolineActivity.remoteUpdateTask')) else: self.notify.warning('handleToonJoined could not get toon %d' % toonId) return def handleToonExited(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonExited') if self.toon != None: if self.toon.doId != base.localAvatar.doId: taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask')) self.surface.setZ(self.trampHeight) self.toon.setPlayRate(self.oldJumpSquatPlayRate, 'jump-squat') self.toon.setPlayRate(self.oldJumpLandPlayRate, 'jump-land') self.toon = None return def handleToonDisabled(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonDisabled') DistributedPartyTrampolineActivity.notify.debug('avatar ' + str(toonId) + ' disabled') if base.localAvatar.doId == toonId: self.releaseToon() def handleRulesDone(self): self.sendUpdate('toonReady') self.finishRules() def getTitle(self): if self.doJellyBeans: return TTLocalizer.PartyTrampolineJellyBeanTitle elif self.doTricks: return TTLocalizer.PartyTrampolineTricksTitle else: return DistributedPartyActivity.getTitle(self) def getInstructions(self): return TTLocalizer.PartyTrampolineActivityInstructions def updateTask(self, task): z = self.toon.getZ() dt = globalClock.getDt() if self.doSimulateStep: self.timeLeftToSimulate += dt while self.timeLeftToSimulate >= self.stepDT: z, a = self.simulateStep(z) self.timeLeftToSimulate -= self.stepDT self.toon.setZ(z) if z <= self.trampHeight: self.surface.setZ(z) else: self.surface.setZ(self.trampHeight) self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor) if self.turnLeft: self.toon.setH(self.toon.getH() + self.turnFactor * dt) if self.turnRight: self.toon.setH(self.toon.getH() - self.turnFactor * dt) currentPos = base.camera.getPos(self.toon) vec = self.targetCameraPos - currentPos newPos = currentPos + vec * (dt * self.cameraSpeed) base.camera.setPos(self.toon, newPos) base.camera.lookAt(self.toon) #if z > self.trampHeight: # heightFactor = 1.0 - min(1.0, (z - self.trampHeight) / self.dropShadowCutoff) # self.toon.dropShadow.setAlphaScale(heightFactor) # self.toon.dropShadow.setScale(max(0.1, heightFactor)) #else: # self.toon.dropShadow.setAlphaScale(1.0) # self.toon.dropShadow.setScale(1.0) if self.leavingTrampoline and z < self.trampHeight and abs(a) < 0.1: self.releaseToon() return Task.cont def simulateStep(self, z): if z >= self.trampHeight: a = self.g self.toonJumped = False else: a = self.g + self.trampK * (self.trampHeight - z) - self.trampB * self.toonVelocity if self.toonJumped: if self.lastPeak > self.earlyJumpThreshold or self.toonVelocity >= -300000.0: a += self.jumpBoost if self.lastPeak < self.beginningBoostThreshold: a += self.beginningBoost lastVelocity = self.toonVelocity self.toonVelocity += a * self.stepDT if lastVelocity > 0.0 and self.toonVelocity <= 0.0: topOfJump = True bottomOfJump = False elif lastVelocity < 0.0 and self.toonVelocity >= 0.0: topOfJump = False bottomOfJump = True else: topOfJump = False bottomOfJump = False newZ = z + self.toonVelocity * self.stepDT if newZ > self.topHeight: self.topHeight = newZ if self.doJellyBeans: self.collectJellyBeans(newZ) if topOfJump: self.lastPeak = newZ if newZ >= self.minHeightForText: self.heightTextInterval.start() if topOfJump: if newZ > self.trampHeight + 20.0: self.b_requestAnim('Falling') elif self.animFSM.state == 'Jump': self.b_requestAnim('Falling') if newZ <= self.trampHeight and z > self.trampHeight: if self.animFSM.state == 'Falling': self.b_requestAnim('Land') elif self.animFSM.state != 'Neutral': self.b_requestAnim('Neutral') if bottomOfJump and a > self.boingThreshold: base.playSfx(self.boingSound) return (newZ, a) def collectJellyBeans(self, z): beansToRemove = [] for i in self.beansToCollect: height = self.beanDetails[i][0] if height <= z: beansToRemove.append(i) if len(beansToRemove) > 0: base.playSfx(self.jellyBeanSound) self.numBeansCollected += len(beansToRemove) self.b_removeBeans(beansToRemove) def remoteUpdateTask(self, task): if self.toon != None and not self.toon.isEmpty(): z = self.toon.getZ() if z <= self.trampHeight: self.surface.setZ(z) else: self.surface.setZ(self.trampHeight) return Task.cont def poofBean(self, bean, beanAnim): if bean == None: self.notify.warning('poofBean, returning immediately as bean is None') return if bean.isEmpty(): self.notify.warning('poofBean, returning immediately as bean is empty') return currentAlpha = bean.getColorScale()[3] currentScale = bean.getScale() poofAnim = Sequence(Parallel(LerpFunc(bean.setAlphaScale, fromData=currentAlpha, toData=0.0, duration=0.25), LerpFunc(bean.setScale, fromData=currentScale, toData=currentScale * 5.0, duration=0.25)), Func(bean.stash), Func(beanAnim.finish), Func(bean.setAlphaScale, currentAlpha), Func(bean.setScale, currentScale)) poofAnim.start() return def _showFlashMessage(self, message): if self.isDisabled(): return if self.flashTextInterval is not None and self.flashTextInterval.isPlaying(): self.flashTextInterval.finish() self.flashText.setText(message) self.flashText.setAlphaScale(1.0) self.flashText.unstash() return def _hideFlashMessage(self, duration = 0.0): if self.isDisabled(): pass self.flashTextInterval = Sequence(Wait(duration), LerpFunc(self.flashText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), Func(self.flashText.stash)) self.flashTextInterval.start() def flashMessage(self, message, duration = 0.5): self._showFlashMessage(message) self._hideFlashMessage(duration)
class DistributedLawbotCannon(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLawbotCannon') LOCAL_CANNON_MOVE_TASK = 'localCannonMoveTask' FIRE_KEY = 'control' UP_KEY = 'arrow_up' DOWN_KEY = 'arrow_down' LEFT_KEY = 'arrow_left' RIGHT_KEY = 'arrow_right' HIT_GROUND = 0 def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.index = None self.avId = 0 self.av = None self.localToonShooting = 0 self.cannonsActive = 0 self.cannonLocation = None self.cannonPostion = None self.cannon = None self.madeGui = 0 self.jurorToon = None self.toonModel = None self.toonHead = None self.toonScale = None self.dustCloud = None self.hitBumper = 0 self.hitTarget = 0 self.lastPos = Vec3(0, 0, 0) self.lastVel = Vec3(0, 0, 0) self.vel = Vec3(0, 0, 0) self.landingPos = Vec3(0, 0, 0) self.t = 0 self.lastT = 0 self.deltaT = 0 self.hitTrack = None self.flyColNode = None self.flyColNodePath = None self.localAvId = base.localAvatar.doId self.model_Created = 0 return def disable(self): taskMgr.remove(self.uniqueName('fireCannon')) taskMgr.remove(self.uniqueName('shootTask')) self.__stopFlyTask(self.avId) taskMgr.remove(self.uniqueName('flyTask')) self.ignoreAll() self.setMovie(CannonGlobals.CANNON_MOVIE_CLEAR, 0, 0) self.nodePath.detachNode() self.__unmakeGui() if self.hitTrack: self.hitTrack.finish() del self.hitTrack self.hitTrack = None DistributedObject.DistributedObject.disable(self) return def delete(self): self.offstage() self.unload() DistributedObject.DistributedObject.delete(self) def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) self.boss.cannons[self.index] = self def generateInit(self): DistributedObject.DistributedObject.generateInit(self) self.nodePath = NodePath(self.uniqueName('Cannon')) self.load() self.activateCannons() def setPosHpr(self, x, y, z, h, p, r): self.nodePath.setPosHpr(x, y, z, h, p, r) def setBossCogId(self, bossCogId): self.bossCogId = bossCogId self.boss = base.cr.doId2do[bossCogId] def getSphereRadius(self): return 1.5 def getParentNodePath(self): return render def setIndex(self, index): self.index = index def load(self): self.cannon = loader.loadModel('phase_4/models/minigames/toon_cannon') self.collSphere = CollisionSphere(0, 0, 0, self.getSphereRadius()) self.dustCloud = DustCloud.DustCloud(render) self.dustCloud.setBillboardPointEye() self.collSphere.setTangible(1) self.collNode = CollisionNode(self.uniqueName('CannonSphere')) self.collNode.setCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.nodePath.attachNewNode(self.collNode) self.cannon.reparentTo(self.nodePath) self.kartColNode = CollisionNode(self.uniqueName('KartColNode')) self.kartNode = self.nodePath.attachNewNode(self.kartColNode) self.sndCannonMove = base.loadSfx('phase_4/audio/sfx/MG_cannon_adjust.ogg') self.sndCannonFire = base.loadSfx('phase_4/audio/sfx/MG_cannon_fire_alt.ogg') self.sndHitGround = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg') self.sndHitChair = base.loadSfx('phase_11/audio/sfx/LB_toon_jury.ogg') self.cannon.hide() self.flashingLabel = None return def unload(self): if self.cannon: self.cannon.removeNode() del self.cannon if self.dustCloud != None: self.dustCloud.destroy() del self.dustCloud del self.sndCannonMove del self.sndCannonFire del self.sndHitGround del self.sndHitChair if self.av: self.__resetToon(self.av) self.av.loop('neutral') self.av.setPlayRate(1.0, 'run') if self.toonHead != None: self.toonHead.stopBlink() self.toonHead.stopLookAroundNow() self.toonHead.delete() del self.toonHead if self.toonModel != None: self.toonModel.removeNode() del self.toonModel if self.jurorToon != None: self.jurorToon.delete() del self.jurorToon del self.toonScale return def activateCannons(self): if not self.cannonsActive: self.cannonsActive = 1 self.onstage() self.nodePath.reparentTo(self.getParentNodePath()) self.accept(self.uniqueName('enterCannonSphere'), self.__handleEnterSphere) def onstage(self): self.__createCannon() self.cannon.reparentTo(self.nodePath) self.dustCloud.reparentTo(render) def offstage(self): if self.cannon: self.cannon.reparentTo(hidden) if self.dustCloud: self.dustCloud.reparentTo(hidden) self.dustCloud.stop() def __createCannon(self): self.barrel = self.cannon.find('**/cannon') self.cannonLocation = Point3(0, 0, 0.025) self.cannonPosition = [0, CANNON_ANGLE_MIN] self.cannon.setPos(self.cannonLocation) self.__updateCannonPosition(self.avId) def updateCannonPosition(self, avId, zRot, angle): if avId != self.localAvId: self.cannonPosition = [zRot, angle] self.__updateCannonPosition(avId) def __updateCannonPosition(self, avId): self.cannon.setHpr(self.cannonPosition[0], 0.0, 0.0) self.barrel.setHpr(0.0, self.cannonPosition[1], 0.0) maxP = 90 newP = self.barrel.getP() yScale = 1 - 0.5 * float(newP) / maxP shadow = self.cannon.find('**/square_drop_shadow') shadow.setScale(1, yScale, 1) def __handleEnterSphere(self, collEntry): self.d_requestEnter() def d_requestEnter(self): self.sendUpdate('requestEnter', []) def setMovie(self, mode, avId, extraInfo): wasLocalToon = self.localToonShooting self.avId = avId if mode == CannonGlobals.CANNON_MOVIE_CLEAR: self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_LANDED: self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_FORCE_EXIT: self.exitCannon(self.avId) self.setLanded() elif mode == CannonGlobals.CANNON_MOVIE_LOAD: if self.avId == base.localAvatar.doId: self.cannonBallsLeft = extraInfo base.cr.playGame.getPlace().setState('crane') base.localAvatar.setTeleportAvailable(0) self.localToonShooting = 1 self.__makeGui() camera.reparentTo(self.barrel) camera.setPos(0.5, -2, 2.5) camera.setHpr(0, 0, 0) self.boss.toonEnteredCannon(self.avId, self.index) if self.cr.doId2do.has_key(self.avId): self.av = self.cr.doId2do[self.avId] self.acceptOnce(self.av.uniqueName('disable'), self.__avatarGone) self.av.loop('neutral') self.av.stopSmooth() self.__destroyToonModels() self.__createToonModels() self.av.setPosHpr(3, 0, 0, 90, 0, 0) self.av.reparentTo(self.cannon) else: self.notify.warning('Unknown avatar %d in cannon %d' % (self.avId, self.doId)) else: self.notify.warning('unhandled case, mode = %d' % mode) def __avatarGone(self): self.setMovie(CannonGlobals.CANNON_MOVIE_CLEAR, 0, 0) def __makeGui(self): if self.madeGui: return NametagGlobals.setMasterArrowsOn(0) guiModel = 'phase_4/models/gui/cannon_game_gui' cannonGui = loader.loadModel(guiModel) self.aimPad = DirectFrame(image=cannonGui.find('**/CannonFire_PAD'), relief=None, pos=(0.7, 0, -0.553333), scale=0.8) cannonGui.removeNode() self.fireButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Fire_Btn_UP'), (guiModel, '**/Fire_Btn_DN'), (guiModel, '**/Fire_Btn_RLVR')), relief=None, pos=(0.0115741, 0, 0.00505051), scale=1.0, command=self.__firePressed) self.upButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0115741, 0, 0.221717)) self.downButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0136112, 0, -0.210101), image_hpr=(0, 0, 180)) self.leftButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(-0.199352, 0, -0.000505269), image_hpr=(0, 0, -90)) self.rightButton = DirectButton(parent=self.aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.219167, 0, -0.00101024), image_hpr=(0, 0, 90)) guiClose = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') cannonBallText = '%d/%d' % (self.cannonBallsLeft, ToontownGlobals.LawbotBossCannonBallMax) self.cannonBallLabel = DirectLabel(parent=self.aimPad, text=cannonBallText, text_fg=VBase4(1, 1, 1, 1), text_align=TextNode.ACenter, relief=None, pos=(0.475, 0.0, -0.35), scale=0.25) if self.cannonBallsLeft < 5: if self.flashingLabel: self.flashingLabel.stop() flashingTrack = Sequence() for i in range(10): flashingTrack.append(LerpColorScaleInterval(self.cannonBallLabel, 0.5, VBase4(1, 0, 0, 1))) flashingTrack.append(LerpColorScaleInterval(self.cannonBallLabel, 0.5, VBase4(1, 1, 1, 1))) self.flashingLabel = flashingTrack self.flashingLabel.start() self.aimPad.setColor(1, 1, 1, 0.9) def bindButton(button, upHandler, downHandler): button.bind(DGG.B1PRESS, lambda x, handler = upHandler: handler()) button.bind(DGG.B1RELEASE, lambda x, handler = downHandler: handler()) bindButton(self.upButton, self.__upPressed, self.__upReleased) bindButton(self.downButton, self.__downPressed, self.__downReleased) bindButton(self.leftButton, self.__leftPressed, self.__leftReleased) bindButton(self.rightButton, self.__rightPressed, self.__rightReleased) self.__enableAimInterface() self.madeGui = 1 return def __unmakeGui(self): self.notify.debug('__unmakeGui') if not self.madeGui: return if self.flashingLabel: self.flashingLabel.finish() self.flashingLabel = None NametagGlobals.setMasterArrowsOn(1) self.__disableAimInterface() self.upButton.unbind(DGG.B1PRESS) self.upButton.unbind(DGG.B1RELEASE) self.downButton.unbind(DGG.B1PRESS) self.downButton.unbind(DGG.B1RELEASE) self.leftButton.unbind(DGG.B1PRESS) self.leftButton.unbind(DGG.B1RELEASE) self.rightButton.unbind(DGG.B1PRESS) self.rightButton.unbind(DGG.B1RELEASE) self.aimPad.destroy() del self.aimPad del self.fireButton del self.upButton del self.downButton del self.leftButton del self.rightButton self.madeGui = 0 return def __enableAimInterface(self): self.aimPad.show() self.accept(self.FIRE_KEY, self.__fireKeyPressed) self.accept(self.UP_KEY, self.__upKeyPressed) self.accept(self.DOWN_KEY, self.__downKeyPressed) self.accept(self.LEFT_KEY, self.__leftKeyPressed) self.accept(self.RIGHT_KEY, self.__rightKeyPressed) self.__spawnLocalCannonMoveTask() def __disableAimInterface(self): self.aimPad.hide() self.ignore(self.FIRE_KEY) self.ignore(self.UP_KEY) self.ignore(self.DOWN_KEY) self.ignore(self.LEFT_KEY) self.ignore(self.RIGHT_KEY) self.ignore(self.FIRE_KEY + '-up') self.ignore(self.UP_KEY + '-up') self.ignore(self.DOWN_KEY + '-up') self.ignore(self.LEFT_KEY + '-up') self.ignore(self.RIGHT_KEY + '-up') self.__killLocalCannonMoveTask() def __fireKeyPressed(self): self.ignore(self.FIRE_KEY) self.accept(self.FIRE_KEY + '-up', self.__fireKeyReleased) self.__firePressed() def __upKeyPressed(self): self.ignore(self.UP_KEY) self.accept(self.UP_KEY + '-up', self.__upKeyReleased) self.__upPressed() def __downKeyPressed(self): self.ignore(self.DOWN_KEY) self.accept(self.DOWN_KEY + '-up', self.__downKeyReleased) self.__downPressed() def __leftKeyPressed(self): self.ignore(self.LEFT_KEY) self.accept(self.LEFT_KEY + '-up', self.__leftKeyReleased) self.__leftPressed() def __rightKeyPressed(self): self.ignore(self.RIGHT_KEY) self.accept(self.RIGHT_KEY + '-up', self.__rightKeyReleased) self.__rightPressed() def __fireKeyReleased(self): self.ignore(self.FIRE_KEY + '-up') self.accept(self.FIRE_KEY, self.__fireKeyPressed) def __leftKeyReleased(self): self.ignore(self.LEFT_KEY + '-up') self.accept(self.LEFT_KEY, self.__leftKeyPressed) self.__leftReleased() def __rightKeyReleased(self): self.ignore(self.RIGHT_KEY + '-up') self.accept(self.RIGHT_KEY, self.__rightKeyPressed) self.__rightReleased() def __upKeyReleased(self): self.ignore(self.UP_KEY + '-up') self.accept(self.UP_KEY, self.__upKeyPressed) self.__upReleased() def __downKeyReleased(self): self.ignore(self.DOWN_KEY + '-up') self.accept(self.DOWN_KEY, self.__downKeyPressed) self.__downReleased() def __leaveCannon(self): self.notify.warning('__leaveCannon') return self.sendUpdate('requestLeave') def __firePressed(self): self.notify.debug('fire pressed') if not self.boss.state == 'BattleTwo': self.notify.debug('boss is in state=%s, not firing' % self.boss.state) return self.__broadcastLocalCannonPosition() self.__unmakeGui() self.sendUpdate('setCannonLit', [self.cannonPosition[0], self.cannonPosition[1]]) def __upPressed(self): self.notify.debug('up pressed') self.upPressed = self.__enterControlActive(self.upPressed) def __downPressed(self): self.notify.debug('down pressed') self.downPressed = self.__enterControlActive(self.downPressed) def __leftPressed(self): self.notify.debug('left pressed') self.leftPressed = self.__enterControlActive(self.leftPressed) def __rightPressed(self): self.notify.debug('right pressed') self.rightPressed = self.__enterControlActive(self.rightPressed) def __upReleased(self): self.notify.debug('up released') self.upPressed = self.__exitControlActive(self.upPressed) def __downReleased(self): self.notify.debug('down released') self.downPressed = self.__exitControlActive(self.downPressed) def __leftReleased(self): self.notify.debug('left released') self.leftPressed = self.__exitControlActive(self.leftPressed) def __rightReleased(self): self.notify.debug('right released') self.rightPressed = self.__exitControlActive(self.rightPressed) def __enterControlActive(self, control): return control + 1 def __exitControlActive(self, control): return max(0, control - 1) def __spawnLocalCannonMoveTask(self): self.leftPressed = 0 self.rightPressed = 0 self.upPressed = 0 self.downPressed = 0 self.cannonMoving = 0 task = Task(self.__localCannonMoveTask) task.lastPositionBroadcastTime = 0.0 taskMgr.add(task, self.LOCAL_CANNON_MOVE_TASK) def __killLocalCannonMoveTask(self): taskMgr.remove(self.LOCAL_CANNON_MOVE_TASK) if self.cannonMoving: self.sndCannonMove.stop() def __localCannonMoveTask(self, task): pos = self.cannonPosition oldRot = pos[0] oldAng = pos[1] rotVel = 0 if self.leftPressed: rotVel += CANNON_ROTATION_VEL if self.rightPressed: rotVel -= CANNON_ROTATION_VEL pos[0] += rotVel * globalClock.getDt() if pos[0] < CANNON_ROTATION_MIN: pos[0] = CANNON_ROTATION_MIN elif pos[0] > CANNON_ROTATION_MAX: pos[0] = CANNON_ROTATION_MAX angVel = 0 if self.upPressed: angVel += CANNON_ANGLE_VEL if self.downPressed: angVel -= CANNON_ANGLE_VEL pos[1] += angVel * globalClock.getDt() if pos[1] < CANNON_ANGLE_MIN: pos[1] = CANNON_ANGLE_MIN elif pos[1] > CANNON_ANGLE_MAX: pos[1] = CANNON_ANGLE_MAX if oldRot != pos[0] or oldAng != pos[1]: if self.cannonMoving == 0: self.cannonMoving = 1 base.playSfx(self.sndCannonMove, looping=1) self.__updateCannonPosition(self.localAvId) if task.time - task.lastPositionBroadcastTime > CANNON_MOVE_UPDATE_FREQ: task.lastPositionBroadcastTime = task.time self.__broadcastLocalCannonPosition() elif self.cannonMoving: self.cannonMoving = 0 self.sndCannonMove.stop() self.__broadcastLocalCannonPosition() return Task.cont def __broadcastLocalCannonPosition(self): self.sendUpdate('setCannonPosition', [self.cannonPosition[0], self.cannonPosition[1]]) def __updateCannonPosition(self, avId): self.cannon.setHpr(self.cannonPosition[0], 0.0, 0.0) self.barrel.setHpr(0.0, self.cannonPosition[1], 0.0) maxP = 90 newP = self.barrel.getP() yScale = 1 - 0.5 * float(newP) / maxP shadow = self.cannon.find('**/square_drop_shadow') shadow.setScale(1, yScale, 1) def __createToonModels(self): self.model_Created = 1 self.jurorToon = NPCToons.createLocalNPC(ToontownGlobals.LawbotBossBaseJurorNpcId + self.index) self.toonScale = self.jurorToon.getScale() jurorToonParent = render.attachNewNode('toonOriginChange') self.jurorToon.wrtReparentTo(jurorToonParent) self.jurorToon.setPosHpr(0, 0, -(self.jurorToon.getHeight() / 2.0), 0, -90, 0) self.toonModel = jurorToonParent self.toonHead = ToonHead.ToonHead() self.toonHead.setupHead(self.jurorToon.style) self.toonHead.reparentTo(hidden) self.__loadToonInCannon() def __destroyToonModels(self): if (0): self.av.dropShadow.show() if self.dropShadow != None: self.dropShadow.removeNode() self.dropShadow = None self.hitBumper = 0 self.hitTarget = 0 self.angularVel = 0 self.vel = Vec3(0, 0, 0) self.lastVel = Vec3(0, 0, 0) self.lastPos = Vec3(0, 0, 0) self.landingPos = Vec3(0, 0, 0) self.t = 0 self.lastT = 0 self.deltaT = 0 self.av = None self.lastWakeTime = 0 self.localToonShooting = 0 if self.toonHead != None: self.toonHead.reparentTo(hidden) self.toonHead.stopBlink() self.toonHead.stopLookAroundNow() self.toonHead = None if self.toonModel != None: self.toonModel.removeNode() self.toonModel = None if self.jurorToon != None: self.jurorToon.delete() self.jurorToon = None self.model_Created = 0 return def __loadToonInCannon(self): self.toonModel.reparentTo(hidden) self.toonHead.startBlink() self.toonHead.startLookAround() self.toonHead.reparentTo(self.barrel) self.toonHead.setPosHpr(0, 6, 0, 0, -45, 0) sc = self.toonScale self.toonHead.setScale(render, sc[0], sc[1], sc[2]) def exitCannon(self, avId): self.__unmakeGui() if self.avId == avId: self.av.reparentTo(render) self.__resetToonToCannon(self.av) def __resetToonToCannon(self, avatar): pos = None if not avatar: if self.avId: avatar = base.cr.doId2do.get(self.avId, None) if avatar: if hasattr(self, 'cannon') and self.cannon: avatar.reparentTo(self.cannon) avatar.setPosHpr(3, 0, 0, 90, 0, 0) avatar.wrtReparentTo(render) self.__resetToon(avatar) return def __resetToon(self, avatar, pos = None): if avatar: self.__stopCollisionHandler(avatar) self.__setToonUpright(avatar, pos) if self.localToonShooting: self.notify.debug('toon setting position to %s' % pos) if pos: base.localAvatar.setPos(pos) camera.reparentTo(avatar) camera.setPos(self.av.cameraPositions[0][0]) place = base.cr.playGame.getPlace() if place: place.setState('finalBattle') self.b_setLanded() def __stopCollisionHandler(self, avatar): if avatar: avatar.loop('neutral') if self.flyColNode: self.flyColNode = None if avatar == base.localAvatar: avatar.collisionsOn() self.flyColSphere = None if self.flyColNodePath: base.cTrav.removeCollider(self.flyColNodePath) self.flyColNodePath.removeNode() self.flyColNodePath = None self.handler = None return def __setToonUpright(self, avatar, pos = None): if avatar: if not pos: pos = avatar.getPos(render) avatar.setPos(render, pos) avatar.loop('neutral') def b_setLanded(self): self.d_setLanded() def d_setLanded(self): if self.localToonShooting: self.sendUpdate('setLanded', []) def setLanded(self): self.removeAvFromCannon() def removeAvFromCannon(self): if self.av != None: self.__stopCollisionHandler(self.av) self.av.resetLOD() place = base.cr.playGame.getPlace() if self.av == base.localAvatar: if place: place.setState('finalBattle') self.av.loop('neutral') self.av.setPlayRate(1.0, 'run') if self.av.getParent().getName() == 'toonOriginChange': self.av.wrtReparentTo(render) self.__setToonUpright(self.av) if self.av == base.localAvatar: self.av.startPosHprBroadcast() self.av.startSmooth() self.av.setScale(1, 1, 1) self.ignore(self.av.uniqueName('disable')) self.__destroyToonModels() return def setCannonWillFire(self, avId, fireTime, zRot, angle, timestamp): self.notify.debug('setCannonWillFire: ' + str(avId) + ': zRot=' + str(zRot) + ', angle=' + str(angle) + ', time=' + str(fireTime)) if not self.model_Created: self.notify.warning("We walked into the zone mid-flight, so we won't see it") return self.cannonPosition[0] = zRot self.cannonPosition[1] = angle self.__updateCannonPosition(avId) task = Task(self.__fireCannonTask) task.avId = avId ts = globalClockDelta.localElapsedTime(timestamp) task.fireTime = fireTime - ts if task.fireTime < 0.0: task.fireTime = 0.0 taskMgr.add(task, self.taskName('fireCannon')) def __fireCannonTask(self, task): launchTime = task.fireTime avId = task.avId if self.toonHead == None or not self.boss.state == 'BattleTwo': return Task.done startPos, startHpr, startVel, trajectory, timeOfImpact, hitWhat = self.__calcFlightResults(avId, launchTime) self.notify.debug('start position: ' + str(startPos)) self.notify.debug('start velocity: ' + str(startVel)) self.notify.debug('time of launch: ' + str(launchTime)) self.notify.debug('time of impact: ' + str(timeOfImpact)) self.notify.debug('location of impact: ' + str(trajectory.getPos(timeOfImpact))) head = self.toonHead head.stopBlink() head.stopLookAroundNow() head.reparentTo(hidden) juror = self.toonModel juror.reparentTo(render) juror.setPos(startPos) barrelHpr = self.barrel.getHpr(render) juror.setHpr(startHpr) self.jurorToon.loop('swim') self.jurorToon.setPosHpr(0, 0, -(self.jurorToon.getHeight() / 2.0), 0, 0, 0) info = {} info['avId'] = avId info['trajectory'] = trajectory info['launchTime'] = launchTime info['timeOfImpact'] = timeOfImpact info['hitWhat'] = hitWhat info['toon'] = self.toonModel info['hRot'] = self.cannonPosition[0] info['haveWhistled'] = 0 info['maxCamPullback'] = CAMERA_PULLBACK_MIN if self.localToonShooting: camera.reparentTo(juror) camera.setP(45.0) camera.setZ(-10.0) self.flyColSphere = CollisionSphere(0, 0, self.av.getHeight() / 2.0, 1.0) self.flyColNode = CollisionNode(self.uniqueName('flySphere')) self.flyColNode.setCollideMask(ToontownGlobals.WallBitmask | ToontownGlobals.FloorBitmask | ToontownGlobals.PieBitmask) self.flyColNode.addSolid(self.flyColSphere) self.flyColNodePath = self.jurorToon.attachNewNode(self.flyColNode) self.flyColNodePath.setColor(1, 0, 0, 1) self.handler = CollisionHandlerEvent() self.handler.setInPattern(self.uniqueName('cannonHit')) base.cTrav.addCollider(self.flyColNodePath, self.handler) self.accept(self.uniqueName('cannonHit'), self.__handleCannonHit) shootTask = Task(self.__shootTask, self.taskName('shootTask')) flyTask = Task(self.__flyTask, self.taskName('flyTask')) shootTask.info = info flyTask.info = info seqTask = Task.sequence(shootTask, flyTask) taskMgr.add(seqTask, self.taskName('flyingToon') + '-' + str(avId)) self.acceptOnce(self.uniqueName('stopFlyTask'), self.__stopFlyTask) return Task.done def __toRadians(self, angle): return angle * 2.0 * math.pi / 360.0 def __toDegrees(self, angle): return angle * 360.0 / (2.0 * math.pi) def __calcFlightResults(self, avId, launchTime): head = self.toonHead startPos = head.getPos(render) startHpr = head.getHpr(render) hpr = self.barrel.getHpr(render) rotation = self.__toRadians(hpr[0]) angle = self.__toRadians(hpr[1]) horizVel = INITIAL_VELOCITY * math.cos(angle) xVel = horizVel * -math.sin(rotation) yVel = horizVel * math.cos(rotation) zVel = INITIAL_VELOCITY * math.sin(angle) startVel = Vec3(xVel, yVel, zVel) trajectory = Trajectory.Trajectory(launchTime, startPos, startVel) self.trajectory = trajectory timeOfImpact, hitWhat = self.__calcToonImpact(trajectory) return startPos, startHpr, startVel, trajectory, 3 * timeOfImpact, hitWhat def __calcToonImpact(self, trajectory): t_groundImpact = trajectory.checkCollisionWithGround(GROUND_PLANE_MIN) if t_groundImpact >= trajectory.getStartTime(): return (t_groundImpact, self.HIT_GROUND) else: self.notify.error('__calcToonImpact: toon never impacts ground?') return (0.0, self.HIT_GROUND) def __handleCannonHit(self, collisionEntry): if self.av == None or self.flyColNode == None: return interPt = collisionEntry.getSurfacePoint(render) hitNode = collisionEntry.getIntoNode().getName() fromNodePath = collisionEntry.getFromNodePath() intoNodePath = collisionEntry.getIntoNodePath() ignoredHits = ['NearBoss'] for nodeName in ignoredHits: if hitNode == nodeName: return self.__stopFlyTask(self.avId) self.__stopCollisionHandler(self.jurorToon) if self.localToonShooting: camera.wrtReparentTo(render) pos = interPt hpr = self.jurorToon.getHpr() track = Sequence() if self.localToonShooting: pass chairlist = ['trigger-chair'] for index in range(len(ToontownGlobals.LawbotBossChairPosHprs)): chairlist.append('Chair-%s' % index) if hitNode in chairlist: track.append(Func(self.__hitChair, self.jurorToon, pos)) track.append(Wait(1.0)) track.append(Func(self.__setToonUpright, self.av)) if self.av == base.localAvatar: strs = hitNode.split('-') chairNum = int(strs[1]) self.boss.sendUpdate('hitChair', [chairNum, self.index]) else: track.append(Func(self.__hitGround, self.jurorToon, pos)) track.append(Wait(1.0)) track.append(Func(self.__setToonUpright, self.av)) track.append(Func(self.b_setLanded)) if self.localToonShooting: pass if self.hitTrack: self.hitTrack.finish() self.hitTrack = track self.hitTrack.start() return def enterCannonHit(self, collisionEntry): pass def __shootTask(self, task): base.playSfx(self.sndCannonFire) return Task.done def __flyTask(self, task): toon = task.info['toon'] if toon.isEmpty(): self.__resetToonToCannon(self.av) return Task.done curTime = task.time + task.info['launchTime'] t = min(curTime, task.info['timeOfImpact']) self.lastT = self.t self.t = t deltaT = self.t - self.lastT self.deltaT = deltaT if t >= task.info['timeOfImpact']: self.__resetToonToCannon(self.av) return Task.done pos = task.info['trajectory'].getPos(t) toon.setFluidPos(pos) vel = task.info['trajectory'].getVel(t) run = math.sqrt(vel[0] * vel[0] + vel[1] * vel[1]) rise = vel[2] theta = self.__toDegrees(math.atan(rise / run)) toon.setHpr(self.cannon.getH(render), -90 + theta, 0) view = 2 lookAt = task.info['toon'].getPos(render) hpr = task.info['toon'].getHpr(render) if self.localToonShooting: if view == 0: camera.wrtReparentTo(render) camera.lookAt(lookAt) elif view == 1: camera.reparentTo(render) camera.setPos(render, 100, 100, 35.25) camera.lookAt(render, lookAt) elif view == 2: if hpr[1] > -90: camera.setPos(0, 0, -30) if camera.getZ() < lookAt[2]: camera.setZ(render, lookAt[2] + 10) camera.lookAt(Point3(0, 0, 0)) return Task.cont def __stopFlyTask(self, avId): taskMgr.remove(self.taskName('flyingToon') + '-' + str(avId)) def __hitGround(self, avatar, pos, extraArgs = []): hitP = avatar.getPos(render) h = self.barrel.getH(render) avatar.setPos(pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) avatar.setHpr(h, -135, 0) self.dustCloud.setPos(render, pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) self.dustCloud.setScale(0.35) self.dustCloud.play() base.playSfx(self.sndHitGround) avatar.hide() def __hitChair(self, avatar, pos, extraArgs = []): hitP = avatar.getPos(render) h = self.barrel.getH(render) avatar.setPos(pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) avatar.setHpr(h, -135, 0) self.dustCloud.setPos(render, pos[0], pos[1], pos[2] + avatar.getHeight() / 3.0) self.dustCloud.setScale(0.35) self.dustCloud.play() base.playSfx(self.sndHitGround) base.playSfx(self.sndHitChair) avatar.hide() def generateCannonAppearTrack(self, avatar): self.cannon.setScale(0.1) self.cannon.show() kartTrack = Parallel(Sequence(ActorInterval(avatar, 'feedPet'), Func(avatar.loop, 'neutral')), Sequence(Func(self.cannon.reparentTo, avatar.rightHand), Wait(2.1), Func(self.cannon.wrtReparentTo, render), Func(self.cannon.setShear, 0, 0, 0), Parallel(LerpHprInterval(self.cannon, hpr=self.nodePath.getHpr(render), duration=1.2), ProjectileInterval(self.cannon, endPos=self.nodePath.getPos(render), duration=1.2, gravityMult=0.45)), Wait(0.2), Sequence(LerpScaleInterval(self.cannon, scale=Point3(1.1, 1.1, 0.1), duration=0.2), LerpScaleInterval(self.cannon, scale=Point3(0.9, 0.9, 0.1), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 0.1), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 1.1), duration=0.2), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 0.9), duration=0.1), LerpScaleInterval(self.cannon, scale=Point3(1.0, 1.0, 1.0), duration=0.1), Func(self.cannon.wrtReparentTo, self.nodePath)))) return kartTrack
def getDropIval(self, x, y, dropObjName, generation, num): objType = PartyGlobals.Name2DropObjectType[dropObjName] id = (generation, num) dropNode = hidden.attachNewNode('catchDropNode%s' % (id,)) dropNode.setPos(x, y, 0) shadow = self.dropShadow.copyTo(dropNode) shadow.setZ(PartyGlobals.CatchDropShadowHeight) shadow.setColor(1, 1, 1, 1) object = self.getObjModel(dropObjName) object.reparentTo(hidden) if dropObjName in ['watermelon', 'anvil']: objH = object.getH() absDelta = {'watermelon': 12, 'anvil': 15}[dropObjName] delta = (self.randomNumGen.random() * 2.0 - 1.0) * absDelta newH = objH + delta else: newH = self.randomNumGen.random() * 360.0 object.setH(newH) sphereName = 'FallObj%s' % (id,) radius = self.ObjRadius if objType.good: radius *= lerp(1.0, 1.3, 0.5) collSphere = CollisionSphere(0, 0, 0, radius) collSphere.setTangible(0) collNode = CollisionNode(sphereName) collNode.setCollideMask(PartyGlobals.CatchActivityBitmask) collNode.addSolid(collSphere) collNodePath = object.attachNewNode(collNode) collNodePath.hide() if self.ShowObjSpheres: collNodePath.show() catchEventName = 'ltCatch' + sphereName def eatCollEntry(forward, collEntry): forward() self.accept(catchEventName, Functor(eatCollEntry, Functor(self.__handleCatch, id[0], id[1]))) def cleanup(self = self, dropNode = dropNode, id = id, event = catchEventName): self.ignore(event) dropNode.removeNode() duration = objType.fallDuration onscreenDuration = objType.onscreenDuration targetShadowScale = 0.3 if self.trickShadows: intermedScale = targetShadowScale * (self.OffscreenTime / self.BaselineDropDuration) shadowScaleIval = Sequence(LerpScaleInterval(shadow, self.OffscreenTime, intermedScale, startScale=0)) shadowScaleIval.append(LerpScaleInterval(shadow, duration - self.OffscreenTime, targetShadowScale, startScale=intermedScale)) else: shadowScaleIval = LerpScaleInterval(shadow, duration, targetShadowScale, startScale=0) targetShadowAlpha = 0.4 shadowAlphaIval = LerpColorScaleInterval(shadow, self.OffscreenTime, Point4(1, 1, 1, targetShadowAlpha), startColorScale=Point4(1, 1, 1, 0)) shadowIval = Parallel(shadowScaleIval, shadowAlphaIval) if self.useGravity: def setObjPos(t, objType = objType, object = object): z = objType.trajectory.calcZ(t) object.setZ(z) setObjPos(0) dropIval = LerpFunctionInterval(setObjPos, fromData=0, toData=onscreenDuration, duration=onscreenDuration) else: startPos = Point3(0, 0, self.MinOffscreenHeight) object.setPos(startPos) dropIval = LerpPosInterval(object, onscreenDuration, Point3(0, 0, 0), startPos=startPos, blendType='easeIn') ival = Sequence(Func(Functor(dropNode.reparentTo, self.root)), Parallel(Sequence(WaitInterval(self.OffscreenTime), Func(Functor(object.reparentTo, dropNode)), dropIval), shadowIval), Func(cleanup), name='drop%s' % (id,)) if objType == PartyGlobals.Name2DropObjectType['anvil']: ival.append(Func(self.playAnvil)) return ival
class DistributedPartyGate(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory( "DistributedPartyGate") def __init__(self, cr): """__init__(cr) """ DistributedObject.DistributedObject.__init__(self, cr) self.publicPartyChooseGuiDoneEvent = "doneChoosingPublicParty" self.publicPartyGui = PublicPartyGui( self.publicPartyChooseGuiDoneEvent) self.publicPartyGui.stash() self.loadClockSounds() self.hourSoundInterval = Sequence() self.accept('stoppedAsleep', self.handleSleep) def loadClockSounds(self): self.clockSounds = [] for i in range(1, 13): if i < 10: si = "0%d" % i else: si = "%d" % i self.clockSounds.append( base.loadSfx("phase_4/audio/sfx/clock%s.mp3" % si)) def generate(self): """generate(self) This method is called when the DistributedObject is reintroduced to the world, either for the first time or from the cache. """ DistributedObject.DistributedObject.generate(self) loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGate_grp') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return self.clockFlat = partyGate.find("**/clock_flat") collSphere = CollisionSphere(0, 0, 0, 6.9) collSphere.setTangible(1) self.partyGateSphere = CollisionNode("PartyGateSphere") self.partyGateSphere.addSolid(collSphere) self.partyGateCollNodePath = partyGate.find( "**/partyGate_stepsLocator").attachNewNode(self.partyGateSphere) self.__enableCollisions() # self.tunnelOrigin = NodePath("PartyGateTunnelOrigin") # self.tunnelOrigin.reparentTo(partyGate) # self.tunnelOrigin.setPos(partyGate.find("**/clockText_locator").getPos() + Point3(0.0, 0.0, -12.0)) self.toontownTimeGui = ServerTimeGui(partyGate, hourCallback=self.hourChange) self.toontownTimeGui.setPos( partyGate.find("**/clockText_locator").getPos() + Point3(0.0, 0.0, -0.2)) self.toontownTimeGui.setHpr( partyGate.find("**/clockText_locator").getHpr()) self.toontownTimeGui.setScale(12.0, 1.0, 26.0) self.toontownTimeGui.amLabel.setPos(-0.035, 0, -0.032) self.toontownTimeGui.amLabel.setScale(0.5) self.toontownTimeGui.updateTime() self.setupSignText() def setupSignText(self): """Attach text to the left and right signs""" loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGateSignGroup') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return gateFont = ToontownGlobals.getMinnieFont() leftSign = partyGate.find("**/signTextL_locatorBack") signScale = 0.35 wordWrap = 8 leftText = DirectLabel.DirectLabel( parent=leftSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateLeftSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale, ) rightSign = partyGate.find("**/signTextR_locatorFront") rightText = DirectLabel.DirectLabel( parent=rightSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateRightSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale, ) def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) if ToontownGlobals.dnaMap.has_key(self.zoneId): playground = ToontownGlobals.dnaMap[self.zoneId] else: playground = ToontownGlobals.dnaMap[2000] self.toontownTimeGui.hourLabel[ "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.colonLabel[ "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.minutesLabel[ "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.amLabel[ "text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] def disable(self): DistributedObject.DistributedObject.disable(self) self.__disableCollisions() self.toontownTimeGui.ival.finish() self.hourSoundInterval.finish() if self.publicPartyGui: self.publicPartyGui.stash() self.publicPartyGui.destroy() self.publicPartyGui = None def delete(self): DistributedObject.DistributedObject.delete(self) self.toontownTimeGui.destroy() del self.toontownTimeGui self.hourSoundInterval.finish() del self.hourSoundInterval del self.clockFlat if self.publicPartyGui: self.publicPartyGui.destroy() del self.publicPartyGui self.partyGateCollNodePath.removeNode() del self.partyGateCollNodePath self.ignoreAll() def showMessage(self, message): self.messageDoneEvent = self.uniqueName("messageDoneEvent") self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone) self.messageGui = TTDialog.TTGlobalDialog( doneEvent=self.messageDoneEvent, message=message, style=TTDialog.Acknowledge, ) def __handleMessageDone(self): self.ignore(self.messageDoneEvent) self.freeAvatar() self.messageGui.cleanup() self.messageGui = None def __handleAskDone(self): DistributedPartyGate.notify.debug("__handleAskDone") self.ignore(self.publicPartyChooseGuiDoneEvent) doneStatus = self.publicPartyGui.doneStatus self.publicPartyGui.stash() if doneStatus is None: # They don't want to party... just let them walk away from the hat self.freeAvatar() return self.sendUpdate("partyChoiceRequest", [base.localAvatar.doId, doneStatus[0], doneStatus[1]]) def partyRequestDenied(self, reason): """ Called by the AI when the player's request to join a public party was denied. """ DistributedPartyGate.notify.debug( "partyRequestDenied( reason=%s )" % PartyGlobals.PartyGateDenialReasons.getString(reason)) # let the local toon know that they were denied # TODO-parties: tell player through gui if reason == PartyGlobals.PartyGateDenialReasons.Unavailable: self.showMessage(TTLocalizer.PartyGatePartyUnavailable) elif reason == PartyGlobals.PartyGateDenialReasons.Full: self.showMessage(TTLocalizer.PartyGatePartyFull) def setParty(self, partyInfoTuple): """ Gets called by the AI server with the approved partyId. """ DistributedPartyGate.notify.debug("setParty") self.freeAvatar() if partyInfoTuple[0] == 0: DistributedPartyGate.notify.debug( "Public Party closed before toon could get to it.") return # We now need to enter the party with the given partyId, that is, move # our toon toward the hat entrance and do the appropriate state transition shardId, zoneId, numberOfGuests, hostName, activityIds, lane = partyInfoTuple if base.localAvatar.defaultShard == shardId: shardId = None base.cr.playGame.getPlace().requestLeave({ "loader": "safeZoneLoader", "where": "party", "how": "teleportIn", "hoodId": ToontownGlobals.PartyHood, "zoneId": zoneId, "shardId": shardId, "avId": -1, # "partyHat" : True, # "tunnelOrigin" : self.tunnelOrigin, }) def freeAvatar(self): base.localAvatar.posCamera(0, 0) base.cr.playGame.getPlace().setState("walk") def hourChange(self, currentHour): currentHour = currentHour % 12 if currentHour == 0: currentHour = 12 self.hourSoundInterval = Parallel() # Make a sequence with all the clock sounds seq1 = Sequence() for i in range(currentHour): seq1.append(SoundInterval(self.clockSounds[i])) seq1.append(Wait(0.2)) # Now make a sequence that will deform the clock face timeForEachDeformation = seq1.getDuration() / currentHour seq2 = Sequence() for i in range(currentHour): seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(0.9, 1.0, 1.2), blendType='easeInOut')) seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.2, 1.0, 0.9), blendType='easeInOut')) seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.0, 1.0, 1.0), blendType='easeInOut')) # Now parallel the two together self.hourSoundInterval.append(seq1) self.hourSoundInterval.append(seq2) self.hourSoundInterval.start() def handleEnterGateSphere(self, collEntry): self.notify.debug("Entering steps Sphere....") # Freeze the toon, don't let him walk away... base.cr.playGame.getPlace().fsm.request('stopped') self.sendUpdate("getPartyList", [base.localAvatar.doId]) def listAllPublicParties(self, publicPartyInfo): """ Called from DistributedPartyGateAI with a tuple of all the public party information as told to it by the DistributedPartyManagerAI in order of newest party to oldest party. ( shardId, zoneId, numberOfGuests, hostName, activityIds, minLeft ) """ self.notify.debug("listAllPublicParties : publicPartyInfo = %s" % publicPartyInfo) self.acceptOnce(self.publicPartyChooseGuiDoneEvent, self.__handleAskDone) self.publicPartyGui.refresh(publicPartyInfo) self.publicPartyGui.unstash() def __enableCollisions(self): # start listening for toons to enter. self.accept('enterPartyGateSphere', self.handleEnterGateSphere) self.partyGateSphere.setCollideMask(OTPGlobals.WallBitmask) def __disableCollisions(self): # stop listening for toons. self.ignore('enterPartyGateSphere') self.partyGateSphere.setCollideMask(BitMask32(0)) def handleSleep(self): if hasattr(self, 'messageGui'): self.__handleMessageDone()
class PartyCog(FSM): notify = directNotify.newCategory('PartyCog') HpTextGenerator = TextNode('HpTextGenerator') hpText = None height = 7 def __init__(self, parentNode, id, bounceSpeed=3, bounceHeight=1, rotateSpeed=1, heightShift=1, xMoveSpeed=0, xMoveDistance=0, bounceOffset=0): self.id = id FSM.__init__(self, 'PartyCogFSM-%d' % self.id) self.showFacingStatus = False self.xMoveSpeed = xMoveSpeed self.xMoveDistance = xMoveDistance self.heightShift = heightShift self.bounceSpeed = bounceSpeed self.bounceHeight = bounceHeight self.rotateSpeed = rotateSpeed self.parentNode = parentNode self.bounceOffset = bounceOffset self.hitInterval = None self.kaboomTrack = None self.resetRollIval = None self.netTimeSentToStartByHit = 0 self.load() self.request('Down') return def load(self): self.root = NodePath('PartyCog-%d' % self.id) self.root.reparentTo(self.parentNode) path = 'phase_13/models/parties/cogPinata_' self.actor = Actor( path + 'actor', { 'idle': path + 'idle_anim', 'down': path + 'down_anim', 'up': path + 'up_anim', 'bodyHitBack': path + 'bodyHitBack_anim', 'bodyHitFront': path + 'bodyHitFront_anim', 'headHitBack': path + 'headHitBack_anim', 'headHitFront': path + 'headHitFront_anim' }) self.actor.reparentTo(self.root) self.temp_transform = Mat4() self.head_locator = self.actor.attachNewNode('temphead') self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75) self.bodyColl.setTangible(1) self.bodyCollNode = CollisionNode('PartyCog-%d-Body-Collision' % self.id) self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.bodyCollNode.addSolid(self.bodyColl) self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode) self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5) self.headColl.setTangible(1) self.headCollNode = CollisionNode('PartyCog-%d-Head-Collision' % self.id) self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.headCollNode.addSolid(self.headColl) self.headCollNodePath = self.root.attachNewNode(self.headCollNode) self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0) self.arm1Coll.setTangible(1) self.arm1CollNode = CollisionNode('PartyCog-%d-Arm1-Collision' % self.id) self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm1CollNode.addSolid(self.arm1Coll) self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode) self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0) self.arm2Coll.setTangible(1) self.arm2CollNode = CollisionNode('PartyCog-%d-Arm2-Collision' % self.id) self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm2CollNode.addSolid(self.arm2Coll) self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode) splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.ogg') self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.ogg') self.hole = loader.loadModel('phase_13/models/parties/cogPinataHole') self.hole.setTransparency(True) self.hole.setP(-90.0) self.hole.setScale(3) self.hole.setBin('ground', 3) self.hole.reparentTo(self.parentNode) def unload(self): self.request('Off') self.clearHitInterval() if self.hole is not None: self.hole.removeNode() self.hole = None if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboomTrack = None if self.resetRollIval is not None and self.resetRollIval.isPlaying(): self.resetRollIval.finish() self.resetRollIval = None if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.finish() self.hitInterval = None del self.upSound del self.pieHitSound return def enterStatic(self): pass def exitStatic(self): pass def enterActive(self, startTime): self.root.setR(0.0) updateTask = Task.Task(self.updateTask) updateTask.startTime = startTime taskMgr.add(updateTask, 'PartyCog.update-%d' % self.id) def exitActive(self): taskMgr.remove('PartyCog.update-%d' % self.id) taskMgr.remove('PartyCog.bounceTask-%d' % self.id) self.clearHitInterval() self.resetRollIval = self.root.hprInterval(0.5, Point3( self.root.getH(), 0.0, 0.0), blendType='easeInOut') self.resetRollIval.start() self.actor.stop() def enterDown(self): if self.oldState == 'Off': downAnimControl = self.actor.getAnimControl('down') self.actor.pose('down', downAnimControl.getNumFrames() - 1) return self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'down', loop=0)), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def exitDown(self): self.root.setR(0.0) self.root.setH(0.0) self.targetDistance = 0.0 self.targetFacing = 0.0 self.currentT = 0.0 self.setAlongSpline(0.0) self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'up', loop=0)), Func(self.actor.loop, 'idle'), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def filterDown(self, request, args): if request == 'Down': return None else: return self.defaultFilter(request, args) return None def setEndPoints(self, start, end, amplitude=1.7): self.sinAmplitude = amplitude self.sinPeriod = (end.getX() - start.getX()) / 2 self.sinDisplacement = start.getY() self.startPoint = start self.endPoint = end self.currentT = 0.0 self.targetDistance = 0.0 self.currentFacing = 0.0 self.targetFacing = 0.0 self.setAlongSpline(self.currentT) self.hole.setPos(self.root.getPos()) self.hole.setZ(0.02) def rockBackAndForth(self, task): t = task.startTime + task.time angle = math.sin(t) * 20.0 self.root.setR(angle) return task.cont def updateDistance(self, distance): self.targetDistance = clamp(distance, -1.0, 1.0) def updateTask(self, task): self.rockBackAndForth(task) if self.targetDistance > self.currentT: self.currentT += min(0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) elif self.targetDistance < self.currentT: self.currentT += max(-0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) if self.currentT < 0.0: self.targetFacing = -90.0 elif self.currentT > 0.0: self.targetFacing = 90.0 else: self.targetFacing = 0.0 if self.targetFacing > self.currentFacing: self.currentFacing += min(10, self.targetFacing - self.currentFacing) elif self.targetFacing < self.currentFacing: self.currentFacing += max(-10, self.targetFacing - self.currentFacing) self.root.setH(self.currentFacing) return task.cont def setAlongSpline(self, t): t = t + 1.0 dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0 x = self.startPoint.getX() + t * dist y = self.startPoint.getY() - math.sin( t * 2 * math.pi) * self.sinAmplitude self.root.setPos(x, y, 0) def startBounce(self): taskMgr.add(self.bounce, 'PartyCog.bounceTask-%d' % self.id) def bounce(self, task): self.root.setZ( math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight + self.heightShift) return task.cont def setPos(self, position): self.root.setPos(position) def respondToPieHit(self, timestamp, position, hot=False, direction=1.0): if self.netTimeSentToStartByHit < timestamp: self.__showSplat(position, direction, hot) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearHitInterval(self): if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.clearToInitial() return def __showSplat(self, position, direction, hot=False): if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.clearHitInterval() splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splat.reparentTo(render) self.splat.setPos(self.root, position) self.splat.setAlphaScale(1.0) if not direction == 1.0: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0]) if self.currentFacing > 0.0: facing = 'HitFront' else: facing = 'HitBack' else: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1]) if self.currentFacing > 0.0: facing = 'HitBack' else: facing = 'HitFront' if hot: targetscale = 0.75 part = 'head' else: targetscale = 0.5 part = 'body' def setSplatAlpha(amount): self.splat.setAlphaScale(amount) self.hitInterval = Sequence( ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, 'idle')) self.hitInterval.start() self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence( Func(self.splat.showThrough), Parallel( Sequence( LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Wait(0.175)), Sequence( Wait(0.1), LerpFunc(setSplatAlpha, duration=1.0, fromData=1.0, toData=0.0, blendType='easeOut'))), Func(self.splat.cleanup), Func(self.splat.removeNode))) self.kaboomTrack.start() return def showHitScore(self, number, scale=1): if number <= 0: return if self.hpText: self.hideHitScore() self.HpTextGenerator.setFont(ToontownGlobals.getSignFont()) if number < 0: self.HpTextGenerator.setText(str(number)) else: self.HpTextGenerator.setText('+' + str(number)) self.HpTextGenerator.clearShadow() self.HpTextGenerator.setAlign(TextNode.ACenter) r = 1 g = 1 b = 0 a = 1 self.HpTextGenerator.setTextColor(r, g, b, a) self.hpTextNode = self.HpTextGenerator.generate() self.hpText = render.attachNewNode(self.hpTextNode) self.hpText.setScale(scale) self.hpText.setBillboardPointEye() self.hpText.setBin('fixed', 100) self.hpText.setPos(self.root, 0, 0, self.height / 2) seq = Task.sequence( self.hpText.lerpPos(Point3( self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), 0.25, blendType='easeOut'), Task.pause(0.25), self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1), Task.Task(self.__hideHitScoreTask)) taskMgr.add(seq, 'PartyCogHpText' + str(self.id)) def __hideHitScoreTask(self, task): self.hideHitScore() return Task.done def hideHitScore(self): if self.hpText: taskMgr.remove('PartyCogHpText' + str(self.id)) self.hpText.removeNode() self.hpText = None return def getHeadLocation(self): self.actor.getJoints(jointName='head')[0].getNetTransform( self.temp_transform) self.head_locator.setMat(self.temp_transform) return self.head_locator.getZ(self.root)
class DistributedPartyCatchActivity(DistributedPartyActivity, DistributedPartyCatchActivityBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyCatchActivity') DropTaskName = 'dropSomething' DropObjectPlurals = {'apple': TTLocalizer.PartyCatchActivityApples, 'orange': TTLocalizer.PartyCatchActivityOranges, 'pear': TTLocalizer.PartyCatchActivityPears, 'coconut': TTLocalizer.PartyCatchActivityCoconuts, 'watermelon': TTLocalizer.PartyCatchActivityWatermelons, 'pineapple': TTLocalizer.PartyCatchActivityPineapples, 'anvil': TTLocalizer.PartyCatchActivityAnvils} class Generation: def __init__(self, generation, startTime, startNetworkTime, numPlayers): self.generation = generation self.startTime = startTime self.startNetworkTime = startNetworkTime self.numPlayers = numPlayers self.hasBeenScheduled = False self.droppedObjNames = [] self.dropSchedule = [] self.numItemsDropped = 0 self.droppedObjCaught = {} def __init__(self, cr): DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyCatch, PartyGlobals.ActivityTypes.HostInitiated, wantRewardGui=True) self.setUsesSmoothing() self.setUsesLookAround() self._sNumGen = SerialNumGen() def getTitle(self): return TTLocalizer.PartyCatchActivityTitle def getInstructions(self): return TTLocalizer.PartyCatchActivityInstructions % {'badThing': self.DropObjectPlurals['anvil']} def generate(self): DistributedPartyActivity.generate(self) self.notify.info('localAvatar doId: %s' % base.localAvatar.doId) self.notify.info('generate()') self._generateFrame = globalClock.getFrameCount() self._id2gen = {} self._orderedGenerations = [] self._orderedGenerationIndex = None rng = RandomNumGen(self.doId) self._generationSeedBase = rng.randrange(1000) self._lastDropTime = 0.0 return def getCurGeneration(self): if self._orderedGenerationIndex is None: return return self._orderedGenerations[self._orderedGenerationIndex] def _addGeneration(self, generation, startTime, startNetworkTime, numPlayers): self._id2gen[generation] = self.Generation(generation, startTime, startNetworkTime, numPlayers) i = 0 while 1: if i >= len(self._orderedGenerations): break gen = self._orderedGenerations[i] startNetT = self._id2gen[gen].startTime genId = self._id2gen[gen].generation if startNetT > startNetworkTime: break if startNetT == startNetworkTime and genId > generation: break i += 1 self._orderedGenerations = self._orderedGenerations[:i] + [generation] + self._orderedGenerations[i:] if self._orderedGenerationIndex is not None: if self._orderedGenerationIndex >= i: self._orderedGenerationIndex += 1 def _removeGeneration(self, generation): del self._id2gen[generation] i = self._orderedGenerations.index(generation) self._orderedGenerations = self._orderedGenerations[:i] + self._orderedGenerations[i + 1:] if self._orderedGenerationIndex is not None: if len(self._orderedGenerations): if self._orderedGenerationIndex >= i: self._orderedGenerationIndex -= 1 else: self._orderedGenerationIndex = None return def announceGenerate(self): self.notify.info('announceGenerate()') self.catchTreeZoneEvent = 'fence_floor' DistributedPartyActivity.announceGenerate(self) def load(self, loadModels = 1, arenaModel = 'partyCatchTree'): self.notify.info('load()') DistributedPartyCatchActivity.notify.debug('PartyCatch: load') self.activityFSM = CatchActivityFSM(self) if __dev__: for o in xrange(3): print {0: 'SPOTS PER PLAYER', 1: 'DROPS PER MINUTE PER SPOT DURING NORMAL DROP PERIOD', 2: 'DROPS PER MINUTE PER PLAYER DURING NORMAL DROP PERIOD'}[o] for i in xrange(1, self.FallRateCap_Players + 10): self.defineConstants(forceNumPlayers=i) numDropLocations = self.DropRows * self.DropColumns numDropsPerMin = 60.0 / self.DropPeriod if o == 0: spotsPerPlayer = numDropLocations / float(i) print '%2d PLAYERS: %s' % (i, spotsPerPlayer) elif o == 1: numDropsPerMinPerSpot = numDropsPerMin / numDropLocations print '%2d PLAYERS: %s' % (i, numDropsPerMinPerSpot) elif i > 0: numDropsPerMinPerPlayer = numDropsPerMin / i print '%2d PLAYERS: %s' % (i, numDropsPerMinPerPlayer) self.defineConstants() self.treesAndFence = loader.loadModel('phase_13/models/parties/%s' % arenaModel) self.treesAndFence.setScale(0.9) self.treesAndFence.find('**/fence_floor').setPos(0.0, 0.0, 0.1) self.treesAndFence.reparentTo(self.root) ground = self.treesAndFence.find('**/groundPlane') ground.setBin('ground', 1) DistributedPartyActivity.load(self) exitText = TextNode('PartyCatchExitText') exitText.setCardAsMargin(0.1, 0.1, 0.1, 0.1) exitText.setCardDecal(True) exitText.setCardColor(1.0, 1.0, 1.0, 0.0) exitText.setText(TTLocalizer.PartyCatchActivityExit) exitText.setTextColor(0.0, 8.0, 0.0, 0.9) exitText.setAlign(exitText.ACenter) exitText.setFont(ToontownGlobals.getBuildingNametagFont()) exitText.setShadowColor(0, 0, 0, 1) exitText.setBin('fixed') if TTLocalizer.BuildingNametagShadow: exitText.setShadow(*TTLocalizer.BuildingNametagShadow) exitTextLoc = self.treesAndFence.find('**/loc_exitSignText') exitTextNp = exitTextLoc.attachNewNode(exitText) exitTextNp.setDepthWrite(0) exitTextNp.setScale(4) exitTextNp.setZ(-.5) self.sign.reparentTo(self.treesAndFence.find('**/loc_eventSign')) self.sign.wrtReparentTo(self.root) self.avatarNodePath = NodePath('PartyCatchAvatarNodePath') self.avatarNodePath.reparentTo(self.root) self._avatarNodePathParentToken = 3 base.cr.parentMgr.registerParent(self._avatarNodePathParentToken, self.avatarNodePath) self.toonSDs = {} self.dropShadow = loader.loadModelOnce('phase_3/models/props/drop_shadow') self.dropObjModels = {} if loadModels: self.__loadDropModels() self.sndGoodCatch = base.loadSfx('phase_4/audio/sfx/SZ_DD_treasure.ogg') self.sndOof = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg') self.sndAnvilLand = base.loadSfx('phase_4/audio/sfx/AA_drop_anvil_miss.ogg') self.sndPerfect = base.loadSfx('phase_4/audio/sfx/ring_perfect.ogg') self.__textGen = TextNode('partyCatchActivity') self.__textGen.setFont(ToontownGlobals.getSignFont()) self.__textGen.setAlign(TextNode.ACenter) self.activityFSM.request('Idle') def __loadDropModels(self): for objType in PartyGlobals.DropObjectTypes: model = loader.loadModel(objType.modelPath) self.dropObjModels[objType.name] = model modelScales = {'apple': 0.7, 'orange': 0.7, 'pear': 0.5, 'coconut': 0.7, 'watermelon': 0.6, 'pineapple': 0.45} if modelScales.has_key(objType.name): model.setScale(modelScales[objType.name]) if objType == PartyGlobals.Name2DropObjectType['pear']: model.setZ(-.6) if objType == PartyGlobals.Name2DropObjectType['coconut']: model.setP(180) if objType == PartyGlobals.Name2DropObjectType['watermelon']: model.setH(135) model.setZ(-.5) if objType == PartyGlobals.Name2DropObjectType['pineapple']: model.setZ(-1.7) if objType == PartyGlobals.Name2DropObjectType['anvil']: model.setZ(-self.ObjRadius) model.flattenStrong() def unload(self): DistributedPartyCatchActivity.notify.debug('unload') self.finishAllDropIntervals() self.destroyOrthoWalk() DistributedPartyActivity.unload(self) self.stopDropTask() del self.activityFSM del self.__textGen for avId in self.toonSDs.keys(): if self.toonSDs.has_key(avId): toonSD = self.toonSDs[avId] toonSD.unload() del self.toonSDs self.treesAndFence.removeNode() del self.treesAndFence self.dropShadow.removeNode() del self.dropShadow base.cr.parentMgr.unregisterParent(self._avatarNodePathParentToken) for model in self.dropObjModels.values(): model.removeNode() del self.dropObjModels del self.sndGoodCatch del self.sndOof del self.sndAnvilLand del self.sndPerfect def setStartTimestamp(self, timestamp32): self.notify.info('setStartTimestamp(%s)' % (timestamp32,)) self._startTimestamp = globalClockDelta.networkToLocalTime(timestamp32, bits=32) def getCurrentCatchActivityTime(self): return globalClock.getFrameTime() - self._startTimestamp def getObjModel(self, objName): return self.dropObjModels[objName].copyTo(hidden) def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) base.cr.playGame.getPlace().fsm.request('walk') def handleToonJoined(self, toonId): if not self.toonSDs.has_key(toonId): toonSD = PartyCatchActivityToonSD(toonId, self) self.toonSDs[toonId] = toonSD toonSD.load() self.notify.debug('handleToonJoined : currentState = %s' % self.activityFSM.state) self.cr.doId2do[toonId].useLOD(500) if self.activityFSM.state == 'Active': if self.toonSDs.has_key(toonId): self.toonSDs[toonId].enter() if base.localAvatar.doId == toonId: base.localAvatar.b_setParent(self._avatarNodePathParentToken) self.putLocalAvatarInActivity() if self.toonSDs.has_key(toonId): self.toonSDs[toonId].fsm.request('rules') def handleToonExited(self, toonId): self.notify.debug('handleToonExited( toonId=%s )' % toonId) if self.cr.doId2do.has_key(toonId): self.cr.doId2do[toonId].resetLOD() if self.toonSDs.has_key(toonId): self.toonSDs[toonId].fsm.request('notPlaying') self.toonSDs[toonId].exit() self.toonSDs[toonId].unload() del self.toonSDs[toonId] if base.localAvatar.doId == toonId: base.localAvatar.b_setParent(ToontownGlobals.SPRender) def takeLocalAvatarOutOfActivity(self): self.notify.debug('localToon has left the circle') camera.reparentTo(base.localAvatar) base.localAvatar.startUpdateSmartCamera() base.localAvatar.enableSmartCameraViews() base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex) DistributedSmoothNode.activateSmoothing(1, 0) def _enableCollisions(self): DistributedPartyActivity._enableCollisions(self) self._enteredTree = False self.accept('enter' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree) self.accept('again' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree) self.accept('exit' + self.catchTreeZoneEvent, self._toonExitedTree) self.accept(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT, self._handleCannonLanded) def _disableCollisions(self): self.ignore(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT) self.ignore('enter' + self.catchTreeZoneEvent) self.ignore('again' + self.catchTreeZoneEvent) self.ignore('exit' + self.catchTreeZoneEvent) DistributedPartyActivity._disableCollisions(self) def _handleCannonLanded(self): x = base.localAvatar.getX() y = base.localAvatar.getY() if x > self.x - self.StageHalfWidth and x < self.x + self.StageHalfWidth and y > self.y - self.StageHalfHeight and y < self.y + self.StageHalfHeight: self._toonEnteredTree(None) return def _toonMayHaveEnteredTree(self, collEntry): if self._enteredTree: return if base.localAvatar.controlManager.currentControls.getIsAirborne(): return self._toonEnteredTree(collEntry) def _toonEnteredTree(self, collEntry): self.notify.debug('_toonEnteredTree : avid = %s' % base.localAvatar.doId) self.notify.debug('_toonEnteredTree : currentState = %s' % self.activityFSM.state) if self.isLocalToonInActivity(): return if self.activityFSM.state == 'Active': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() elif self.activityFSM.state == 'Idle': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() self._enteredTree = True def _toonExitedTree(self, collEntry): self.notify.debug('_toonExitedTree : avid = %s' % base.localAvatar.doId) self._enteredTree = False if hasattr(base.cr.playGame.getPlace(), 'fsm') and self.activityFSM.state == 'Active' and self.isLocalToonInActivity(): if self.toonSDs.has_key(base.localAvatar.doId): self.takeLocalAvatarOutOfActivity() self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying') self.d_toonExitDemand() def setToonsPlaying(self, toonIds): self.notify.info('setToonsPlaying(%s)' % (toonIds,)) DistributedPartyActivity.setToonsPlaying(self, toonIds) if self.isLocalToonInActivity() and base.localAvatar.doId not in toonIds: if self.toonSDs.has_key(base.localAvatar.doId): self.takeLocalAvatarOutOfActivity() self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying') def __genText(self, text): self.__textGen.setText(text) return self.__textGen.generate() def getNumPlayers(self): return len(self.toonIds) def defineConstants(self, forceNumPlayers = None): DistributedPartyCatchActivity.notify.debug('defineConstants') self.ShowObjSpheres = 0 self.ShowToonSpheres = 0 self.useGravity = True self.trickShadows = True if forceNumPlayers is None: numPlayers = self.getNumPlayers() else: numPlayers = forceNumPlayers self.calcDifficultyConstants(numPlayers) DistributedPartyCatchActivity.notify.debug('ToonSpeed: %s' % self.ToonSpeed) DistributedPartyCatchActivity.notify.debug('total drops: %s' % self.totalDrops) DistributedPartyCatchActivity.notify.debug('numFruits: %s' % self.numFruits) DistributedPartyCatchActivity.notify.debug('numAnvils: %s' % self.numAnvils) self.ObjRadius = 1.0 dropRegionTable = PartyRegionDropPlacer.getDropRegionTable(numPlayers) self.DropRows, self.DropColumns = len(dropRegionTable), len(dropRegionTable[0]) for objType in PartyGlobals.DropObjectTypes: DistributedPartyCatchActivity.notify.debug('*** Object Type: %s' % objType.name) objType.onscreenDuration = objType.onscreenDurMult * self.BaselineOnscreenDropDuration DistributedPartyCatchActivity.notify.debug('onscreenDuration=%s' % objType.onscreenDuration) v_0 = 0.0 t = objType.onscreenDuration x_0 = self.MinOffscreenHeight x = 0.0 g = 2.0 * (x - x_0 - v_0 * t) / (t * t) DistributedPartyCatchActivity.notify.debug('gravity=%s' % g) objType.trajectory = Trajectory(0, Vec3(0, 0, x_0), Vec3(0, 0, v_0), gravMult=abs(g / Trajectory.gravity)) objType.fallDuration = objType.onscreenDuration + self.OffscreenTime return def grid2world(self, column, row): x = column / float(self.DropColumns - 1) y = row / float(self.DropRows - 1) x = x * 2.0 - 1.0 y = y * 2.0 - 1.0 x *= self.StageHalfWidth y *= self.StageHalfHeight return (x, y) def showPosts(self): self.hidePosts() self.posts = [Toon.Toon(), Toon.Toon(), Toon.Toon(), Toon.Toon()] for i in xrange(len(self.posts)): tree = self.posts[i] tree.reparentTo(render) x = self.StageHalfWidth y = self.StageHalfHeight if i > 1: x = -x if i % 2: y = -y tree.setPos(x + self.x, y + self.y, 0) def hidePosts(self): if hasattr(self, 'posts'): for tree in self.posts: tree.removeNode() del self.posts def showDropGrid(self): self.hideDropGrid() self.dropMarkers = [] for row in xrange(self.DropRows): self.dropMarkers.append([]) rowList = self.dropMarkers[row] for column in xrange(self.DropColumns): toon = Toon.Toon() toon.setDNA(base.localAvatar.getStyle()) toon.reparentTo(self.root) toon.setScale(1.0 / 3) x, y = self.grid2world(column, row) toon.setPos(x, y, 0) rowList.append(toon) def hideDropGrid(self): if hasattr(self, 'dropMarkers'): for row in self.dropMarkers: for marker in row: marker.removeNode() del self.dropMarkers def handleToonDisabled(self, avId): DistributedPartyCatchActivity.notify.debug('handleToonDisabled') DistributedPartyCatchActivity.notify.debug('avatar ' + str(avId) + ' disabled') if self.toonSDs.has_key(avId): self.toonSDs[avId].exit(unexpectedExit=True) del self.toonSDs[avId] def turnOffSmoothingOnGuests(self): pass def setState(self, newState, timestamp): self.notify.info('setState(%s, %s)' % (newState, timestamp)) DistributedPartyCatchActivity.notify.debug('setState( newState=%s, ... )' % newState) DistributedPartyActivity.setState(self, newState, timestamp) self.activityFSM.request(newState) if newState == 'Active': if base.localAvatar.doId != self.party.partyInfo.hostId: if globalClock.getFrameCount() > self._generateFrame: if base.localAvatar.getX() > self.x - self.StageHalfWidth and base.localAvatar.getX() < self.x + self.StageHalfWidth and base.localAvatar.getY() > self.y - self.StageHalfHeight and base.localAvatar.getY() < self.y + self.StageHalfHeight: self._toonEnteredTree(None) return def putLocalAvatarInActivity(self): if base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(), 'fsm'): base.cr.playGame.getPlace().fsm.request('activity', [False]) else: self.notify.info("Avoided crash: toontown.parties.DistributedPartyCatchActivity:632, toontown.parties.DistributedPartyCatchActivity:1198, toontown.parties.activityFSMMixins:49, direct.fsm.FSM:423, AttributeError: 'NoneType' object has no attribute 'fsm'") base.localAvatar.stopUpdateSmartCamera() camera.reparentTo(self.treesAndFence) camera.setPosHpr(0.0, -63.0, 30.0, 0.0, -20.0, 0.0) if not hasattr(self, 'ltLegsCollNode'): self.createCatchCollisions() def createCatchCollisions(self): radius = 0.7 handler = CollisionHandlerEvent() handler.setInPattern('ltCatch%in') self.ltLegsCollNode = CollisionNode('catchLegsCollNode') self.ltLegsCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltHeadCollNode = CollisionNode('catchHeadCollNode') self.ltHeadCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltLHandCollNode = CollisionNode('catchLHandCollNode') self.ltLHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltRHandCollNode = CollisionNode('catchRHandCollNode') self.ltRHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) legsCollNodepath = base.localAvatar.attachNewNode(self.ltLegsCollNode) legsCollNodepath.hide() head = base.localAvatar.getHeadParts().getPath(2) headCollNodepath = head.attachNewNode(self.ltHeadCollNode) headCollNodepath.hide() lHand = base.localAvatar.getLeftHands()[0] lHandCollNodepath = lHand.attachNewNode(self.ltLHandCollNode) lHandCollNodepath.hide() rHand = base.localAvatar.getRightHands()[0] rHandCollNodepath = rHand.attachNewNode(self.ltRHandCollNode) rHandCollNodepath.hide() base.localAvatar.cTrav.addCollider(legsCollNodepath, handler) base.localAvatar.cTrav.addCollider(headCollNodepath, handler) base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler) base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler) if self.ShowToonSpheres: legsCollNodepath.show() headCollNodepath.show() lHandCollNodepath.show() rHandCollNodepath.show() self.ltLegsCollNode.addSolid(CollisionSphere(0, 0, radius, radius)) self.ltHeadCollNode.addSolid(CollisionSphere(0, 0, 0, radius)) self.ltLHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0)) self.ltRHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0)) self.toonCollNodes = [legsCollNodepath, headCollNodepath, lHandCollNodepath, rHandCollNodepath] def destroyCatchCollisions(self): if not hasattr(self, 'ltLegsCollNode'): return for collNode in self.toonCollNodes: while collNode.node().getNumSolids(): collNode.node().removeSolid(0) base.localAvatar.cTrav.removeCollider(collNode) del self.toonCollNodes del self.ltLegsCollNode del self.ltHeadCollNode del self.ltLHandCollNode del self.ltRHandCollNode def timerExpired(self): pass def __handleCatch(self, generation, objNum): DistributedPartyCatchActivity.notify.debug('catch: %s' % [generation, objNum]) if base.localAvatar.doId not in self.toonIds: return self.showCatch(base.localAvatar.doId, generation, objNum) objName = self._id2gen[generation].droppedObjNames[objNum] objTypeId = PartyGlobals.Name2DOTypeId[objName] self.sendUpdate('claimCatch', [generation, objNum, objTypeId]) self.finishDropInterval(generation, objNum) def showCatch(self, avId, generation, objNum): if not self.toonSDs.has_key(avId): return isLocal = avId == base.localAvatar.doId if generation not in self._id2gen: return if not self._id2gen[generation].hasBeenScheduled: return objName = self._id2gen[generation].droppedObjNames[objNum] objType = PartyGlobals.Name2DropObjectType[objName] if objType.good: if not self._id2gen[generation].droppedObjCaught.has_key(objNum): if isLocal: base.playSfx(self.sndGoodCatch) fruit = self.getObjModel(objName) toon = self.getAvatar(avId) rHand = toon.getRightHands()[1] self.toonSDs[avId].eatFruit(fruit, rHand) else: self.toonSDs[avId].fsm.request('fallForward') self._id2gen[generation].droppedObjCaught[objNum] = 1 def setObjectCaught(self, avId, generation, objNum): self.notify.info('setObjectCaught(%s, %s, %s)' % (avId, generation, objNum)) if self.activityFSM.state != 'Active': DistributedPartyCatchActivity.notify.warning('ignoring msg: object %s caught by %s' % (objNum, avId)) return isLocal = avId == base.localAvatar.doId if not isLocal: DistributedPartyCatchActivity.notify.debug('AI: avatar %s caught %s' % (avId, objNum)) self.finishDropInterval(generation, objNum) self.showCatch(avId, generation, objNum) self._scheduleGenerations() gen = self._id2gen[generation] if gen.hasBeenScheduled: objName = gen.droppedObjNames[objNum] if PartyGlobals.Name2DropObjectType[objName].good: if hasattr(self, 'fruitsCaught'): self.fruitsCaught += 1 def finishDropInterval(self, generation, objNum): if hasattr(self, 'dropIntervals'): if self.dropIntervals.has_key((generation, objNum)): self.dropIntervals[generation, objNum].finish() def finishAllDropIntervals(self): if hasattr(self, 'dropIntervals'): for dropInterval in self.dropIntervals.values(): dropInterval.finish() def setGenerations(self, generations): self.notify.info('setGenerations(%s)' % (generations,)) gen2t = {} gen2nt = {} gen2np = {} for id, timestamp32, numPlayers in generations: gen2t[id] = globalClockDelta.networkToLocalTime(timestamp32, bits=32) - self._startTimestamp gen2nt[id] = timestamp32 gen2np[id] = numPlayers ids = self._id2gen.keys() for id in ids: if id not in gen2t: self._removeGeneration(id) for id in gen2t: if id not in self._id2gen: self._addGeneration(id, gen2t[id], gen2nt[id], gen2np[id]) def scheduleDrops(self, genId = None): if genId is None: genId = self.getCurGeneration() gen = self._id2gen[genId] if gen.hasBeenScheduled: return fruitIndex = int((gen.startTime + 0.5 * self.DropPeriod) / PartyGlobals.CatchActivityDuration) fruitNames = ['apple', 'orange', 'pear', 'coconut', 'watermelon', 'pineapple'] fruitName = fruitNames[fruitIndex % len(fruitNames)] rng = RandomNumGen(genId + self._generationSeedBase) gen.droppedObjNames = [fruitName] * self.numFruits + ['anvil'] * self.numAnvils rng.shuffle(gen.droppedObjNames) dropPlacer = PartyRegionDropPlacer(self, gen.numPlayers, genId, gen.droppedObjNames, startTime=gen.startTime) gen.numItemsDropped = 0 tIndex = gen.startTime % PartyGlobals.CatchActivityDuration tPercent = float(tIndex) / PartyGlobals.CatchActivityDuration gen.numItemsDropped += dropPlacer.skipPercent(tPercent) while not dropPlacer.doneDropping(continuous=True): nextDrop = dropPlacer.getNextDrop() gen.dropSchedule.append(nextDrop) gen.hasBeenScheduled = True return def startDropTask(self): taskMgr.add(self.dropTask, self.DropTaskName) def stopDropTask(self): taskMgr.remove(self.DropTaskName) def _scheduleGenerations(self): curT = self.getCurrentCatchActivityTime() genIndex = self._orderedGenerationIndex newGenIndex = genIndex while genIndex is None or genIndex < len(self._orderedGenerations) - 1: if genIndex is None: nextGenIndex = 0 else: nextGenIndex = genIndex + 1 nextGenId = self._orderedGenerations[nextGenIndex] nextGen = self._id2gen[nextGenId] startT = nextGen.startTime if curT >= startT: newGenIndex = nextGenIndex if not nextGen.hasBeenScheduled: self.defineConstants(forceNumPlayers=nextGen.numPlayers) self.scheduleDrops(genId=self._orderedGenerations[nextGenIndex]) genIndex = nextGenIndex self._orderedGenerationIndex = newGenIndex return def dropTask(self, task): self._scheduleGenerations() curT = self.getCurrentCatchActivityTime() if self._orderedGenerationIndex is not None: i = self._orderedGenerationIndex genIndex = self._orderedGenerations[i] gen = self._id2gen[genIndex] while len(gen.dropSchedule) > 0 and gen.dropSchedule[0][0] < curT: drop = gen.dropSchedule[0] gen.dropSchedule = gen.dropSchedule[1:] dropTime, objName, dropCoords = drop objNum = gen.numItemsDropped x, y = self.grid2world(*dropCoords) dropIval = self.getDropIval(x, y, objName, genIndex, objNum) def cleanup(generation, objNum, self = self): del self.dropIntervals[generation, objNum] dropIval.append(Func(Functor(cleanup, genIndex, objNum))) self.dropIntervals[genIndex, objNum] = dropIval gen.numItemsDropped += 1 dropIval.start(curT - dropTime) self._lastDropTime = dropTime return Task.cont def getDropIval(self, x, y, dropObjName, generation, num): objType = PartyGlobals.Name2DropObjectType[dropObjName] id = (generation, num) dropNode = hidden.attachNewNode('catchDropNode%s' % (id,)) dropNode.setPos(x, y, 0) shadow = self.dropShadow.copyTo(dropNode) shadow.setZ(PartyGlobals.CatchDropShadowHeight) shadow.setColor(1, 1, 1, 1) object = self.getObjModel(dropObjName) object.reparentTo(hidden) if dropObjName in ['watermelon', 'anvil']: objH = object.getH() absDelta = {'watermelon': 12, 'anvil': 15}[dropObjName] delta = (self.randomNumGen.random() * 2.0 - 1.0) * absDelta newH = objH + delta else: newH = self.randomNumGen.random() * 360.0 object.setH(newH) sphereName = 'FallObj%s' % (id,) radius = self.ObjRadius if objType.good: radius *= lerp(1.0, 1.3, 0.5) collSphere = CollisionSphere(0, 0, 0, radius) collSphere.setTangible(0) collNode = CollisionNode(sphereName) collNode.setCollideMask(PartyGlobals.CatchActivityBitmask) collNode.addSolid(collSphere) collNodePath = object.attachNewNode(collNode) collNodePath.hide() if self.ShowObjSpheres: collNodePath.show() catchEventName = 'ltCatch' + sphereName def eatCollEntry(forward, collEntry): forward() self.accept(catchEventName, Functor(eatCollEntry, Functor(self.__handleCatch, id[0], id[1]))) def cleanup(self = self, dropNode = dropNode, id = id, event = catchEventName): self.ignore(event) dropNode.removeNode() duration = objType.fallDuration onscreenDuration = objType.onscreenDuration targetShadowScale = 0.3 if self.trickShadows: intermedScale = targetShadowScale * (self.OffscreenTime / self.BaselineDropDuration) shadowScaleIval = Sequence(LerpScaleInterval(shadow, self.OffscreenTime, intermedScale, startScale=0)) shadowScaleIval.append(LerpScaleInterval(shadow, duration - self.OffscreenTime, targetShadowScale, startScale=intermedScale)) else: shadowScaleIval = LerpScaleInterval(shadow, duration, targetShadowScale, startScale=0) targetShadowAlpha = 0.4 shadowAlphaIval = LerpColorScaleInterval(shadow, self.OffscreenTime, Point4(1, 1, 1, targetShadowAlpha), startColorScale=Point4(1, 1, 1, 0)) shadowIval = Parallel(shadowScaleIval, shadowAlphaIval) if self.useGravity: def setObjPos(t, objType = objType, object = object): z = objType.trajectory.calcZ(t) object.setZ(z) setObjPos(0) dropIval = LerpFunctionInterval(setObjPos, fromData=0, toData=onscreenDuration, duration=onscreenDuration) else: startPos = Point3(0, 0, self.MinOffscreenHeight) object.setPos(startPos) dropIval = LerpPosInterval(object, onscreenDuration, Point3(0, 0, 0), startPos=startPos, blendType='easeIn') ival = Sequence(Func(Functor(dropNode.reparentTo, self.root)), Parallel(Sequence(WaitInterval(self.OffscreenTime), Func(Functor(object.reparentTo, dropNode)), dropIval), shadowIval), Func(cleanup), name='drop%s' % (id,)) if objType == PartyGlobals.Name2DropObjectType['anvil']: ival.append(Func(self.playAnvil)) return ival def playAnvil(self): if base.localAvatar.doId in self.toonIds: base.playSfx(self.sndAnvilLand) def initOrthoWalk(self): DistributedPartyCatchActivity.notify.debug('startOrthoWalk') def doCollisions(oldPos, newPos, self = self): x = bound(newPos[0], self.StageHalfWidth, -self.StageHalfWidth) y = bound(newPos[1], self.StageHalfHeight, -self.StageHalfHeight) newPos.setX(x) newPos.setY(y) return newPos orthoDrive = OrthoDrive(self.ToonSpeed, instantTurn=True) self.orthoWalk = OrthoWalk(orthoDrive, broadcast=True) def destroyOrthoWalk(self): DistributedPartyCatchActivity.notify.debug('destroyOrthoWalk') if hasattr(self, 'orthoWalk'): self.orthoWalk.stop() self.orthoWalk.destroy() del self.orthoWalk def startIdle(self): DistributedPartyCatchActivity.notify.debug('startIdle') def finishIdle(self): DistributedPartyCatchActivity.notify.debug('finishIdle') def startActive(self): DistributedPartyCatchActivity.notify.debug('startActive') for avId in self.toonIds: if self.toonSDs.has_key(avId): toonSD = self.toonSDs[avId] toonSD.enter() toonSD.fsm.request('normal') self.fruitsCaught = 0 self.dropIntervals = {} self.startDropTask() if base.localAvatar.doId in self.toonIds: self.putLocalAvatarInActivity() def finishActive(self): DistributedPartyCatchActivity.notify.debug('finishActive') self.stopDropTask() if hasattr(self, 'finishIval'): self.finishIval.pause() del self.finishIval if base.localAvatar.doId in self.toonIds: self.takeLocalAvatarOutOfActivity() for ival in self.dropIntervals.values(): ival.finish() del self.dropIntervals def startConclusion(self): DistributedPartyCatchActivity.notify.debug('startConclusion') for avId in self.toonIds: if self.toonSDs.has_key(avId): toonSD = self.toonSDs[avId] toonSD.fsm.request('notPlaying') self.destroyCatchCollisions() if base.localAvatar.doId not in self.toonIds: return else: self.localToonExiting() if self.fruitsCaught >= self.numFruits: finishText = TTLocalizer.PartyCatchActivityFinishPerfect else: finishText = TTLocalizer.PartyCatchActivityFinish perfectTextSubnode = hidden.attachNewNode(self.__genText(finishText)) perfectText = hidden.attachNewNode('perfectText') perfectTextSubnode.reparentTo(perfectText) frame = self.__textGen.getCardActual() offsetY = -abs(frame[2] + frame[3]) / 2.0 perfectTextSubnode.setPos(0, 0, offsetY) perfectText.setColor(1, 0.1, 0.1, 1) def fadeFunc(t, text = perfectText): text.setColorScale(1, 1, 1, t) def destroyText(text = perfectText): text.removeNode() textTrack = Sequence(Func(perfectText.reparentTo, aspect2d), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5)) soundTrack = SoundInterval(self.sndPerfect) self.finishIval = Parallel(textTrack, soundTrack) self.finishIval.start() def finishConclusion(self): DistributedPartyCatchActivity.notify.debug('finishConclusion') if base.localAvatar.doId in self.toonIds: self.takeLocalAvatarOutOfActivity() base.cr.playGame.getPlace().fsm.request('walk') def showJellybeanReward(self, earnedAmount, jarAmount, message): if earnedAmount > 0: DistributedPartyActivity.showJellybeanReward(self, earnedAmount, jarAmount, message) else: base.cr.playGame.getPlace().fsm.request('walk')
class DistributedPartyGate(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyGate') def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.publicPartyChooseGuiDoneEvent = 'doneChoosingPublicParty' self.publicPartyGui = PublicPartyGui(self.publicPartyChooseGuiDoneEvent) self.publicPartyGui.stash() self.loadClockSounds() self.hourSoundInterval = Sequence() self.accept('stoppedAsleep', self.handleSleep) def loadClockSounds(self): self.clockSounds = [] for i in range(1, 13): if i < 10: si = '0%d' % i else: si = '%d' % i self.clockSounds.append(base.loadSfx('phase_4/audio/sfx/clock%s.ogg' % si)) def generate(self): DistributedObject.DistributedObject.generate(self) loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGate_grp') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return self.clockFlat = partyGate.find('**/clock_flat') collSphere = CollisionSphere(0, 0, 0, 6.9) collSphere.setTangible(1) self.partyGateSphere = CollisionNode('PartyGateSphere') self.partyGateSphere.addSolid(collSphere) self.partyGateCollNodePath = partyGate.find('**/partyGate_stepsLocator').attachNewNode(self.partyGateSphere) self.__enableCollisions() self.toontownTimeGui = ServerTimeGui(partyGate, hourCallback=self.hourChange) self.toontownTimeGui.setPos(partyGate.find('**/clockText_locator').getPos() + Point3(0.0, 0.0, -0.2)) self.toontownTimeGui.setHpr(partyGate.find('**/clockText_locator').getHpr()) self.toontownTimeGui.setScale(12.0, 1.0, 26.0) self.toontownTimeGui.amLabel.setPos(-0.035, 0, -0.032) self.toontownTimeGui.amLabel.setScale(0.5) self.toontownTimeGui.updateTime() self.setupSignText() def setupSignText(self): loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGateSignGroup') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return gateFont = ToontownGlobals.getMinnieFont() leftSign = partyGate.find('**/signTextL_locatorBack') signScale = 0.35 wordWrap = 8 leftText = DirectLabel.DirectLabel(parent=leftSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateLeftSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale) rightSign = partyGate.find('**/signTextR_locatorFront') rightText = DirectLabel.DirectLabel(parent=rightSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateRightSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale) return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) if ToontownGlobals.dnaMap.has_key(self.zoneId): playground = ToontownGlobals.dnaMap[self.zoneId] else: playground = ToontownGlobals.dnaMap[2000] self.toontownTimeGui.hourLabel['text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.colonLabel['text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.minutesLabel['text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.amLabel['text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] def disable(self): DistributedObject.DistributedObject.disable(self) self.__disableCollisions() self.toontownTimeGui.ival.finish() self.hourSoundInterval.finish() if self.publicPartyGui: self.publicPartyGui.stash() self.publicPartyGui.destroy() self.publicPartyGui = None return def delete(self): DistributedObject.DistributedObject.delete(self) self.toontownTimeGui.destroy() del self.toontownTimeGui self.hourSoundInterval.finish() del self.hourSoundInterval del self.clockFlat if self.publicPartyGui: self.publicPartyGui.destroy() del self.publicPartyGui self.partyGateCollNodePath.removeNode() del self.partyGateCollNodePath self.ignoreAll() def showMessage(self, message): self.messageDoneEvent = self.uniqueName('messageDoneEvent') self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone) self.messageGui = TTDialog.TTGlobalDialog(doneEvent=self.messageDoneEvent, message=message, style=TTDialog.Acknowledge) def __handleMessageDone(self): self.ignore(self.messageDoneEvent) self.freeAvatar() self.messageGui.cleanup() self.messageGui = None return def __handleAskDone(self): DistributedPartyGate.notify.debug('__handleAskDone') self.ignore(self.publicPartyChooseGuiDoneEvent) doneStatus = self.publicPartyGui.doneStatus self.publicPartyGui.stash() if doneStatus is None: self.freeAvatar() return self.sendUpdate('partyChoiceRequest', [base.localAvatar.doId, doneStatus[0], doneStatus[1]]) return def partyRequestDenied(self, reason): DistributedPartyGate.notify.debug('partyRequestDenied( reason=%s )' % PartyGlobals.PartyGateDenialReasons.getString(reason)) if reason == PartyGlobals.PartyGateDenialReasons.Unavailable: self.showMessage(TTLocalizer.PartyGatePartyUnavailable) elif reason == PartyGlobals.PartyGateDenialReasons.Full: self.showMessage(TTLocalizer.PartyGatePartyFull) def setParty(self, partyInfoTuple, hostId): DistributedPartyGate.notify.debug('setParty') self.freeAvatar() if partyInfoTuple[0] == 0: DistributedPartyGate.notify.debug('Public Party closed before toon could get to it.') return shardId, zoneId, numberOfGuests, hostName, activityIds, lane = partyInfoTuple #For some reason, the party gate is attempting to teleport to the host of a party rather than a random spot in the party. #This temporarily fixes a hang on the loading screen if base.localAvatar.defaultShard != shardId: shardId = None base.cr.playGame.getPlace().requestLeave({'loader': 'safeZoneLoader', 'where': 'party', 'how': 'teleportIn', 'hoodId': ToontownGlobals.PartyHood, 'zoneId': zoneId, 'shardId': None, 'avId': hostId}) return def freeAvatar(self): base.localAvatar.posCamera(0, 0) base.cr.playGame.getPlace().setState('walk') def hourChange(self, currentHour): currentHour %= 12 if currentHour == 0: currentHour = 12 self.hourSoundInterval = Parallel() seq1 = Sequence() for i in range(currentHour): seq1.append(SoundInterval(self.clockSounds[i])) seq1.append(Wait(0.2)) timeForEachDeformation = seq1.getDuration() / currentHour seq2 = Sequence() for i in range(currentHour): seq2.append(self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(0.9, 1.0, 1.2), blendType='easeInOut')) seq2.append(self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.2, 1.0, 0.9), blendType='easeInOut')) seq2.append(self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.0, 1.0, 1.0), blendType='easeInOut')) self.hourSoundInterval.append(seq1) self.hourSoundInterval.append(seq2) self.hourSoundInterval.start() def handleEnterGateSphere(self, collEntry): self.notify.debug('Entering steps Sphere....') base.cr.playGame.getPlace().fsm.request('stopped') self.sendUpdate('getPartyList', [base.localAvatar.doId]) def listAllPublicParties(self, publicPartyInfo): self.notify.debug('listAllPublicParties : publicPartyInfo = %s' % publicPartyInfo) self.acceptOnce(self.publicPartyChooseGuiDoneEvent, self.__handleAskDone) self.publicPartyGui.refresh(publicPartyInfo) self.publicPartyGui.unstash() def __enableCollisions(self): self.accept('enterPartyGateSphere', self.handleEnterGateSphere) self.partyGateSphere.setCollideMask(OTPGlobals.WallBitmask) def __disableCollisions(self): self.ignore('enterPartyGateSphere') self.partyGateSphere.setCollideMask(BitMask32(0)) def handleSleep(self): if hasattr(self, 'messageGui') and self.messageGui: self.__handleMessageDone()
class PartyCog(FSM): notify = directNotify.newCategory("PartyCog") HpTextGenerator = TextNode("HpTextGenerator") hpText = None height = 7 def __init__(self, parentNode, id, bounceSpeed=3, bounceHeight=1, rotateSpeed=1, heightShift=1, xMoveSpeed=0, xMoveDistance=0, bounceOffset=0): self.id = id FSM.__init__(self, "PartyCogFSM-%d" % self.id) self.showFacingStatus = False self.xMoveSpeed = xMoveSpeed self.xMoveDistance = xMoveDistance self.heightShift = heightShift self.bounceSpeed = bounceSpeed self.bounceHeight = bounceHeight self.rotateSpeed = rotateSpeed self.parentNode = parentNode self.bounceOffset = bounceOffset self.hitInterval = None self.kaboomTrack = None self.resetRollIval = None self.netTimeSentToStartByHit = 0 self.load() self.request("Down") def load(self): self.root = NodePath("PartyCog-%d" % self.id) self.root.reparentTo(self.parentNode) path = "phase_13/models/parties/cogPinata_" self.actor = Actor( path + "actor", { "idle": path + "idle_anim", "down": path + "down_anim", "up": path + "up_anim", "bodyHitBack": path + "bodyHitBack_anim", "bodyHitFront": path + "bodyHitFront_anim", "headHitBack": path + "headHitBack_anim", "headHitFront": path + "headHitFront_anim", }) self.actor.reparentTo(self.root) self.temp_transform = Mat4() self.head_locator = self.actor.attachNewNode("temphead") self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75) self.bodyColl.setTangible(1) self.bodyCollNode = CollisionNode("PartyCog-%d-Body-Collision" % self.id) self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.bodyCollNode.addSolid(self.bodyColl) self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode) self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5) self.headColl.setTangible(1) self.headCollNode = CollisionNode("PartyCog-%d-Head-Collision" % self.id) self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.headCollNode.addSolid(self.headColl) self.headCollNodePath = self.root.attachNewNode(self.headCollNode) # Cog's Left Arm self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0) self.arm1Coll.setTangible(1) self.arm1CollNode = CollisionNode("PartyCog-%d-Arm1-Collision" % self.id) self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm1CollNode.addSolid(self.arm1Coll) self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode) # Cog's Right Arm self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0) self.arm2Coll.setTangible(1) self.arm2CollNode = CollisionNode("PartyCog-%d-Arm2-Collision" % self.id) self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm2CollNode.addSolid(self.arm2Coll) self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode) splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.mp3') self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.mp3') self.hole = loader.loadModel("phase_13/models/parties/cogPinataHole") self.hole.setTransparency(True) self.hole.setP(-90.0) self.hole.setScale(3) self.hole.setBin("ground", 3) self.hole.reparentTo(self.parentNode) def unload(self): self.request("Off") self.clearHitInterval() if self.hole is not None: self.hole.removeNode() self.hole = None if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboomTrack = None if self.resetRollIval is not None and self.resetRollIval.isPlaying(): self.resetRollIval.finish() self.resetRollIval = None if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.finish() self.hitInterval = None del self.upSound del self.pieHitSound #=============================================================================== # FSM States #=============================================================================== def enterStatic(self): pass def exitStatic(self): pass def enterActive(self, startTime): self.root.setR(0.0) updateTask = Task.Task(self.updateTask) updateTask.startTime = startTime taskMgr.add(updateTask, "PartyCog.update-%d" % self.id) def exitActive(self): taskMgr.remove("PartyCog.update-%d" % self.id) taskMgr.remove("PartyCog.bounceTask-%d" % self.id) self.clearHitInterval() self.resetRollIval = self.root.hprInterval(0.5, Point3( self.root.getH(), 0.0, 0.0), blendType="easeInOut") self.resetRollIval.start() self.actor.stop() def enterDown(self): if self.oldState == "Off": downAnimControl = self.actor.getAnimControl("down") self.actor.pose("down", downAnimControl.getNumFrames() - 1) return self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType="easeIn"), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, "down", loop=0), ), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType="easeOut"), ) self.hitInterval.start() def exitDown(self): self.root.setR(0.0) self.root.setH(0.0) self.targetDistance = 0.0 self.targetFacing = 0.0 self.currentT = 0.0 self.setAlongSpline(0.0) self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType="easeIn"), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, "up", loop=0), ), Func(self.actor.loop, "idle"), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType="easeOut"), ) self.hitInterval.start() def filterDown(self, request, args): if request == "Down": return None else: return self.defaultFilter(request, args) #------------------------------------------------------------------------------ def setEndPoints(self, start, end, amplitude=1.7): self.sinAmplitude = amplitude self.sinPeriod = (end.getX() - start.getX()) / 2 self.sinDisplacement = start.getY() self.startPoint = start self.endPoint = end self.currentT = 0.0 self.targetDistance = 0.0 self.currentFacing = 0.0 self.targetFacing = 0.0 self.setAlongSpline(self.currentT) self.hole.setPos(self.root.getPos()) self.hole.setZ(0.02) def rockBackAndForth(self, task): t = task.startTime + task.time angle = math.sin(t) * 20.0 self.root.setR(angle) # if self.id == 0: # print angle return task.cont def updateDistance(self, distance): self.targetDistance = clamp(distance, -1.0, 1.0) def updateTask(self, task): self.rockBackAndForth(task) if self.targetDistance > self.currentT: self.currentT += min(0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) elif self.targetDistance < self.currentT: self.currentT += max(-0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) if self.currentT < 0.0: self.targetFacing = -90.0 elif self.currentT > 0.0: self.targetFacing = 90.0 else: self.targetFacing = 0.0 if self.targetFacing > self.currentFacing: self.currentFacing += min(10, self.targetFacing - self.currentFacing) elif self.targetFacing < self.currentFacing: self.currentFacing += max(-10, self.targetFacing - self.currentFacing) self.root.setH(self.currentFacing) return task.cont def setAlongSpline(self, t): t = t + 1.0 dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0 x = self.startPoint.getX() + t * dist y = self.startPoint.getY() - math.sin( t * 2 * math.pi) * self.sinAmplitude self.root.setPos(x, y, 0) def startBounce(self): taskMgr.add(self.bounce, "PartyCog.bounceTask-%d" % self.id) def bounce(self, task): #self.root.setH(self.root.getH() - self.rotateSpeed) self.root.setZ((math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight) + self.heightShift) return task.cont def setPos(self, position): self.root.setPos(position) def respondToPieHit(self, timestamp, position, hot=False, direction=1.0): """The toon hit us, react appropriately.""" assert (self.notify.debugStateCall(self)) if self.netTimeSentToStartByHit < timestamp: self.__showSplat(position, direction, hot) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: #self.notify.debug('localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToPieHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearHitInterval(self): if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.clearToInitial() def __showSplat(self, position, direction, hot=False): """Show the splat graphic and sound.""" if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.clearHitInterval() splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splat.reparentTo(render) self.splat.setPos(self.root, position) self.splat.setAlphaScale(1.0) if not direction == 1.0: #self.splat.setColorScale(Vec4(0.0, 0.0, 50.0, 1.0)) self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0]) if self.currentFacing > 0.0: facing = "HitFront" else: facing = "HitBack" else: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1]) #self.splat.setColorScale(Vec4(1.0, 0.6, 0.08, 1.0)) if self.currentFacing > 0.0: facing = "HitBack" else: facing = "HitFront" if hot: targetscale = 0.75 part = "head" else: targetscale = 0.5 part = "body" def setSplatAlpha(amount): self.splat.setAlphaScale(amount) self.hitInterval = Sequence( ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, "idle"), ) self.hitInterval.start() self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence( Func(self.splat.showThrough), Parallel( Sequence( LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType="easeOut"), Wait(0.175), ), Sequence( Wait(0.1), LerpFunc( setSplatAlpha, duration=1.0, #0.4, fromData=1.0, toData=0.0, blendType="easeOut"))), Func(self.splat.cleanup), Func(self.splat.removeNode), )) self.kaboomTrack.start() def showHitScore(self, number, scale=1): """ Shows the hit score. Borrowed from otp.avatar.DistributedAvatar.showHpText """ if number <= 0: return # Get rid of the number if it is already there. if self.hpText: self.hideHitScore() # Set the font self.HpTextGenerator.setFont(ToontownGlobals.getSignFont()) # Show both negative and positive signs if number < 0: self.HpTextGenerator.setText(str(number)) else: self.HpTextGenerator.setText("+" + str(number)) # No shadow self.HpTextGenerator.clearShadow() # Center the number self.HpTextGenerator.setAlign(TextNode.ACenter) # Red, always #if number < 0: r = 1 #0.9 g = 1 #0 b = 0 a = 1 self.HpTextGenerator.setTextColor(r, g, b, a) self.hpTextNode = self.HpTextGenerator.generate() # Put the hpText over the head of the avatar self.hpText = render.attachNewNode(self.hpTextNode) self.hpText.setScale(scale) # Make sure it is a billboard self.hpText.setBillboardPointEye() # Render it after other things in the scene. self.hpText.setBin('fixed', 100) # Initial position ... Center of the body... the "tan tien" self.hpText.setPos(self.root, 0, 0, self.height / 2) # Black magic from the early days of Panda3D, later replaced by a Sequence seq = Task.sequence( # Fly the number out of the character self.hpText.lerpPos(Point3( self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), 0.25, blendType='easeOut'), Task.pause(0.25), # Fade the number self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1), # Get rid of the number Task.Task(self.__hideHitScoreTask)) taskMgr.add(seq, "PartyCogHpText" + str(self.id)) def __hideHitScoreTask(self, task): self.hideHitScore() return Task.done def hideHitScore(self): if self.hpText: taskMgr.remove("PartyCogHpText" + str(self.id)) self.hpText.removeNode() self.hpText = None def getHeadLocation(self): (self.actor.getJoints(jointName="head")[0]).getNetTransform( self.temp_transform) self.head_locator.setMat(self.temp_transform) #print self.head_locator.getZ() return self.head_locator.getZ(self.root)
class DistributedPartyGate(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyGate') def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.publicPartyChooseGuiDoneEvent = 'doneChoosingPublicParty' self.publicPartyGui = PublicPartyGui(self.publicPartyChooseGuiDoneEvent) self.publicPartyGui.stash() self.loadClockSounds() self.hourSoundInterval = Sequence() self.accept('stoppedAsleep', self.handleSleep) def loadClockSounds(self): self.clockSounds = [] for i in xrange(1, 13): if i < 10: si = '0%d' % i else: si = '%d' % i self.clockSounds.append(base.loader.loadSfx('phase_4/audio/sfx/clock%s.ogg' % si)) def generate(self): DistributedObject.DistributedObject.generate(self) loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGate_grp') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return self.clockFlat = partyGate.find('**/clock_flat') collSphere = CollisionSphere(0, 0, 0, 6.9) collSphere.setTangible(1) self.partyGateSphere = CollisionNode('PartyGateSphere') self.partyGateSphere.addSolid(collSphere) self.partyGateCollNodePath = partyGate.find('**/partyGate_stepsLocator').attachNewNode(self.partyGateSphere) self.__enableCollisions() self.toontownTimeGui = ServerTimeGui(partyGate, hourCallback=self.hourChange) self.toontownTimeGui.setPos(partyGate.find('**/clockText_locator').getPos() + Point3(0.0, 0.0, -0.2)) self.toontownTimeGui.setHpr(partyGate.find('**/clockText_locator').getHpr()) self.toontownTimeGui.setScale(12.0, 1.0, 26.0) self.toontownTimeGui.amLabel.setPos(-0.035, 0, -0.032) self.toontownTimeGui.amLabel.setScale(0.5) self.toontownTimeGui.updateTime() self.setupSignText() def setupSignText(self): loader = self.cr.playGame.hood.loader partyGate = loader.geom.find('**/partyGateSignGroup') if partyGate.isEmpty(): self.notify.warning('Could not find partyGate_grp in loader.geom') return gateFont = ToontownGlobals.getMinnieFont() leftSign = partyGate.find('**/signTextL_locatorBack') signScale = 0.35 wordWrap = 8 leftText = DirectLabel.DirectLabel(parent=leftSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateLeftSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale) rightSign = partyGate.find('**/signTextR_locatorFront') rightText = DirectLabel.DirectLabel(parent=rightSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateRightSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.7, 0.3, 0.3, 1.0), scale=signScale) return def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) if self.zoneId in ToontownGlobals.dnaMap: playground = ToontownGlobals.dnaMap[self.zoneId] else: playground = ToontownGlobals.dnaMap[2000] self.toontownTimeGui.hourLabel['text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.colonLabel['text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.minutesLabel['text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.amLabel['text_fg'] = PartyGlobals.PlayGroundToPartyClockColors[playground] def disable(self): DistributedObject.DistributedObject.disable(self) self.__disableCollisions() self.toontownTimeGui.ival.finish() self.hourSoundInterval.finish() if self.publicPartyGui: self.publicPartyGui.stash() self.publicPartyGui.destroy() self.publicPartyGui = None return def delete(self): DistributedObject.DistributedObject.delete(self) self.toontownTimeGui.destroy() del self.toontownTimeGui self.hourSoundInterval.finish() del self.hourSoundInterval del self.clockFlat if self.publicPartyGui: self.publicPartyGui.destroy() del self.publicPartyGui self.partyGateCollNodePath.removeNode() del self.partyGateCollNodePath self.ignoreAll() def showMessage(self, message): self.messageDoneEvent = self.uniqueName('messageDoneEvent') self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone) self.messageGui = TTDialog.TTGlobalDialog(doneEvent=self.messageDoneEvent, message=message, style=TTDialog.Acknowledge) def __handleMessageDone(self): self.ignore(self.messageDoneEvent) self.freeAvatar() self.messageGui.cleanup() self.messageGui = None return def __handleAskDone(self): DistributedPartyGate.notify.debug('__handleAskDone') self.ignore(self.publicPartyChooseGuiDoneEvent) doneStatus = self.publicPartyGui.doneStatus self.publicPartyGui.stash() if doneStatus is None: self.freeAvatar() return self.sendUpdate('partyChoiceRequest', [base.localAvatar.doId, doneStatus[0], doneStatus[1]]) return def partyRequestDenied(self, reason): DistributedPartyGate.notify.debug('partyRequestDenied( reason=%s )' % PartyGlobals.PartyGateDenialReasons.getString(reason)) if reason == PartyGlobals.PartyGateDenialReasons.Unavailable: self.showMessage(TTLocalizer.PartyGatePartyUnavailable) elif reason == PartyGlobals.PartyGateDenialReasons.Full: self.showMessage(TTLocalizer.PartyGatePartyFull) def setParty(self, partyInfoTuple, hostId): DistributedPartyGate.notify.debug('setParty') self.freeAvatar() if partyInfoTuple[0] == 0: DistributedPartyGate.notify.debug('Public Party closed before toon could get to it.') return shardId, zoneId, numberOfGuests, hostName, activityIds, lane = partyInfoTuple #For some reason, the party gate is attempting to teleport to the host of a party rather than a random spot in the party. #This temporarily fixes a hang on the loading screen if base.localAvatar.defaultShard != shardId: shardId = None base.cr.playGame.getPlace().requestLeave({'loader': 'safeZoneLoader', 'where': 'party', 'how': 'teleportIn', 'hoodId': ToontownGlobals.PartyHood, 'zoneId': zoneId, 'shardId': None, 'avId': hostId}) return def freeAvatar(self): base.localAvatar.posCamera(0, 0) base.cr.playGame.getPlace().setState('walk') def hourChange(self, currentHour): currentHour = currentHour % 12 if currentHour == 0: currentHour = 12 self.hourSoundInterval = Parallel() seq1 = Sequence() for i in xrange(currentHour): seq1.append(SoundInterval(self.clockSounds[i])) seq1.append(Wait(0.2)) timeForEachDeformation = seq1.getDuration() / currentHour seq2 = Sequence() for i in xrange(currentHour): seq2.append(self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(0.9, 1.0, 1.2), blendType='easeInOut')) seq2.append(self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.2, 1.0, 0.9), blendType='easeInOut')) seq2.append(self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.0, 1.0, 1.0), blendType='easeInOut')) self.hourSoundInterval.append(seq1) self.hourSoundInterval.append(seq2) self.hourSoundInterval.start() def handleEnterGateSphere(self, collEntry): self.notify.debug('Entering steps Sphere....') base.cr.playGame.getPlace().fsm.request('stopped') self.sendUpdate('getPartyList', [base.localAvatar.doId]) def listAllPublicParties(self, publicPartyInfo): self.notify.debug('listAllPublicParties : publicPartyInfo = %s' % publicPartyInfo) self.acceptOnce(self.publicPartyChooseGuiDoneEvent, self.__handleAskDone) self.publicPartyGui.refresh(publicPartyInfo) self.publicPartyGui.unstash() def __enableCollisions(self): self.accept('enterPartyGateSphere', self.handleEnterGateSphere) self.partyGateSphere.setCollideMask(OTPGlobals.WallBitmask) def __disableCollisions(self): self.ignore('enterPartyGateSphere') self.partyGateSphere.setCollideMask(BitMask32(0)) def handleSleep(self): if hasattr(self, 'messageGui') and self.messageGui: self.__handleMessageDone()
class PartyCog(FSM): notify = directNotify.newCategory('PartyCog') HpTextGenerator = TextNode('HpTextGenerator') hpText = None height = 7 def __init__(self, parentNode, id, bounceSpeed = 3, bounceHeight = 1, rotateSpeed = 1, heightShift = 1, xMoveSpeed = 0, xMoveDistance = 0, bounceOffset = 0): self.id = id FSM.__init__(self, 'PartyCogFSM-%d' % self.id) self.showFacingStatus = False self.xMoveSpeed = xMoveSpeed self.xMoveDistance = xMoveDistance self.heightShift = heightShift self.bounceSpeed = bounceSpeed self.bounceHeight = bounceHeight self.rotateSpeed = rotateSpeed self.parentNode = parentNode self.bounceOffset = bounceOffset self.hitInterval = None self.kaboomTrack = None self.resetRollIval = None self.netTimeSentToStartByHit = 0 self.load() self.request('Down') return def load(self): self.root = NodePath('PartyCog-%d' % self.id) self.root.reparentTo(self.parentNode) path = 'phase_13/models/parties/cogPinata_' self.actor = Actor(path + 'actor', {'idle': path + 'idle_anim', 'down': path + 'down_anim', 'up': path + 'up_anim', 'bodyHitBack': path + 'bodyHitBack_anim', 'bodyHitFront': path + 'bodyHitFront_anim', 'headHitBack': path + 'headHitBack_anim', 'headHitFront': path + 'headHitFront_anim'}) self.actor.reparentTo(self.root) self.temp_transform = Mat4() self.head_locator = self.actor.attachNewNode('temphead') self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75) self.bodyColl.setTangible(1) self.bodyCollNode = CollisionNode('PartyCog-%d-Body-Collision' % self.id) self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.bodyCollNode.addSolid(self.bodyColl) self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode) self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5) self.headColl.setTangible(1) self.headCollNode = CollisionNode('PartyCog-%d-Head-Collision' % self.id) self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.headCollNode.addSolid(self.headColl) self.headCollNodePath = self.root.attachNewNode(self.headCollNode) self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0) self.arm1Coll.setTangible(1) self.arm1CollNode = CollisionNode('PartyCog-%d-Arm1-Collision' % self.id) self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm1CollNode.addSolid(self.arm1Coll) self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode) self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0) self.arm2Coll.setTangible(1) self.arm2CollNode = CollisionNode('PartyCog-%d-Arm2-Collision' % self.id) self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm2CollNode.addSolid(self.arm2Coll) self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode) splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound('AA_wholepie_only.ogg') self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.ogg') self.hole = loader.loadModel('phase_13/models/parties/cogPinataHole') self.hole.setTransparency(True) self.hole.setP(-90.0) self.hole.setScale(3) self.hole.setBin('ground', 3) self.hole.reparentTo(self.parentNode) def unload(self): self.request('Off') self.clearHitInterval() if self.hole is not None: self.hole.removeNode() self.hole = None if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboomTrack = None if self.resetRollIval is not None and self.resetRollIval.isPlaying(): self.resetRollIval.finish() self.resetRollIval = None if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.finish() self.hitInterval = None del self.upSound del self.pieHitSound return def enterStatic(self): pass def exitStatic(self): pass def enterActive(self, startTime): self.root.setR(0.0) updateTask = Task.Task(self.updateTask) updateTask.startTime = startTime taskMgr.add(updateTask, 'PartyCog.update-%d' % self.id) def exitActive(self): taskMgr.remove('PartyCog.update-%d' % self.id) taskMgr.remove('PartyCog.bounceTask-%d' % self.id) self.clearHitInterval() self.resetRollIval = self.root.hprInterval(0.5, Point3(self.root.getH(), 0.0, 0.0), blendType='easeInOut') self.resetRollIval.start() self.actor.stop() def enterDown(self): if self.oldState == 'Off': downAnimControl = self.actor.getAnimControl('down') self.actor.pose('down', downAnimControl.getNumFrames() - 1) return self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence(LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel(SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'down', loop=0)), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def exitDown(self): self.root.setR(0.0) self.root.setH(0.0) self.targetDistance = 0.0 self.targetFacing = 0.0 self.currentT = 0.0 self.setAlongSpline(0.0) self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence(LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel(SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'up', loop=0)), Func(self.actor.loop, 'idle'), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def filterDown(self, request, args): if request == 'Down': return None else: return self.defaultFilter(request, args) return None def setEndPoints(self, start, end, amplitude = 1.7): self.sinAmplitude = amplitude self.sinPeriod = (end.getX() - start.getX()) / 2 self.sinDisplacement = start.getY() self.startPoint = start self.endPoint = end self.currentT = 0.0 self.targetDistance = 0.0 self.currentFacing = 0.0 self.targetFacing = 0.0 self.setAlongSpline(self.currentT) self.hole.setPos(self.root.getPos()) self.hole.setZ(0.02) def rockBackAndForth(self, task): t = task.startTime + task.time angle = math.sin(t) * 20.0 self.root.setR(angle) return task.cont def updateDistance(self, distance): self.targetDistance = clamp(distance, -1.0, 1.0) def updateTask(self, task): self.rockBackAndForth(task) if self.targetDistance > self.currentT: self.currentT += min(0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) elif self.targetDistance < self.currentT: self.currentT += max(-0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) if self.currentT < 0.0: self.targetFacing = -90.0 elif self.currentT > 0.0: self.targetFacing = 90.0 else: self.targetFacing = 0.0 if self.targetFacing > self.currentFacing: self.currentFacing += min(10, self.targetFacing - self.currentFacing) elif self.targetFacing < self.currentFacing: self.currentFacing += max(-10, self.targetFacing - self.currentFacing) self.root.setH(self.currentFacing) return task.cont def setAlongSpline(self, t): t = t + 1.0 dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0 x = self.startPoint.getX() + t * dist y = self.startPoint.getY() - math.sin(t * 2 * math.pi) * self.sinAmplitude self.root.setPos(x, y, 0) def startBounce(self): taskMgr.add(self.bounce, 'PartyCog.bounceTask-%d' % self.id) def bounce(self, task): self.root.setZ(math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight + self.heightShift) return task.cont def setPos(self, position): self.root.setPos(position) def respondToPieHit(self, timestamp, position, hot = False, direction = 1.0): if self.netTimeSentToStartByHit < timestamp: self.__showSplat(position, direction, hot) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug('respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearHitInterval(self): if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.clearToInitial() return def __showSplat(self, position, direction, hot = False): if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.clearHitInterval() splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splat.reparentTo(render) self.splat.setPos(self.root, position) self.splat.setAlphaScale(1.0) if not direction == 1.0: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0]) if self.currentFacing > 0.0: facing = 'HitFront' else: facing = 'HitBack' else: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1]) if self.currentFacing > 0.0: facing = 'HitBack' else: facing = 'HitFront' if hot: targetscale = 0.75 part = 'head' else: targetscale = 0.5 part = 'body' def setSplatAlpha(amount): self.splat.setAlphaScale(amount) self.hitInterval = Sequence(ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, 'idle')) self.hitInterval.start() self.kaboomTrack = Parallel(SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence(Func(self.splat.showThrough), Parallel(Sequence(LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Wait(0.175)), Sequence(Wait(0.1), LerpFunc(setSplatAlpha, duration=1.0, fromData=1.0, toData=0.0, blendType='easeOut'))), Func(self.splat.cleanup), Func(self.splat.removeNode))) self.kaboomTrack.start() return def showHitScore(self, number, scale = 1): if number <= 0: return if self.hpText: self.hideHitScore() self.HpTextGenerator.setFont(ToontownGlobals.getSignFont()) if number < 0: self.HpTextGenerator.setText(str(number)) else: self.HpTextGenerator.setText('+' + str(number)) self.HpTextGenerator.clearShadow() self.HpTextGenerator.setAlign(TextNode.ACenter) r = 1 g = 1 b = 0 a = 1 self.HpTextGenerator.setTextColor(r, g, b, a) self.hpTextNode = self.HpTextGenerator.generate() self.hpText = render.attachNewNode(self.hpTextNode) self.hpText.setScale(scale) self.hpText.setBillboardPointEye() self.hpText.setBin('fixed', 100) self.hpText.setPos(self.root, 0, 0, self.height / 2) seq = Sequence(self.hpText.posInterval(0.25, Point3(self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), blendType='easeOut'), Wait(0.25), self.hpText.colorInterval(0.1, Vec4(r, g, b, 0)), Func(self.__hideHitScore)) seq.start() def hideHitScore(self): if self.hpText: taskMgr.remove('PartyCogHpText' + str(self.id)) self.hpText.removeNode() self.hpText = None return def getHeadLocation(self): self.actor.getJoints(jointName='head')[0].getNetTransform(self.temp_transform) self.head_locator.setMat(self.temp_transform) return self.head_locator.getZ(self.root)
class DistributedPartyTrampolineActivity(DistributedPartyActivity): notify = DirectNotifyGlobal.directNotify.newCategory( "DistributedPartyTrampolineActivity") def __init__(self, cr, doJellyBeans=True, doTricks=False, texture=None): DistributedPartyTrampolineActivity.notify.debug("__init__") DistributedPartyActivity.__init__( self, cr, PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityTypes.GuestInitiated, wantLever=False, wantRewardGui=True, ) self.doJellyBeans = doJellyBeans self.doTricks = doTricks self.texture = texture self.toon = None self.trampHeight = 3.6 self.trampK = 400.0 # spring constant self.normalTrampB = 2.5 # spring damping self.leavingTrampB = 8.0 # increase damping to slow toon faster when leaving self.trampB = self.normalTrampB self.g = -32.0 # acceleration due to gravity self.jumpBoost = 330.0 self.beginningBoost = 500.0 self.beginningBoostThreshold = self.trampHeight + 1.5 self.earlyJumpThreshold = 75.0 self.boingThreshold = 300.0 self.turnFactor = 120.0 self.stepDT = 0.001 self.targetCameraPos = Point3(0.0, 40.0, 10.0) # relative to toon self.cameraSpeed = 2.0 self.hopOffPos = Point3(16.0, 0.0, 0.0) # relative to tramp self.indicatorFactor = 0.0095 self.dropShadowCutoff = 15.0 self.minHeightForText = 15.0 self.heightTextOffset = -0.065 self.beanOffset = 0.5 self.guiBeanOffset = -0.02 self.jumpTextShown = False self.toonJumped = False self.turnLeft = False self.turnRight = False self.leavingTrampoline = False self.toonVelocity = 0.0 self.topHeight = 0.0 self.lastPeak = 0.0 self.beginRoundInterval = None self.hopOnAnim = None self.hopOffAnim = None self.flashTextInterval = None # Jelly Beans self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans # These are in PartyGlobals so they can be available to the AI. self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus self.jellyBeanStartHeight = 20.0 self.jellyBeanStopHeight = 90.0 self.jellyBeanColors = [ VBase4(1.0, 0.5, 0.5, 1.0), VBase4(0.5, 1.0, 0.5, 1.0), VBase4(0.5, 1.0, 1.0, 1.0), VBase4(1.0, 1.0, 0.4, 1.0), VBase4(0.4, 0.4, 1.0, 1.0), VBase4(1.0, 0.5, 1.0, 1.0), ] delta = (self.jellyBeanStopHeight - self.jellyBeanStartHeight) / (self.numJellyBeans - 1) self.jellyBeanPositions = [ self.jellyBeanStartHeight + n * delta for n in range(self.numJellyBeans) ] self.doSimulateStep = False # import sys # sys.path.append( "C:\\pratt\\SchellGames\\perforce\\depot\\Tools\\PandaMisc" ) # from Reloader import Reloader # self.reloader = Reloader( "C:\\cygwin\\home\\pratt\\player_working\\toontown\\src\\parties" ) #--------------------------------------------------- # Loading #--------------------------------------------------- def load(self): DistributedPartyTrampolineActivity.notify.debug("load") DistributedPartyActivity.load(self) self.loadModels() self.loadCollision() self.loadGUI() self.loadSounds() self.loadIntervals() self.activityFSM = TrampolineActivityFSM(self) self.activityFSM.request("Idle") self.animFSM = TrampolineAnimFSM(self) self.setBestHeightInfo("", 0) def loadModels(self): self.tramp = self.root.attachNewNode(self.uniqueName("tramp")) self.screenPlaneElements = NodePath(self.uniqueName("screenPlane")) self.trampActor = Actor( "phase_13/models/parties/trampoline_model", {"emptyAnim": "phase_13/models/parties/trampoline_anim"}, ) self.trampActor.reparentTo(self.tramp) # Allow reskinning. if self.texture: reskinNode = self.tramp.find( "**/trampoline/__Actor_modelRoot/-GeomNode") reskinNode.setTexture(loader.loadTexture(self.texture), 100) self.surface = NodePath(self.uniqueName("trampSurface")) self.surface.reparentTo(self.tramp) self.surface.setZ(self.trampHeight) self.trampActor.controlJoint(self.surface, "modelRoot", "trampoline_joint1") self.sign.setPos(PartyGlobals.TrampolineSignOffset) self.beans = [ loader.loadModelCopy("phase_4/models/props/jellybean4") for i in range(self.numJellyBeans) ] for bean in self.beans: bean.find("**/jellybean").setP(-35.0) bean.setScale(3.0) bean.setTransparency(True) bean.reparentTo(self.tramp) bean.stash() self.beans[-1].setScale(8.0) def loadCollision(self): collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4) collTube.setTangible(True) self.trampolineCollision = CollisionNode( self.uniqueName("TrampolineCollision")) self.trampolineCollision.addSolid(collTube) self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask | OTPGlobals.WallBitmask) self.trampolineCollisionNP = self.tramp.attachNewNode( self.trampolineCollision) collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0) collSphere.setTangible(False) self.trampolineTrigger = CollisionNode( self.uniqueName("TrampolineTrigger")) self.trampolineTrigger.addSolid(collSphere) self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask) self.trampolineTriggerNP = self.tramp.attachNewNode( self.trampolineTrigger) self.accept("enter%s" % self.uniqueName("TrampolineTrigger"), self.onTrampolineTrigger) def loadGUI(self): self.gui = loader.loadModel("phase_13/models/parties/trampolineGUI") self.gui.setX(-1.15) self.gui.reparentTo(self.screenPlaneElements) self.toonIndicator = self.gui.find("**/trampolineGUI_MovingBar") jumpLineLocator = self.gui.find("**/jumpLine_locator") guiBean = self.gui.find("**/trampolineGUI_GreenJellyBean") self.gui.find("**/trampolineGUI_GreenJellyBean").stash( ) # sadly, the white jelly bean is named GreenJellyBean self.guiBeans = [ guiBean.instanceUnderNode(jumpLineLocator, self.uniqueName("guiBean%d" % i)) for i in range(self.numJellyBeans) ] self.guiBeans[-1].setScale(1.5) heightTextNode = TextNode( self.uniqueName("TrampolineActivity.heightTextNode")) heightTextNode.setFont(ToontownGlobals.getSignFont()) heightTextNode.setAlign(TextNode.ALeft) heightTextNode.setText("0.0") heightTextNode.setShadow(0.05, 0.05) heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0) heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0) self.heightText = jumpLineLocator.attachNewNode(heightTextNode) self.heightText.setX(0.15) self.heightText.setScale(0.1) self.heightText.setAlphaScale(0.0) self.quitEarlyButtonModels = loader.loadModel( "phase_3.5/models/gui/inventory_gui") quitEarlyUp = self.quitEarlyButtonModels.find("**//InventoryButtonUp") quitEarlyDown = self.quitEarlyButtonModels.find( "**/InventoryButtonDown") quitEarlyRollover = self.quitEarlyButtonModels.find( "**/InventoryButtonRollover") self.quitEarlyButton = DirectButton( parent=self.screenPlaneElements, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(1.15, 0, 0.6), scale=0.09, command=self.leaveTrampoline, ) self.quitEarlyButton.stash() self.flashText = OnscreenText( text="", pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True, ) self.timer = PartyUtils.getNewToontownTimer() self.timer.reparentTo(self.screenPlaneElements) def loadSounds(self): self.jellyBeanSound = base.loadSfx("phase_4/audio/sfx/sparkly.mp3") self.boingSound = base.loadSfx( "phase_4/audio/sfx/target_trampoline_2.mp3") self.whistleSound = base.loadSfx( "phase_4/audio/sfx/AA_sound_whistle.mp3") def loadIntervals(self): def prepareHeightText(): self.heightText.node().setText( TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ())) self.heightText.setZ(self.indicatorFactor * self.toon.getZ() + self.heightTextOffset) self.heightTextInterval = Sequence( Func(prepareHeightText), LerpFunc(self.heightText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), ) def unload(self): DistributedPartyTrampolineActivity.notify.debug("unload") if self.hopOnAnim and self.hopOnAnim.isPlaying(): self.hopOnAnim.finish() if self.hopOffAnim and self.hopOffAnim.isPlaying(): self.hopOffAnim.finish() if self.beginRoundInterval and self.beginRoundInterval.isPlaying(): self.beginRoundInterval.finish() if self.flashTextInterval and self.flashTextInterval.isPlaying(): self.flashTextInterval.finish() if self.heightTextInterval and self.heightTextInterval.isPlaying(): self.heightTextInterval.finish() self.timer.stop() DistributedPartyActivity.unload(self) # Unload tasks taskMgr.remove(self.uniqueName("TrampolineActivity.updateTask")) taskMgr.remove(self.uniqueName("TrampolineActivity.remoteUpdateTask")) # Unload events self.ignoreAll() # Unload intervals del self.heightTextInterval del self.beginRoundInterval del self.hopOnAnim del self.hopOffAnim del self.flashTextInterval if hasattr(self, 'beanAnims'): # we need to cleanup the jelly bean interval self.cleanupJellyBeans() # Unload gui stuff self.quitEarlyButton.destroy() del self.quitEarlyButton if self.screenPlaneElements: self.screenPlaneElements.removeNode() self.screenPlaneElements = None # Unload fsms del self.activityFSM del self.animFSM #--------------------------------------------------- # Distributed #--------------------------------------------------- def setBestHeightInfo(self, toonName, height): if GMUtils.testGMIdentity(toonName): toonName = GMUtils.handleGMName(toonName) self.bestHeightInfo = (toonName, height) DistributedPartyTrampolineActivity.notify.debug( "%s has the best height of %d" % (toonName, height)) if height > 0: self.setSignNote(TTLocalizer.PartyTrampolineBestHeight % self.bestHeightInfo) else: self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet) def leaveTrampoline(self): if self.toon != None and self.toon.doId == base.localAvatar.doId: self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp) self.leavingTrampoline = True self.timer.reset() self.trampB = self.leavingTrampB self.ignore("control") self.quitEarlyButton.stash() def requestAnim(self, request): self.animFSM.request(request) def b_requestAnim(self, request): self.requestAnim(request) self.sendUpdate("requestAnim", [request]) def requestAnimEcho(self, request): if self.toon != None and self.toon.doId != base.localAvatar.doId: self.requestAnim(request) def removeBeans(self, beansToRemove): for i in beansToRemove: height, bean, guiBean, beanAnim = self.beanDetails[i] guiBean.stash() if i in self.beansToCollect: self.beansToCollect.remove(i) else: self.notify.warning( "removeBeans avoided a crash, %d not in self.beansToCollect" % i) self.poofBean(bean, beanAnim) # bean.stash() # beanAnim.finish() def b_removeBeans(self, beansToRemove): self.removeBeans(beansToRemove) self.sendUpdate("removeBeans", [beansToRemove]) def removeBeansEcho(self, beansToRemove): if self.toon != None and self.toon.doId != base.localAvatar.doId: self.removeBeans(beansToRemove) def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny) base.cr.playGame.getPlace().fsm.request("walk") def exitRequestDenied(self, reason): DistributedPartyActivity.exitRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny) def setState(self, newState, timestamp): DistributedPartyTrampolineActivity.notify.debug( "setState( newState=%s, ... )" % newState) DistributedPartyActivity.setState(self, newState, timestamp) self.activityFSM.request(newState) #--------------------------------------------------- # FSM handling #--------------------------------------------------- def startIdle(self): DistributedPartyTrampolineActivity.notify.debug("startIdle") def finishIdle(self): DistributedPartyTrampolineActivity.notify.debug("finishIdle") def startRules(self): DistributedPartyTrampolineActivity.notify.debug("startRules") if self.doJellyBeans: self.setupJellyBeans() if self.toon != None and self.toon.doId == base.localAvatar.doId: self.acquireToon() def startActive(self): DistributedPartyTrampolineActivity.notify.debug("startActive") if self.toon != None and self.toon.doId == base.localAvatar.doId: base.setCellsAvailable(base.bottomCells, True) self.accept("arrow_left", self.onLeft) self.accept("arrow_left-up", self.onLeftUp) self.accept("arrow_right", self.onRight) self.accept("arrow_right-up", self.onRightUp) self.beginRoundInterval = Sequence( Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady), Wait(1.2), Func(self.flashMessage, TTLocalizer.PartyTrampolineGo), Func(self.beginRound)) self.beginRoundInterval.start() def finishActive(self): DistributedPartyTrampolineActivity.notify.debug("finishActive") if self.doJellyBeans: self.cleanupJellyBeans() #--------------------------------------------------- # FSM extras #--------------------------------------------------- def setupJellyBeans(self): self.beanAnims = [] self.beansToCollect = [] self.beanDetails = [] self.numBeansCollected = 0 for i in range(self.numJellyBeans): bean = self.beans[i] guiBean = self.guiBeans[i] height = self.jellyBeanPositions[i] color = random.choice(self.jellyBeanColors) bean.find("**/jellybean").setColor(color) if self.toon.doId == base.localAvatar.doId: bean.setAlphaScale(1.0) else: bean.setAlphaScale(0.5) guiBean.setColor(color) bean.setZ(height + self.toon.getHeight() + self.beanOffset) guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset) bean.setH(0.0) bean.unstash() guiBean.unstash() beanAnim = bean.hprInterval( 1.5, VBase3((((i % 2) * 2) - 1) * 360.0, 0.0, 0.0) ) # the (((i % 2)*2) - 1) makes adjacent beans spin opposite directions beanAnim.loop() self.beanAnims.append(beanAnim) self.beanDetails.append((height, bean, guiBean, beanAnim)) self.beansToCollect = range(self.numJellyBeans) def cleanupJellyBeans(self): for bean in self.beans: bean.stash() for guiBean in self.guiBeans: guiBean.stash() # If handleToonJoined hasn't been sent toonId on some clients if hasattr(self, 'beanAnims'): for beanAnim in self.beanAnims: beanAnim.finish() del self.beanAnims del self.beansToCollect def beginRound(self): base.playSfx(self.whistleSound) self.timer.setTime(PartyGlobals.TrampolineDuration) self.timer.countdown(PartyGlobals.TrampolineDuration) self.timer.show() self.quitEarlyButton.unstash() self.notify.debug("Accepting contorl") self.accept("control", self.onJump) self.notify.debug("setting simulate step to true") self.doSimulateStep = True def acquireToon(self): # self.dataLog = open( "dataLog.txt", "w" ) self.toon.disableSmartCameraViews() self.toon.stopUpdateSmartCamera() camera.wrtReparentTo(render) self.toon.dropShadow.reparentTo(hidden) self.toon.startPosHprBroadcast(period=0.2) self.toonAcceleration = 0.0 self.toonVelocity = 0.0 self.topHeight = 0.0 self.trampB = self.normalTrampB self.leavingTrampoline = False self.hopOnAnim = Sequence( Func(self.toon.b_setAnimState, "jump", 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, Point3(0.0, 0.0, self.trampHeight), 5.0, self.tramp), Func(self.postHopOn), ) self.hopOnAnim.start() def postHopOn(self): self.toon.setH(self.toon.getH() + 90.0) # makes camera adjustment less jarring self.toon.dropShadow.reparentTo(self.surface) self.screenPlaneElements.reparentTo(aspect2d) self.timeLeftToSimulate = 0.0 self.doSimulateStep = False taskMgr.add(self.updateTask, self.uniqueName("TrampolineActivity.updateTask")) base.setCellsAvailable(base.leftCells, False) base.setCellsAvailable(base.bottomCells, False) DistributedPartyActivity.startRules(self) def releaseToon(self): self._hideFlashMessage() self.ignore("arrow_left") self.ignore("arrow_left-up") self.ignore("arrow_right") self.ignore("arrow_right-up") taskMgr.remove(self.uniqueName("TrampolineActivity.updateTask")) self.hopOffAnim = Sequence( self.toon.hprInterval(0.5, VBase3(-90.0, 0.0, 0.0), other=self.tramp), Func(self.toon.b_setAnimState, "jump", 1.0), Func(self.toon.dropShadow.reparentTo, hidden), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0, self.tramp), Func(self.postHopOff), ) self.hopOffAnim.start() def postHopOff(self): self.screenPlaneElements.reparentTo(hidden) base.setCellsAvailable(base.leftCells, True) self.timer.stop() self.timer.hide() self.toon.dropShadow.reparentTo(self.toon.getShadowJoint()) self.toon.dropShadow.setAlphaScale(1.0) self.toon.dropShadow.setScale(1.0) # Continue broadcasting so remote toons see us reach the final hop off position. #self.toon.stopPosHprBroadcast() self.b_requestAnim("Off") camera.reparentTo(base.localAvatar) base.localAvatar.startUpdateSmartCamera() base.localAvatar.enableSmartCameraViews() base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex) place = base.cr.playGame.getPlace() if self.doJellyBeans: self.sendUpdate("awardBeans", [self.numBeansCollected, int(self.topHeight)]) if int(self.topHeight) > self.bestHeightInfo[1]: self.sendUpdate("reportHeightInformation", [int(self.topHeight)]) self.d_toonExitDemand() #--------------------------------------------------- # Event Handling #--------------------------------------------------- def onTrampolineTrigger(self, collEntry): if (self.activityFSM.state == "Idle") and (self.toon == None) and ( base.cr.playGame.getPlace().fsm.getCurrentState().getName() == "walk"): base.cr.playGame.getPlace().fsm.request("activity") self.d_toonJoinRequest() else: self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied, duration=2.0) def onJump(self): self.notify.debug("got onJump") if self.toon != None and self.toon.getZ() < self.trampHeight: # Have to be on the trampoline self.toonJumped = True self.b_requestAnim("Jump") else: self.notify.debug("z is less than tramp height") def onLeft(self): self.turnLeft = True def onLeftUp(self): self.turnLeft = False def onRight(self): self.turnRight = True def onRightUp(self): self.turnRight = False #--------------------------------------------------- # Super class functionality #--------------------------------------------------- def handleToonJoined(self, toonId): DistributedPartyTrampolineActivity.notify.debug("handleToonJoined") self.toon = self.getAvatar(toonId) if self.toon != None and not self.toon.isEmpty(): self.oldJumpSquatPlayRate = self.toon.getPlayRate("jump-squat") self.oldJumpLandPlayRate = self.toon.getPlayRate("jump-land") self.toon.setPlayRate(2.5, "jump-squat") self.toon.setPlayRate(2.0, "jump-land") self.turnLeft = False self.turnRight = False self.activityFSM.request("Rules") if self.toon.doId != base.localAvatar.doId: taskMgr.add( self.remoteUpdateTask, self.uniqueName("TrampolineActivity.remoteUpdateTask")) else: self.notify.warning("handleToonJoined could not get toon %d" % toonId) def handleToonExited(self, toonId): DistributedPartyTrampolineActivity.notify.debug("handleToonExited") if self.toon != None: if self.toon.doId != base.localAvatar.doId: taskMgr.remove( self.uniqueName("TrampolineActivity.remoteUpdateTask")) self.surface.setZ(self.trampHeight) self.toon.setPlayRate(self.oldJumpSquatPlayRate, "jump-squat") self.toon.setPlayRate(self.oldJumpLandPlayRate, "jump-land") self.toon = None def handleToonDisabled(self, toonId): """ A toon dropped unexpectedly from the game. Handle it! """ DistributedPartyTrampolineActivity.notify.debug("handleToonDisabled") DistributedPartyTrampolineActivity.notify.debug("avatar " + str(toonId) + " disabled") if base.localAvatar.doId == toonId: self.releaseToon() def handleRulesDone(self): self.sendUpdate("toonReady") self.finishRules() def getTitle(self): if self.doJellyBeans: return TTLocalizer.PartyTrampolineJellyBeanTitle elif self.doTricks: return TTLocalizer.PartyTrampolineTricksTitle else: return DistributedPartyActivity.getTitle(self) def getInstructions(self): return TTLocalizer.PartyTrampolineActivityInstructions #--------------------------------------------------- # Simulation #--------------------------------------------------- def updateTask(self, task): # Only run on local client z = self.toon.getZ() dt = globalClock.getDt() if self.doSimulateStep: self.timeLeftToSimulate += dt while self.timeLeftToSimulate >= self.stepDT: z, a = self.simulateStep(z) self.timeLeftToSimulate -= self.stepDT self.toon.setZ(z) # Move tramp surface if z <= self.trampHeight: self.surface.setZ(z) else: self.surface.setZ(self.trampHeight) # Move toon indicator self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor) # Turn left or right if self.turnLeft: self.toon.setH(self.toon.getH() + self.turnFactor * dt) if self.turnRight: self.toon.setH(self.toon.getH() - self.turnFactor * dt) # Update camera currentPos = base.camera.getPos(self.toon) vec = self.targetCameraPos - currentPos newPos = currentPos + vec * (dt * self.cameraSpeed) base.camera.setPos(self.toon, newPos) base.camera.lookAt(self.toon) # Fade and scale drop shadow if z > self.trampHeight: heightFactor = 1.0 - min( 1.0, (z - self.trampHeight) / self.dropShadowCutoff) self.toon.dropShadow.setAlphaScale(heightFactor) self.toon.dropShadow.setScale(max(0.1, heightFactor)) else: self.toon.dropShadow.setAlphaScale(1.0) self.toon.dropShadow.setScale(1.0) # Leave trampoline if necessary if self.leavingTrampoline and (z < self.trampHeight) and (abs(a) < 0.1): self.releaseToon() # Simulate poor framerate # time.sleep( 0.03 ) return Task.cont def simulateStep(self, z): # Calculate acceleration if z >= self.trampHeight: # Above the trampoline; only use gravity. a = self.g # Clear jumped flag self.toonJumped = False else: # On the trampoline; use gravity + spring + damping a = self.g + self.trampK * (self.trampHeight - z) - self.trampB * self.toonVelocity # Add jump acceleration if necessary if self.toonJumped: # Don't penalize early jumps. # If we're above the earlyJumpThreshold, go ahead and add jump # acceleration, even if the toon hasn't bottomed out (which # will reduce the effectiveness of the jump). # Otherwise, only add jump acceleration, if the toon has # bottomed out (toonVelocity >= 0.0). #self.notify.debug("self.lastPeak=%s earlyJumpThreshold=%s toonVelocity=%s" %(self.lastPeak, self.earlyJumpThreshold, self.toonVelocity )) if (self.lastPeak > self.earlyJumpThreshold) or ( self.toonVelocity >= -3E5): a += self.jumpBoost # Add beginning boost if necessary. if self.lastPeak < self.beginningBoostThreshold: a += self.beginningBoost # Calculate velocity #import pdb; pdb.set_trace() lastVelocity = self.toonVelocity self.toonVelocity += a * self.stepDT if (lastVelocity > 0.0) and (self.toonVelocity <= 0.0): topOfJump = True bottomOfJump = False elif (lastVelocity < 0.0) and (self.toonVelocity >= 0.0): topOfJump = False bottomOfJump = True else: topOfJump = False bottomOfJump = False # optimal jumping # if bottomOfJump and self.isAccepting( "control" ): # self.toonJumped = True # print z # Calculate position newZ = z + self.toonVelocity * self.stepDT if newZ > self.topHeight: self.topHeight = newZ if self.doJellyBeans: self.collectJellyBeans(newZ) if topOfJump: # Set lastPeak self.lastPeak = newZ # Show height text if necessary if newZ >= self.minHeightForText: self.heightTextInterval.start() # Set anim state if topOfJump: if newZ > (self.trampHeight + 20.0): self.b_requestAnim("Falling") elif self.animFSM.state == "Jump": self.b_requestAnim("Falling") if (newZ <= self.trampHeight) and (z > self.trampHeight): if self.animFSM.state == "Falling": self.b_requestAnim("Land") elif self.animFSM.state != "Neutral": self.b_requestAnim("Neutral") # Play "boing" sound. if bottomOfJump and (a > self.boingThreshold): base.playSfx(self.boingSound) return newZ, a def collectJellyBeans(self, z): beansToRemove = [] for i in self.beansToCollect: height = self.beanDetails[i][0] if height <= z: beansToRemove.append(i) if len(beansToRemove) > 0: base.playSfx(self.jellyBeanSound) self.numBeansCollected += len(beansToRemove) self.b_removeBeans(beansToRemove) def remoteUpdateTask(self, task): # Only run on remote clients # Move tramp surface if self.toon != None and not self.toon.isEmpty(): z = self.toon.getZ() if z <= self.trampHeight: self.surface.setZ(z) else: self.surface.setZ(self.trampHeight) return Task.cont #--------------------------------------------------- # Misc #--------------------------------------------------- def poofBean(self, bean, beanAnim): if bean == None: self.notify.warning( "poofBean, returning immediately as bean is None") return if bean.isEmpty(): self.notify.warning( "poofBean, returning immediately as bean is empty") return currentAlpha = bean.getColorScale()[3] currentScale = bean.getScale() poofAnim = Sequence( Parallel( LerpFunc(bean.setAlphaScale, fromData=currentAlpha, toData=0.0, duration=0.25), LerpFunc(bean.setScale, fromData=currentScale, toData=currentScale * 5.0, duration=0.25), ), Func(bean.stash), Func(beanAnim.finish), Func(bean.setAlphaScale, currentAlpha), Func(bean.setScale, currentScale), ) poofAnim.start() def _showFlashMessage(self, message): if self.isDisabled(): assert self.notify.debug( "_showFlasMessage disabled, not showing %s" % message) return if (self.flashTextInterval is not None) and self.flashTextInterval.isPlaying(): self.flashTextInterval.finish() self.flashText.setText(message) self.flashText.setAlphaScale(1.0) self.flashText.unstash() def _hideFlashMessage(self, duration=0.0): if self.isDisabled(): assert self.notify.debug( "_hideFlashMessage we're disabled, but still hiding self.flashText" ) # return self.flashTextInterval = Sequence( Wait(duration), LerpFunc(self.flashText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), Func(self.flashText.stash), ) self.flashTextInterval.start() def flashMessage(self, message, duration=0.5): self._showFlashMessage(message) self._hideFlashMessage(duration)
class Myclass(ShowBase): """docstring for Myclass""" def __init__(self): ShowBase.__init__(self) self.playerGUI = gameGUI() self.numObjects = 200; self.again = 0 self.setBackgroundColor(.6, .6, 1) self.evrn = self.loader.loadModel(MYDIR+"/world/world") self.evrn.reparentTo(self.render) self.evrn.setScale(3) self.evrn.setPos(0,0,0) self.evrn.setCollideMask(BitMask32.bit(1)) self.sky = self.loader.loadModel(MYDIR+"/alice-skies--happysky/happysky") self.sky.reparentTo(self.render) self.sky.setScale(3) self.sky.setPos(-10,-50,5) self.house = self.loader.loadModel(MYDIR+"/dojo/dojo") self.house.reparentTo(self.evrn) self.house.setScale(0.032) self.house.setPos(30,30,4) self.house.setHpr(90,0,0) self.house.setCollideMask(BitMask32.bit(1)) self.rect = CollisionSphere(0,0,0,300) self.rectnode = CollisionNode('houserect') self.rectnode.addSolid(self.rect) self.rectnode.setCollideMask(BitMask32.bit(1)) self.houserectad = self.house.attachNewNode(self.rectnode) #self.houserectad.show() self.placeCollectibles() self.loadMenu() self.loadcharacter() def loadcharacter(self): self.ralphstartpos = Point3(-350,-150,9) self.player = Character(MYDIR+"/ralph/ralph",MYDIR+"/ralph/ralph-run",MYDIR+"/ralph/ralph-walk",self.ralphstartpos, 1.2,1,self.playerGUI) ralph = self.player.getactor() self.accept("j", self.player.setControl, ["left",1]) self.accept("l", self.player.setControl, ["right",1]) self.accept("i", self.player.setControl, ["forward",1]) self.accept("j-up", self.player.setControl, ["left",0]) self.accept("l-up", self.player.setControl, ["right",0]) self.accept("i-up", self.player.setControl, ["forward",0]) camera = Camera(self.player.actor) self.accept("a-up", camera.setControl, ["left",0]) self.accept("s-up", camera.setControl, ["right",0]) self.accept("a", camera.setControl, ["left",1]) self.accept("s", camera.setControl, ["right",1]) self.dino = Agent(MYDIR+"/trex/trex",MYDIR+"/trex/trex-run",MYDIR+"/trex/trex-run",(-350,120,3),1.2,2,ralph,self.playerGUI) def placeCollectibles(self): self.placeCol = render.attachNewNode("Collectible-Placeholder") self.placeCol.setPos(0,0,0) # Add the health items to the placeCol node for i in range(self.numObjects): # Load in the health item model self.collect = loader.loadModel(MYDIR+"/ball/jack") self.collect.setPos(0,0,0) self.collect.setH(90) self.collect.setScale(2) self.collect.reparentTo(self.placeCol) self.placeItem(self.collect) # Add spherical collision detection colSphere = CollisionSphere(0,0,0,1) sphereNode = CollisionNode('colSphere') sphereNode.addSolid(colSphere) sphereNode.setFromCollideMask(BitMask32.allOff()) sphereNode.setIntoCollideMask(BitMask32.bit(1)) sphereNp = self.collect.attachNewNode(sphereNode) def placeItem(self, item): # Add ground collision detector to the health item self.cTrav1 = CollisionTraverser() self.collectGroundRay = CollisionRay() self.collectGroundRay.setOrigin(0,0,300) self.collectGroundRay.setDirection(0,0,-1) self.collectGroundCol = CollisionNode('colRay') self.collectGroundCol.addSolid(self.collectGroundRay) self.collectGroundCol.setFromCollideMask(BitMask32.bit(1)) self.collectGroundCol.setIntoCollideMask(BitMask32.allOff()) self.collectGroundColNp = item.attachNewNode(self.collectGroundCol) self.collectGroundHandler = CollisionHandlerQueue() base.cTrav1.addCollider(self.collectGroundColNp, self.collectGroundHandler) placed = False; while placed == False: # re-randomize position item.setPos(-random.randint(-350,300),-random.randint(-100,150),0) base.cTrav1.traverse(render) # Get Z position from terrain collision entries = [] for j in range(self.collectGroundHandler.getNumEntries()): entry = self.collectGroundHandler.getEntry(j) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): item.setZ(entries[0].getSurfacePoint(render).getZ()+4) placed = True # remove placement collider #self.collectGroundColNp.removeNode() def start(self): self.playerGUI.runralph = 1 self.playerGUI.setgamepausevalue(1) taskMgr.add(self.movement, "Movement") self.playerGUI.playend() self.playerGUI.initTimer() #Start music #soundMgr.playBG() def movement(self,task): ''' taskMgr.add(self.finishGame, "Finish Game") Task.again ''' global finishme if self.playerGUI.runralph == 1 and finishme == 0: return Task.again else: self.player.getactor().stop() self.dino.getactor().stop() taskMgr.doMethodLater(2, self.finishGame, "Finish Game") return Task.done def loadMenu(self): #Load main menu #Add play icon click = loader.loadSfx("./sounds/correct.ogg") self.playicon = DirectButton(image="./GUI/cloud.png", scale=.3, pos=(-0.38,0,0.21), relief=None, state=DGG.NORMAL, command=self.playGame, clickSound=click) self.playicon.setScale(0.3) self.playicon.setTransparency(TransparencyAttrib.MAlpha) #Play text play = TextNode('Play') play.setText("\1menu\1 Play! \2") self.playNP = aspect2d.attachNewNode(play) self.playNP.setScale(0.18) self.playNP.setPos(-0.7,0,0.13) self.playerGUI.controls() #Exit text and icon self.exiticon = DirectButton(image="./GUI/cloud.png", scale=.3, pos=(0.48,0,0.21), relief=None, state=DGG.NORMAL, command=exit, clickSound=click) self.exiticon.setScale(0.3) self.exiticon.setTransparency(TransparencyAttrib.MAlpha) exitx = TextNode('Exit') exitx.setText("\1menu\1 Exit \2") self.exitxNP = aspect2d.attachNewNode(exitx) self.exitxNP.setScale(0.18) self.exitxNP.setPos(0.22,0,0.13) def playGame(self): #Unload menu self.playicon.destroy() self.exiticon.destroy() self.playNP.removeNode() self.exitxNP.removeNode() self.playerGUI.controlsleftNP.removeNode() self.playerGUI.controlsrightNP.removeNode() self.playerGUI.controlsforwardNP.removeNode() self.playerGUI.controlscameraaNP.removeNode() self.playerGUI.controlscamerasNP.removeNode() self.playerGUI.instructions1NP.removeNode() if self.again: self.playerGUI.reset() #self.restartgame() self.player.getactor().cleanup() self.player.getactor().removeNode() self.dino.getactor().cleanup() self.dino.getactor().removeNode() self.loadcharacter() #Start game self.countdw = 3 taskMgr.doMethodLater(1, self.countDown, "Count Down") def restartgame(self): self.numObjects = 200; self.player.getactor().setPos(self.ralphstartpos) self.dino.getactor().setPos(-350,120,3) self.time = 0 base.camera.setPos(self.player.getactor().getX()-30,self.player.getactor().getY()-10,self.player.getactor().getZ()+7) camera.setHpr(-60,0,0) #self.placeHealthItems() self.placeCollectibles() #taskMgr.add(self.move,"moveTask") #taskMgr.doMethodLater(0.5, self.healthDec, "healthTask") def finishGame(self, task): global finishme #if finishme == 0 and self.playerGUI.runralph == 1: # Task.cont #check if finish global is 1 toh continue else return task.cont #Check if there's a new record if self.playerGUI.points > self.playerGUI.record: self.playerGUI.setRecord(self.playerGUI.points) #else: #soundMgr.playSnd("./sounds/opening.ogg",1,False) self.again = 1 self.playerGUI.setgamepausevalue(0) #self.player.getactor().stop() #self.dino.getactor().stop() taskMgr.remove("moveTask") taskMgr.remove("AIUpdate") taskMgr.remove("cameraMoveTask") #taskMgr.remove("TicTac") finishme = 0 self.playerGUI.picked = 0 self.loadMenu() def countDown(self, task): #Start countdown if self.countdw >= -1: if self.countdw == 0: self.start() self.playerGUI.setCount(self.countdw) self.countdw -= 1 return Task.again else: return Task.done
class DistributedPartyCatchActivity(DistributedPartyActivity, DistributedPartyCatchActivityBase): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyCatchActivity') DropTaskName = 'dropSomething' DropObjectPlurals = {'apple': TTLocalizer.PartyCatchActivityApples, 'orange': TTLocalizer.PartyCatchActivityOranges, 'pear': TTLocalizer.PartyCatchActivityPears, 'coconut': TTLocalizer.PartyCatchActivityCoconuts, 'watermelon': TTLocalizer.PartyCatchActivityWatermelons, 'pineapple': TTLocalizer.PartyCatchActivityPineapples, 'anvil': TTLocalizer.PartyCatchActivityAnvils} class Generation: def __init__(self, generation, startTime, startNetworkTime, numPlayers): self.generation = generation self.startTime = startTime self.startNetworkTime = startNetworkTime self.numPlayers = numPlayers self.hasBeenScheduled = False self.droppedObjNames = [] self.dropSchedule = [] self.numItemsDropped = 0 self.droppedObjCaught = {} def __init__(self, cr): DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyCatch, PartyGlobals.ActivityTypes.HostInitiated, wantRewardGui=True) self.setUsesSmoothing() self.setUsesLookAround() self._sNumGen = SerialNumGen() def getTitle(self): return TTLocalizer.PartyCatchActivityTitle def getInstructions(self): return TTLocalizer.PartyCatchActivityInstructions % {'badThing': self.DropObjectPlurals['anvil']} def generate(self): DistributedPartyActivity.generate(self) self.notify.info('localAvatar doId: %s' % base.localAvatar.doId) self.notify.info('generate()') self._generateFrame = globalClock.getFrameCount() self._id2gen = {} self._orderedGenerations = [] self._orderedGenerationIndex = None rng = RandomNumGen(self.doId) self._generationSeedBase = rng.randrange(1000) self._lastDropTime = 0.0 return def getCurGeneration(self): if self._orderedGenerationIndex is None: return return self._orderedGenerations[self._orderedGenerationIndex] def _addGeneration(self, generation, startTime, startNetworkTime, numPlayers): self._id2gen[generation] = self.Generation(generation, startTime, startNetworkTime, numPlayers) i = 0 while 1: if i >= len(self._orderedGenerations): break gen = self._orderedGenerations[i] startNetT = self._id2gen[gen].startTime genId = self._id2gen[gen].generation if startNetT > startNetworkTime: break if startNetT == startNetworkTime and genId > generation: break i += 1 self._orderedGenerations = self._orderedGenerations[:i] + [generation] + self._orderedGenerations[i:] if self._orderedGenerationIndex is not None: if self._orderedGenerationIndex >= i: self._orderedGenerationIndex += 1 def _removeGeneration(self, generation): del self._id2gen[generation] i = self._orderedGenerations.index(generation) self._orderedGenerations = self._orderedGenerations[:i] + self._orderedGenerations[i + 1:] if self._orderedGenerationIndex is not None: if len(self._orderedGenerations): if self._orderedGenerationIndex >= i: self._orderedGenerationIndex -= 1 else: self._orderedGenerationIndex = None return def announceGenerate(self): self.notify.info('announceGenerate()') self.catchTreeZoneEvent = 'fence_floor' DistributedPartyActivity.announceGenerate(self) def load(self, loadModels = 1, arenaModel = 'partyCatchTree'): self.notify.info('load()') DistributedPartyCatchActivity.notify.debug('PartyCatch: load') self.activityFSM = CatchActivityFSM(self) if __dev__: for o in xrange(3): print {0: 'SPOTS PER PLAYER', 1: 'DROPS PER MINUTE PER SPOT DURING NORMAL DROP PERIOD', 2: 'DROPS PER MINUTE PER PLAYER DURING NORMAL DROP PERIOD'}[o] for i in xrange(1, self.FallRateCap_Players + 10): self.defineConstants(forceNumPlayers=i) numDropLocations = self.DropRows * self.DropColumns numDropsPerMin = 60.0 / self.DropPeriod if o == 0: spotsPerPlayer = numDropLocations / float(i) print '%2d PLAYERS: %s' % (i, spotsPerPlayer) elif o == 1: numDropsPerMinPerSpot = numDropsPerMin / numDropLocations print '%2d PLAYERS: %s' % (i, numDropsPerMinPerSpot) elif i > 0: numDropsPerMinPerPlayer = numDropsPerMin / i print '%2d PLAYERS: %s' % (i, numDropsPerMinPerPlayer) self.defineConstants() self.treesAndFence = loader.loadModel('phase_13/models/parties/%s' % arenaModel) self.treesAndFence.setScale(0.9) self.treesAndFence.find('**/fence_floor').setPos(0.0, 0.0, 0.1) self.treesAndFence.reparentTo(self.root) ground = self.treesAndFence.find('**/groundPlane') ground.setBin('ground', 1) DistributedPartyActivity.load(self) exitText = TextNode('PartyCatchExitText') exitText.setCardAsMargin(0.1, 0.1, 0.1, 0.1) exitText.setCardDecal(True) exitText.setCardColor(1.0, 1.0, 1.0, 0.0) exitText.setText(TTLocalizer.PartyCatchActivityExit) exitText.setTextColor(0.0, 8.0, 0.0, 0.9) exitText.setAlign(exitText.ACenter) exitText.setFont(ToontownGlobals.getBuildingNametagFont()) exitText.setShadowColor(0, 0, 0, 1) exitText.setBin('fixed') if TTLocalizer.BuildingNametagShadow: exitText.setShadow(*TTLocalizer.BuildingNametagShadow) exitTextLoc = self.treesAndFence.find('**/loc_exitSignText') exitTextNp = exitTextLoc.attachNewNode(exitText) exitTextNp.setDepthWrite(0) exitTextNp.setScale(4) exitTextNp.setZ(-.5) self.sign.reparentTo(self.treesAndFence.find('**/loc_eventSign')) self.sign.wrtReparentTo(self.root) self.avatarNodePath = NodePath('PartyCatchAvatarNodePath') self.avatarNodePath.reparentTo(self.root) self._avatarNodePathParentToken = 3 base.cr.parentMgr.registerParent(self._avatarNodePathParentToken, self.avatarNodePath) self.toonSDs = {} self.dropShadow = loader.loadModelOnce('phase_3/models/props/drop_shadow') self.dropObjModels = {} if loadModels: self.__loadDropModels() self.sndGoodCatch = base.loadSfx('phase_4/audio/sfx/SZ_DD_treasure.ogg') self.sndOof = base.loadSfx('phase_4/audio/sfx/MG_cannon_hit_dirt.ogg') self.sndAnvilLand = base.loadSfx('phase_4/audio/sfx/AA_drop_anvil_miss.ogg') self.sndPerfect = base.loadSfx('phase_4/audio/sfx/ring_perfect.ogg') self.__textGen = TextNode('partyCatchActivity') self.__textGen.setFont(ToontownGlobals.getSignFont()) self.__textGen.setAlign(TextNode.ACenter) self.activityFSM.request('Idle') def __loadDropModels(self): for objType in PartyGlobals.DropObjectTypes: model = loader.loadModel(objType.modelPath) self.dropObjModels[objType.name] = model modelScales = {'apple': 0.7, 'orange': 0.7, 'pear': 0.5, 'coconut': 0.7, 'watermelon': 0.6, 'pineapple': 0.45} if objType.name in modelScales: model.setScale(modelScales[objType.name]) if objType == PartyGlobals.Name2DropObjectType['pear']: model.setZ(-.6) if objType == PartyGlobals.Name2DropObjectType['coconut']: model.setP(180) if objType == PartyGlobals.Name2DropObjectType['watermelon']: model.setH(135) model.setZ(-.5) if objType == PartyGlobals.Name2DropObjectType['pineapple']: model.setZ(-1.7) if objType == PartyGlobals.Name2DropObjectType['anvil']: model.setZ(-self.ObjRadius) model.flattenStrong() def unload(self): DistributedPartyCatchActivity.notify.debug('unload') self.finishAllDropIntervals() self.destroyOrthoWalk() DistributedPartyActivity.unload(self) self.stopDropTask() del self.activityFSM del self.__textGen for avId in self.toonSDs.keys(): if avId in self.toonSDs: toonSD = self.toonSDs[avId] toonSD.unload() del self.toonSDs self.treesAndFence.removeNode() del self.treesAndFence self.dropShadow.removeNode() del self.dropShadow base.cr.parentMgr.unregisterParent(self._avatarNodePathParentToken) for model in self.dropObjModels.values(): model.removeNode() del self.dropObjModels del self.sndGoodCatch del self.sndOof del self.sndAnvilLand del self.sndPerfect def setStartTimestamp(self, timestamp32): self.notify.info('setStartTimestamp(%s)' % (timestamp32,)) self._startTimestamp = globalClockDelta.networkToLocalTime(timestamp32, bits=32) def getCurrentCatchActivityTime(self): return globalClock.getFrameTime() - self._startTimestamp def getObjModel(self, objName): return self.dropObjModels[objName].copyTo(hidden) def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) base.cr.playGame.getPlace().fsm.request('walk') def handleToonJoined(self, toonId): if toonId not in self.toonSDs: toonSD = PartyCatchActivityToonSD(toonId, self) self.toonSDs[toonId] = toonSD toonSD.load() self.notify.debug('handleToonJoined : currentState = %s' % self.activityFSM.state) self.cr.doId2do[toonId].useLOD(500) if self.activityFSM.state == 'Active': if toonId in self.toonSDs: self.toonSDs[toonId].enter() if base.localAvatar.doId == toonId: base.localAvatar.b_setParent(self._avatarNodePathParentToken) self.putLocalAvatarInActivity() if toonId in self.toonSDs: self.toonSDs[toonId].fsm.request('rules') def handleToonExited(self, toonId): self.notify.debug('handleToonExited( toonId=%s )' % toonId) if toonId in self.cr.doId2do: self.cr.doId2do[toonId].resetLOD() if toonId in self.toonSDs: self.toonSDs[toonId].fsm.request('notPlaying') self.toonSDs[toonId].exit() self.toonSDs[toonId].unload() del self.toonSDs[toonId] if base.localAvatar.doId == toonId: base.localAvatar.b_setParent(ToontownGlobals.SPRender) def takeLocalAvatarOutOfActivity(self): self.notify.debug('localToon has left the circle') base.camera.reparentTo(base.localAvatar) base.localAvatar.startUpdateSmartCamera() base.localAvatar.enableSmartCameraViews() base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex) DistributedSmoothNode.activateSmoothing(1, 0) def _enableCollisions(self): DistributedPartyActivity._enableCollisions(self) self._enteredTree = False self.accept('enter' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree) self.accept('again' + self.catchTreeZoneEvent, self._toonMayHaveEnteredTree) self.accept('exit' + self.catchTreeZoneEvent, self._toonExitedTree) self.accept(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT, self._handleCannonLanded) def _disableCollisions(self): self.ignore(DistributedPartyCannonActivity.LOCAL_TOON_LANDED_EVENT) self.ignore('enter' + self.catchTreeZoneEvent) self.ignore('again' + self.catchTreeZoneEvent) self.ignore('exit' + self.catchTreeZoneEvent) DistributedPartyActivity._disableCollisions(self) def _handleCannonLanded(self): x = base.localAvatar.getX() y = base.localAvatar.getY() if x > self.x - self.StageHalfWidth and x < self.x + self.StageHalfWidth and y > self.y - self.StageHalfHeight and y < self.y + self.StageHalfHeight: self._toonEnteredTree(None) return def _toonMayHaveEnteredTree(self, collEntry): if self._enteredTree: return if base.localAvatar.controlManager.currentControls.getIsAirborne(): return self._toonEnteredTree(collEntry) def _toonEnteredTree(self, collEntry): self.notify.debug('_toonEnteredTree : avid = %s' % base.localAvatar.doId) self.notify.debug('_toonEnteredTree : currentState = %s' % self.activityFSM.state) if self.isLocalToonInActivity(): return if self.activityFSM.state == 'Active': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() elif self.activityFSM.state == 'Idle': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() self._enteredTree = True def _toonExitedTree(self, collEntry): self.notify.debug('_toonExitedTree : avid = %s' % base.localAvatar.doId) self._enteredTree = False if hasattr(base.cr.playGame.getPlace(), 'fsm') and self.activityFSM.state == 'Active' and self.isLocalToonInActivity(): if base.localAvatar.doId in self.toonSDs: self.takeLocalAvatarOutOfActivity() self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying') self.d_toonExitDemand() def setToonsPlaying(self, toonIds): self.notify.info('setToonsPlaying(%s)' % (toonIds,)) DistributedPartyActivity.setToonsPlaying(self, toonIds) if self.isLocalToonInActivity() and base.localAvatar.doId not in toonIds: if base.localAvatar.doId in self.toonSDs: self.takeLocalAvatarOutOfActivity() self.toonSDs[base.localAvatar.doId].fsm.request('notPlaying') def __genText(self, text): self.__textGen.setText(text) return self.__textGen.generate() def getNumPlayers(self): return len(self.toonIds) def defineConstants(self, forceNumPlayers = None): DistributedPartyCatchActivity.notify.debug('defineConstants') self.ShowObjSpheres = 0 self.ShowToonSpheres = 0 self.useGravity = True self.trickShadows = True if forceNumPlayers is None: numPlayers = self.getNumPlayers() else: numPlayers = forceNumPlayers self.calcDifficultyConstants(numPlayers) DistributedPartyCatchActivity.notify.debug('ToonSpeed: %s' % self.ToonSpeed) DistributedPartyCatchActivity.notify.debug('total drops: %s' % self.totalDrops) DistributedPartyCatchActivity.notify.debug('numFruits: %s' % self.numFruits) DistributedPartyCatchActivity.notify.debug('numAnvils: %s' % self.numAnvils) self.ObjRadius = 1.0 dropRegionTable = PartyRegionDropPlacer.getDropRegionTable(numPlayers) self.DropRows, self.DropColumns = len(dropRegionTable), len(dropRegionTable[0]) for objType in PartyGlobals.DropObjectTypes: DistributedPartyCatchActivity.notify.debug('*** Object Type: %s' % objType.name) objType.onscreenDuration = objType.onscreenDurMult * self.BaselineOnscreenDropDuration DistributedPartyCatchActivity.notify.debug('onscreenDuration=%s' % objType.onscreenDuration) v_0 = 0.0 t = objType.onscreenDuration x_0 = self.MinOffscreenHeight x = 0.0 g = 2.0 * (x - x_0 - v_0 * t) / (t * t) DistributedPartyCatchActivity.notify.debug('gravity=%s' % g) objType.trajectory = Trajectory(0, Vec3(0, 0, x_0), Vec3(0, 0, v_0), gravMult=abs(g / Trajectory.gravity)) objType.fallDuration = objType.onscreenDuration + self.OffscreenTime return def grid2world(self, column, row): x = column / float(self.DropColumns - 1) y = row / float(self.DropRows - 1) x = x * 2.0 - 1.0 y = y * 2.0 - 1.0 x *= self.StageHalfWidth y *= self.StageHalfHeight return (x, y) def showPosts(self): self.hidePosts() self.posts = [Toon.Toon(), Toon.Toon(), Toon.Toon(), Toon.Toon()] for i in xrange(len(self.posts)): tree = self.posts[i] tree.reparentTo(render) x = self.StageHalfWidth y = self.StageHalfHeight if i > 1: x = -x if i % 2: y = -y tree.setPos(x + self.x, y + self.y, 0) def hidePosts(self): if hasattr(self, 'posts'): for tree in self.posts: tree.removeNode() del self.posts def showDropGrid(self): self.hideDropGrid() self.dropMarkers = [] for row in xrange(self.DropRows): self.dropMarkers.append([]) rowList = self.dropMarkers[row] for column in xrange(self.DropColumns): toon = Toon.Toon() toon.setDNA(base.localAvatar.getStyle()) toon.reparentTo(self.root) toon.setScale(1.0 / 3) x, y = self.grid2world(column, row) toon.setPos(x, y, 0) rowList.append(toon) def hideDropGrid(self): if hasattr(self, 'dropMarkers'): for row in self.dropMarkers: for marker in row: marker.removeNode() del self.dropMarkers def handleToonDisabled(self, avId): DistributedPartyCatchActivity.notify.debug('handleToonDisabled') DistributedPartyCatchActivity.notify.debug('avatar ' + str(avId) + ' disabled') if avId in self.toonSDs: self.toonSDs[avId].exit(unexpectedExit=True) del self.toonSDs[avId] def turnOffSmoothingOnGuests(self): pass def setState(self, newState, timestamp): self.notify.info('setState(%s, %s)' % (newState, timestamp)) DistributedPartyCatchActivity.notify.debug('setState( newState=%s, ... )' % newState) DistributedPartyActivity.setState(self, newState, timestamp) self.activityFSM.request(newState) if newState == 'Active': if base.localAvatar.doId != self.party.partyInfo.hostId: if globalClock.getFrameCount() > self._generateFrame: if base.localAvatar.getX() > self.x - self.StageHalfWidth and base.localAvatar.getX() < self.x + self.StageHalfWidth and base.localAvatar.getY() > self.y - self.StageHalfHeight and base.localAvatar.getY() < self.y + self.StageHalfHeight: self._toonEnteredTree(None) return def putLocalAvatarInActivity(self): if base.cr.playGame.getPlace() and hasattr(base.cr.playGame.getPlace(), 'fsm'): base.cr.playGame.getPlace().fsm.request('activity', [False]) else: self.notify.info("Avoided crash: toontown.parties.DistributedPartyCatchActivity:632, toontown.parties.DistributedPartyCatchActivity:1198, toontown.parties.activityFSMMixins:49, direct.fsm.FSM:423, AttributeError: 'NoneType' object has no attribute 'fsm'") base.localAvatar.stopUpdateSmartCamera() base.camera.reparentTo(self.treesAndFence) base.camera.setPosHpr(0.0, -63.0, 30.0, 0.0, -20.0, 0.0) if not hasattr(self, 'ltLegsCollNode'): self.createCatchCollisions() def createCatchCollisions(self): radius = 0.7 handler = CollisionHandlerEvent() handler.setInPattern('ltCatch%in') self.ltLegsCollNode = CollisionNode('catchLegsCollNode') self.ltLegsCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltHeadCollNode = CollisionNode('catchHeadCollNode') self.ltHeadCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltLHandCollNode = CollisionNode('catchLHandCollNode') self.ltLHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) self.ltRHandCollNode = CollisionNode('catchRHandCollNode') self.ltRHandCollNode.setCollideMask(PartyGlobals.CatchActivityBitmask) legsCollNodepath = base.localAvatar.attachNewNode(self.ltLegsCollNode) legsCollNodepath.hide() head = base.localAvatar.getHeadParts().getPath(2) headCollNodepath = head.attachNewNode(self.ltHeadCollNode) headCollNodepath.hide() lHand = base.localAvatar.getLeftHands()[0] lHandCollNodepath = lHand.attachNewNode(self.ltLHandCollNode) lHandCollNodepath.hide() rHand = base.localAvatar.getRightHands()[0] rHandCollNodepath = rHand.attachNewNode(self.ltRHandCollNode) rHandCollNodepath.hide() base.localAvatar.cTrav.addCollider(legsCollNodepath, handler) base.localAvatar.cTrav.addCollider(headCollNodepath, handler) base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler) base.localAvatar.cTrav.addCollider(lHandCollNodepath, handler) if self.ShowToonSpheres: legsCollNodepath.show() headCollNodepath.show() lHandCollNodepath.show() rHandCollNodepath.show() self.ltLegsCollNode.addSolid(CollisionSphere(0, 0, radius, radius)) self.ltHeadCollNode.addSolid(CollisionSphere(0, 0, 0, radius)) self.ltLHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0)) self.ltRHandCollNode.addSolid(CollisionSphere(0, 0, 0, 2 * radius / 3.0)) self.toonCollNodes = [legsCollNodepath, headCollNodepath, lHandCollNodepath, rHandCollNodepath] def destroyCatchCollisions(self): if not hasattr(self, 'ltLegsCollNode'): return for collNode in self.toonCollNodes: while collNode.node().getNumSolids(): collNode.node().removeSolid(0) base.localAvatar.cTrav.removeCollider(collNode) del self.toonCollNodes del self.ltLegsCollNode del self.ltHeadCollNode del self.ltLHandCollNode del self.ltRHandCollNode def timerExpired(self): pass def __handleCatch(self, generation, objNum): DistributedPartyCatchActivity.notify.debug('catch: %s' % [generation, objNum]) if base.localAvatar.doId not in self.toonIds: return self.showCatch(base.localAvatar.doId, generation, objNum) objName = self._id2gen[generation].droppedObjNames[objNum] objTypeId = PartyGlobals.Name2DOTypeId[objName] self.sendUpdate('claimCatch', [generation, objNum, objTypeId]) self.finishDropInterval(generation, objNum) def showCatch(self, avId, generation, objNum): if avId not in self.toonSDs: return isLocal = avId == base.localAvatar.doId if generation not in self._id2gen: return if not self._id2gen[generation].hasBeenScheduled: return objName = self._id2gen[generation].droppedObjNames[objNum] objType = PartyGlobals.Name2DropObjectType[objName] if objType.good: if objNum not in self._id2gen[generation].droppedObjCaught: if isLocal: base.playSfx(self.sndGoodCatch) fruit = self.getObjModel(objName) toon = self.getAvatar(avId) rHand = toon.getRightHands()[1] self.toonSDs[avId].eatFruit(fruit, rHand) else: self.toonSDs[avId].fsm.request('fallForward') self._id2gen[generation].droppedObjCaught[objNum] = 1 def setObjectCaught(self, avId, generation, objNum): self.notify.info('setObjectCaught(%s, %s, %s)' % (avId, generation, objNum)) if self.activityFSM.state != 'Active': DistributedPartyCatchActivity.notify.warning('ignoring msg: object %s caught by %s' % (objNum, avId)) return isLocal = avId == base.localAvatar.doId if not isLocal: DistributedPartyCatchActivity.notify.debug('AI: avatar %s caught %s' % (avId, objNum)) self.finishDropInterval(generation, objNum) self.showCatch(avId, generation, objNum) self._scheduleGenerations() gen = self._id2gen[generation] if gen.hasBeenScheduled: objName = gen.droppedObjNames[objNum] if PartyGlobals.Name2DropObjectType[objName].good: if hasattr(self, 'fruitsCaught'): self.fruitsCaught += 1 def finishDropInterval(self, generation, objNum): if hasattr(self, 'dropIntervals'): if (generation, objNum) in self.dropIntervals: self.dropIntervals[generation, objNum].finish() def finishAllDropIntervals(self): if hasattr(self, 'dropIntervals'): for dropInterval in self.dropIntervals.values(): dropInterval.finish() def setGenerations(self, generations): self.notify.info('setGenerations(%s)' % (generations,)) gen2t = {} gen2nt = {} gen2np = {} for id, timestamp32, numPlayers in generations: gen2t[id] = globalClockDelta.networkToLocalTime(timestamp32, bits=32) - self._startTimestamp gen2nt[id] = timestamp32 gen2np[id] = numPlayers ids = self._id2gen.keys() for id in ids: if id not in gen2t: self._removeGeneration(id) for id in gen2t: if id not in self._id2gen: self._addGeneration(id, gen2t[id], gen2nt[id], gen2np[id]) def scheduleDrops(self, genId = None): if genId is None: genId = self.getCurGeneration() gen = self._id2gen[genId] if gen.hasBeenScheduled: return fruitIndex = int((gen.startTime + 0.5 * self.DropPeriod) / PartyGlobals.CatchActivityDuration) fruitNames = ['apple', 'orange', 'pear', 'coconut', 'watermelon', 'pineapple'] fruitName = fruitNames[fruitIndex % len(fruitNames)] rng = RandomNumGen(genId + self._generationSeedBase) gen.droppedObjNames = [fruitName] * self.numFruits + ['anvil'] * self.numAnvils rng.shuffle(gen.droppedObjNames) dropPlacer = PartyRegionDropPlacer(self, gen.numPlayers, genId, gen.droppedObjNames, startTime=gen.startTime) gen.numItemsDropped = 0 tIndex = gen.startTime % PartyGlobals.CatchActivityDuration tPercent = float(tIndex) / PartyGlobals.CatchActivityDuration gen.numItemsDropped += dropPlacer.skipPercent(tPercent) while not dropPlacer.doneDropping(continuous=True): nextDrop = dropPlacer.getNextDrop() gen.dropSchedule.append(nextDrop) gen.hasBeenScheduled = True return def startDropTask(self): taskMgr.add(self.dropTask, self.DropTaskName) def stopDropTask(self): taskMgr.remove(self.DropTaskName) def _scheduleGenerations(self): curT = self.getCurrentCatchActivityTime() genIndex = self._orderedGenerationIndex newGenIndex = genIndex while genIndex is None or genIndex < len(self._orderedGenerations) - 1: if genIndex is None: nextGenIndex = 0 else: nextGenIndex = genIndex + 1 nextGenId = self._orderedGenerations[nextGenIndex] nextGen = self._id2gen[nextGenId] startT = nextGen.startTime if curT >= startT: newGenIndex = nextGenIndex if not nextGen.hasBeenScheduled: self.defineConstants(forceNumPlayers=nextGen.numPlayers) self.scheduleDrops(genId=self._orderedGenerations[nextGenIndex]) genIndex = nextGenIndex self._orderedGenerationIndex = newGenIndex return def dropTask(self, task): self._scheduleGenerations() curT = self.getCurrentCatchActivityTime() if self._orderedGenerationIndex is not None: i = self._orderedGenerationIndex genIndex = self._orderedGenerations[i] gen = self._id2gen[genIndex] while len(gen.dropSchedule) > 0 and gen.dropSchedule[0][0] < curT: drop = gen.dropSchedule[0] gen.dropSchedule = gen.dropSchedule[1:] dropTime, objName, dropCoords = drop objNum = gen.numItemsDropped x, y = self.grid2world(*dropCoords) dropIval = self.getDropIval(x, y, objName, genIndex, objNum) def cleanup(generation, objNum, self = self): del self.dropIntervals[generation, objNum] dropIval.append(Func(Functor(cleanup, genIndex, objNum))) self.dropIntervals[genIndex, objNum] = dropIval gen.numItemsDropped += 1 dropIval.start(curT - dropTime) self._lastDropTime = dropTime return Task.cont def getDropIval(self, x, y, dropObjName, generation, num): objType = PartyGlobals.Name2DropObjectType[dropObjName] id = (generation, num) dropNode = hidden.attachNewNode('catchDropNode%s' % (id,)) dropNode.setPos(x, y, 0) shadow = self.dropShadow.copyTo(dropNode) shadow.setZ(PartyGlobals.CatchDropShadowHeight) shadow.setColor(1, 1, 1, 1) object = self.getObjModel(dropObjName) object.reparentTo(hidden) if dropObjName in ['watermelon', 'anvil']: objH = object.getH() absDelta = {'watermelon': 12, 'anvil': 15}[dropObjName] delta = (self.randomNumGen.random() * 2.0 - 1.0) * absDelta newH = objH + delta else: newH = self.randomNumGen.random() * 360.0 object.setH(newH) sphereName = 'FallObj%s' % (id,) radius = self.ObjRadius if objType.good: radius *= lerp(1.0, 1.3, 0.5) collSphere = CollisionSphere(0, 0, 0, radius) collSphere.setTangible(0) collNode = CollisionNode(sphereName) collNode.setCollideMask(PartyGlobals.CatchActivityBitmask) collNode.addSolid(collSphere) collNodePath = object.attachNewNode(collNode) collNodePath.hide() if self.ShowObjSpheres: collNodePath.show() catchEventName = 'ltCatch' + sphereName def eatCollEntry(forward, collEntry): forward() self.accept(catchEventName, Functor(eatCollEntry, Functor(self.__handleCatch, id[0], id[1]))) def cleanup(self = self, dropNode = dropNode, id = id, event = catchEventName): self.ignore(event) dropNode.removeNode() duration = objType.fallDuration onscreenDuration = objType.onscreenDuration targetShadowScale = 0.3 if self.trickShadows: intermedScale = targetShadowScale * (self.OffscreenTime / self.BaselineDropDuration) shadowScaleIval = Sequence(LerpScaleInterval(shadow, self.OffscreenTime, intermedScale, startScale=0)) shadowScaleIval.append(LerpScaleInterval(shadow, duration - self.OffscreenTime, targetShadowScale, startScale=intermedScale)) else: shadowScaleIval = LerpScaleInterval(shadow, duration, targetShadowScale, startScale=0) targetShadowAlpha = 0.4 shadowAlphaIval = LerpColorScaleInterval(shadow, self.OffscreenTime, Point4(1, 1, 1, targetShadowAlpha), startColorScale=Point4(1, 1, 1, 0)) shadowIval = Parallel(shadowScaleIval, shadowAlphaIval) if self.useGravity: def setObjPos(t, objType = objType, object = object): z = objType.trajectory.calcZ(t) object.setZ(z) setObjPos(0) dropIval = LerpFunctionInterval(setObjPos, fromData=0, toData=onscreenDuration, duration=onscreenDuration) else: startPos = Point3(0, 0, self.MinOffscreenHeight) object.setPos(startPos) dropIval = LerpPosInterval(object, onscreenDuration, Point3(0, 0, 0), startPos=startPos, blendType='easeIn') ival = Sequence(Func(Functor(dropNode.reparentTo, self.root)), Parallel(Sequence(WaitInterval(self.OffscreenTime), Func(Functor(object.reparentTo, dropNode)), dropIval), shadowIval), Func(cleanup), name='drop%s' % (id,)) if objType == PartyGlobals.Name2DropObjectType['anvil']: ival.append(Func(self.playAnvil)) return ival def playAnvil(self): if base.localAvatar.doId in self.toonIds: base.playSfx(self.sndAnvilLand) def initOrthoWalk(self): DistributedPartyCatchActivity.notify.debug('startOrthoWalk') def doCollisions(oldPos, newPos, self = self): x = bound(newPos[0], self.StageHalfWidth, -self.StageHalfWidth) y = bound(newPos[1], self.StageHalfHeight, -self.StageHalfHeight) newPos.setX(x) newPos.setY(y) return newPos orthoDrive = OrthoDrive(self.ToonSpeed, instantTurn=True) self.orthoWalk = OrthoWalk(orthoDrive, broadcast=True) def destroyOrthoWalk(self): DistributedPartyCatchActivity.notify.debug('destroyOrthoWalk') if hasattr(self, 'orthoWalk'): self.orthoWalk.stop() self.orthoWalk.destroy() del self.orthoWalk def startIdle(self): DistributedPartyCatchActivity.notify.debug('startIdle') def finishIdle(self): DistributedPartyCatchActivity.notify.debug('finishIdle') def startActive(self): DistributedPartyCatchActivity.notify.debug('startActive') for avId in self.toonIds: if avId in self.toonSDs: toonSD = self.toonSDs[avId] toonSD.enter() toonSD.fsm.request('normal') self.fruitsCaught = 0 self.dropIntervals = {} self.startDropTask() if base.localAvatar.doId in self.toonIds: self.putLocalAvatarInActivity() def finishActive(self): DistributedPartyCatchActivity.notify.debug('finishActive') self.stopDropTask() if hasattr(self, 'finishIval'): self.finishIval.pause() del self.finishIval if base.localAvatar.doId in self.toonIds: self.takeLocalAvatarOutOfActivity() for ival in self.dropIntervals.values(): ival.finish() del self.dropIntervals def startConclusion(self): DistributedPartyCatchActivity.notify.debug('startConclusion') for avId in self.toonIds: if avId in self.toonSDs: toonSD = self.toonSDs[avId] toonSD.fsm.request('notPlaying') self.destroyCatchCollisions() if base.localAvatar.doId not in self.toonIds: return else: self.localToonExiting() if self.fruitsCaught >= self.numFruits: finishText = TTLocalizer.PartyCatchActivityFinishPerfect else: finishText = TTLocalizer.PartyCatchActivityFinish perfectTextSubnode = hidden.attachNewNode(self.__genText(finishText)) perfectText = hidden.attachNewNode('perfectText') perfectTextSubnode.reparentTo(perfectText) frame = self.__textGen.getCardActual() offsetY = -abs(frame[2] + frame[3]) / 2.0 perfectTextSubnode.setPos(0, 0, offsetY) perfectText.setColor(1, 0.1, 0.1, 1) def fadeFunc(t, text = perfectText): text.setColorScale(1, 1, 1, t) def destroyText(text = perfectText): text.removeNode() textTrack = Sequence(Func(perfectText.reparentTo, aspect2d), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=0.3, startScale=0.0), LerpFunctionInterval(fadeFunc, fromData=0.0, toData=1.0, duration=0.5)), Wait(2.0), Parallel(LerpScaleInterval(perfectText, duration=0.5, scale=1.0), LerpFunctionInterval(fadeFunc, fromData=1.0, toData=0.0, duration=0.5, blendType='easeIn')), Func(destroyText), WaitInterval(0.5)) soundTrack = SoundInterval(self.sndPerfect) self.finishIval = Parallel(textTrack, soundTrack) self.finishIval.start() def finishConclusion(self): DistributedPartyCatchActivity.notify.debug('finishConclusion') if base.localAvatar.doId in self.toonIds: self.takeLocalAvatarOutOfActivity() base.cr.playGame.getPlace().fsm.request('walk') def showJellybeanReward(self, earnedAmount, jarAmount, message): if earnedAmount > 0: DistributedPartyActivity.showJellybeanReward(self, earnedAmount, jarAmount, message) else: base.cr.playGame.getPlace().fsm.request('walk')
class DistributedPartyTrampolineActivity(DistributedPartyActivity): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyTrampolineActivity') def __init__(self, cr, doJellyBeans = True, doTricks = False, texture = None): DistributedPartyTrampolineActivity.notify.debug('__init__') DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityTypes.GuestInitiated, wantLever=False, wantRewardGui=True) self.doJellyBeans = doJellyBeans self.doTricks = doTricks self.texture = texture self.toon = None self.trampHeight = 3.6 self.trampK = 400.0 self.normalTrampB = 2.5 self.leavingTrampB = 8.0 self.trampB = self.normalTrampB self.g = -32.0 self.jumpBoost = 330.0 self.beginningBoost = 500.0 self.beginningBoostThreshold = self.trampHeight + 1.5 self.earlyJumpThreshold = 75.0 self.boingThreshold = 300.0 self.turnFactor = 120.0 self.stepDT = 0.001 self.targetCameraPos = Point3(0.0, 40.0, 10.0) self.cameraSpeed = 2.0 self.hopOffPos = Point3(16.0, 0.0, 0.0) self.indicatorFactor = 0.0095 self.dropShadowCutoff = 15.0 self.minHeightForText = 15.0 self.heightTextOffset = -0.065 self.beanOffset = 0.5 self.guiBeanOffset = -0.02 self.jumpTextShown = False self.toonJumped = False self.turnLeft = False self.turnRight = False self.leavingTrampoline = False self.toonVelocity = 0.0 self.topHeight = 0.0 self.lastPeak = 0.0 self.beginRoundInterval = None self.hopOnAnim = None self.hopOffAnim = None self.flashTextInterval = None self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus self.jellyBeanStartHeight = 20.0 self.jellyBeanStopHeight = 90.0 self.jellyBeanColors = [VBase4(1.0, 0.5, 0.5, 1.0), VBase4(0.5, 1.0, 0.5, 1.0), VBase4(0.5, 1.0, 1.0, 1.0), VBase4(1.0, 1.0, 0.4, 1.0), VBase4(0.4, 0.4, 1.0, 1.0), VBase4(1.0, 0.5, 1.0, 1.0)] delta = (self.jellyBeanStopHeight - self.jellyBeanStartHeight) / (self.numJellyBeans - 1) self.jellyBeanPositions = [ self.jellyBeanStartHeight + n * delta for n in xrange(self.numJellyBeans) ] self.doSimulateStep = False return def load(self): DistributedPartyTrampolineActivity.notify.debug('load') DistributedPartyActivity.load(self) self.loadModels() self.loadCollision() self.loadGUI() self.loadSounds() self.loadIntervals() self.activityFSM = TrampolineActivityFSM(self) self.activityFSM.request('Idle') self.animFSM = TrampolineAnimFSM(self) self.setBestHeightInfo('', 0) def loadModels(self): self.tramp = self.root.attachNewNode(self.uniqueName('tramp')) self.trampActor = Actor('phase_13/models/parties/trampoline_model', {'emptyAnim': 'phase_13/models/parties/trampoline_anim'}) self.trampActor.reparentTo(self.tramp) if self.texture: reskinNode = self.tramp.find('**/trampoline/__Actor_modelRoot/-GeomNode') reskinNode.setTexture(loader.loadTexture(self.texture), 100) self.surface = NodePath(self.uniqueName('trampSurface')) self.surface.reparentTo(self.tramp) self.surface.setZ(self.trampHeight) self.trampActor.controlJoint(self.surface, 'modelRoot', 'trampoline_joint1') self.sign.setPos(PartyGlobals.TrampolineSignOffset) self.beans = [ loader.loadModelCopy('phase_4/models/props/jellybean4') for i in xrange(self.numJellyBeans) ] for bean in self.beans: bean.find('**/jellybean').setP(-35.0) bean.setScale(3.0) bean.setTransparency(True) bean.reparentTo(self.tramp) bean.stash() self.beans[-1].setScale(8.0) def loadCollision(self): collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4) collTube.setTangible(True) self.trampolineCollision = CollisionNode(self.uniqueName('TrampolineCollision')) self.trampolineCollision.addSolid(collTube) self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask | OTPGlobals.WallBitmask) self.trampolineCollisionNP = self.tramp.attachNewNode(self.trampolineCollision) collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0) collSphere.setTangible(False) self.trampolineTrigger = CollisionNode(self.uniqueName('TrampolineTrigger')) self.trampolineTrigger.addSolid(collSphere) self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask) self.trampolineTriggerNP = self.tramp.attachNewNode(self.trampolineTrigger) self.accept('enter%s' % self.uniqueName('TrampolineTrigger'), self.onTrampolineTrigger) def loadGUI(self): self.gui = loader.loadModel('phase_13/models/parties/trampolineGUI') self.gui.reparentTo(base.a2dTopLeft) self.gui.setPos(0.115, 0, -1) self.gui.hide() self.toonIndicator = self.gui.find('**/trampolineGUI_MovingBar') jumpLineLocator = self.gui.find('**/jumpLine_locator') guiBean = self.gui.find('**/trampolineGUI_GreenJellyBean') self.gui.find('**/trampolineGUI_GreenJellyBean').stash() self.guiBeans = [ guiBean.instanceUnderNode(jumpLineLocator, self.uniqueName('guiBean%d' % i)) for i in xrange(self.numJellyBeans) ] self.guiBeans[-1].setScale(1.5) heightTextNode = TextNode(self.uniqueName('TrampolineActivity.heightTextNode')) heightTextNode.setFont(ToontownGlobals.getSignFont()) heightTextNode.setAlign(TextNode.ALeft) heightTextNode.setText('0.0') heightTextNode.setShadow(0.05, 0.05) heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0) heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0) self.heightText = jumpLineLocator.attachNewNode(heightTextNode) self.heightText.setX(0.15) self.heightText.setScale(0.1) self.heightText.setAlphaScale(0.0) self.quitEarlyButtonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui') quitEarlyUp = self.quitEarlyButtonModels.find('**//InventoryButtonUp') quitEarlyDown = self.quitEarlyButtonModels.find('**/InventoryButtonDown') quitEarlyRollover = self.quitEarlyButtonModels.find('**/InventoryButtonRollover') self.quitEarlyButton = DirectButton(parent=base.a2dTopRight, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-0.183, 0, -0.4), scale=0.09, command=self.leaveTrampoline) self.quitEarlyButton.stash() self.flashText = OnscreenText(text='', pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True) self.timer = PartyUtils.getNewToontownTimer() self.timer.posInTopRightCorner() return def loadSounds(self): self.jellyBeanSound = base.loader.loadSfx('phase_4/audio/sfx/sparkly.ogg') self.boingSound = base.loader.loadSfx('phase_4/audio/sfx/target_trampoline_2.ogg') self.whistleSound = base.loader.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg') def loadIntervals(self): def prepareHeightText(): self.heightText.node().setText(TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ())) self.heightText.setZ(self.indicatorFactor * self.toon.getZ() + self.heightTextOffset) self.heightTextInterval = Sequence(Func(prepareHeightText), LerpFunc(self.heightText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0)) def unload(self): DistributedPartyTrampolineActivity.notify.debug('unload') if self.hopOnAnim and self.hopOnAnim.isPlaying(): self.hopOnAnim.finish() if self.hopOffAnim and self.hopOffAnim.isPlaying(): self.hopOffAnim.finish() if self.beginRoundInterval and self.beginRoundInterval.isPlaying(): self.beginRoundInterval.finish() if self.flashTextInterval and self.flashTextInterval.isPlaying(): self.flashTextInterval.finish() if self.heightTextInterval and self.heightTextInterval.isPlaying(): self.heightTextInterval.finish() self.timer.stop() DistributedPartyActivity.unload(self) taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask')) taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask')) self.ignoreAll() del self.heightTextInterval del self.beginRoundInterval del self.hopOnAnim del self.hopOffAnim del self.flashTextInterval if hasattr(self, 'beanAnims'): self.cleanupJellyBeans() self.quitEarlyButton.destroy() del self.quitEarlyButton del self.gui del self.activityFSM del self.animFSM return def setBestHeightInfo(self, toonName, height): self.bestHeightInfo = (toonName, height) DistributedPartyTrampolineActivity.notify.debug('%s has the best height of %d' % (toonName, height)) if height > 0: self.setSignNote(TTLocalizer.PartyTrampolineBestHeight % self.bestHeightInfo) else: self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet) def leaveTrampoline(self): if self.toon != None and self.toon.doId == base.localAvatar.doId: self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp) self.leavingTrampoline = True self.timer.reset() self.trampB = self.leavingTrampB self.ignore('control') self.quitEarlyButton.stash() self.gui.hide() return def requestAnim(self, request): self.animFSM.request(request) def b_requestAnim(self, request): self.requestAnim(request) self.sendUpdate('requestAnim', [request]) def requestAnimEcho(self, request): if self.toon != None and self.toon.doId != base.localAvatar.doId: self.requestAnim(request) return def removeBeans(self, beansToRemove): for i in beansToRemove: height, bean, guiBean, beanAnim = self.beanDetails[i] guiBean.stash() if i in self.beansToCollect: self.beansToCollect.remove(i) else: self.notify.warning('removeBeans avoided a crash, %d not in self.beansToCollect' % i) self.poofBean(bean, beanAnim) def b_removeBeans(self, beansToRemove): self.removeBeans(beansToRemove) self.sendUpdate('removeBeans', [beansToRemove]) def removeBeansEcho(self, beansToRemove): if self.toon != None and self.toon.doId != base.localAvatar.doId: self.removeBeans(beansToRemove) return def joinRequestDenied(self, reason): DistributedPartyActivity.joinRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny) base.cr.playGame.getPlace().fsm.request('walk') def exitRequestDenied(self, reason): DistributedPartyActivity.exitRequestDenied(self, reason) self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny) def setState(self, newState, timestamp): DistributedPartyTrampolineActivity.notify.debug('setState( newState=%s, ... )' % newState) DistributedPartyActivity.setState(self, newState, timestamp) self.activityFSM.request(newState) def startIdle(self): DistributedPartyTrampolineActivity.notify.debug('startIdle') def finishIdle(self): DistributedPartyTrampolineActivity.notify.debug('finishIdle') def startRules(self): DistributedPartyTrampolineActivity.notify.debug('startRules') if self.doJellyBeans: self.setupJellyBeans() if self.toon != None and self.toon.doId == base.localAvatar.doId: self.acquireToon() return def startActive(self): DistributedPartyTrampolineActivity.notify.debug('startActive') if self.toon != None and self.toon.doId == base.localAvatar.doId: base.setCellsActive(base.bottomCells, True) self.accept('arrow_left', self.onLeft) self.accept('arrow_left-up', self.onLeftUp) self.accept('arrow_right', self.onRight) self.accept('arrow_right-up', self.onRightUp) self.beginRoundInterval = Sequence(Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady), Wait(1.2), Func(self.flashMessage, TTLocalizer.PartyTrampolineGo), Func(self.beginRound)) self.beginRoundInterval.start() return def finishActive(self): DistributedPartyTrampolineActivity.notify.debug('finishActive') if self.doJellyBeans: self.cleanupJellyBeans() def setupJellyBeans(self): self.beanAnims = [] self.beansToCollect = [] self.beanDetails = [] self.numBeansCollected = 0 for i in xrange(self.numJellyBeans): bean = self.beans[i] guiBean = self.guiBeans[i] height = self.jellyBeanPositions[i] color = random.choice(self.jellyBeanColors) bean.find('**/jellybean').setColor(color) if self.toon.doId == base.localAvatar.doId: bean.setAlphaScale(1.0) else: bean.setAlphaScale(0.5) guiBean.setColor(color) bean.setZ(height + self.toon.getHeight() + self.beanOffset) guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset) bean.setH(0.0) bean.unstash() guiBean.unstash() beanAnim = bean.hprInterval(1.5, VBase3((i % 2 * 2 - 1) * 360.0, 0.0, 0.0)) beanAnim.loop() self.beanAnims.append(beanAnim) self.beanDetails.append((height, bean, guiBean, beanAnim)) self.beansToCollect = range(self.numJellyBeans) def cleanupJellyBeans(self): for bean in self.beans: bean.stash() for guiBean in self.guiBeans: guiBean.stash() if hasattr(self, 'beanAnims'): for beanAnim in self.beanAnims: beanAnim.finish() del self.beanAnims del self.beansToCollect def beginRound(self): base.playSfx(self.whistleSound) self.timer.setTime(PartyGlobals.TrampolineDuration) self.timer.countdown(PartyGlobals.TrampolineDuration) self.timer.show() self.gui.show() self.quitEarlyButton.unstash() self.notify.debug('Accepting contorl') self.accept('control', self.onJump) self.notify.debug('setting simulate step to true') self.doSimulateStep = True def acquireToon(self): self.toon.disableSmartCameraViews() self.toon.stopUpdateSmartCamera() camera.wrtReparentTo(render) self.toon.dropShadow.reparentTo(hidden) self.toon.startPosHprBroadcast(period=0.2) self.toonAcceleration = 0.0 self.toonVelocity = 0.0 self.topHeight = 0.0 self.trampB = self.normalTrampB self.leavingTrampoline = False self.hopOnAnim = Sequence(Func(self.toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, Point3(0.0, 0.0, self.trampHeight), 5.0, self.tramp), Func(self.postHopOn)) self.hopOnAnim.start() def postHopOn(self): self.toon.setH(self.toon.getH() + 90.0) self.toon.dropShadow.reparentTo(self.surface) self.timeLeftToSimulate = 0.0 self.doSimulateStep = False taskMgr.add(self.updateTask, self.uniqueName('TrampolineActivity.updateTask')) base.setCellsActive(base.leftCells, False) base.setCellsActive(base.bottomCells, False) DistributedPartyActivity.startRules(self) def releaseToon(self): self._hideFlashMessage() self.ignore('arrow_left') self.ignore('arrow_left-up') self.ignore('arrow_right') self.ignore('arrow_right-up') taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask')) self.hopOffAnim = Sequence(self.toon.hprInterval(0.5, VBase3(-90.0, 0.0, 0.0), other=self.tramp), Func(self.toon.b_setAnimState, 'jump', 1.0), Func(self.toon.dropShadow.reparentTo, hidden), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0, self.tramp), Func(self.postHopOff)) self.hopOffAnim.start() def postHopOff(self): base.setCellsActive(base.leftCells, True) self.timer.stop() self.timer.hide() self.toon.dropShadow.reparentTo(self.toon.getShadowJoint()) self.toon.dropShadow.setAlphaScale(1.0) self.toon.dropShadow.setScale(1.0) self.b_requestAnim('Off') camera.reparentTo(base.localAvatar) base.localAvatar.startUpdateSmartCamera() base.localAvatar.enableSmartCameraViews() base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex) place = base.cr.playGame.getPlace() if self.doJellyBeans: self.sendUpdate('awardBeans', [self.numBeansCollected, int(self.topHeight)]) if int(self.topHeight) > self.bestHeightInfo[1]: self.sendUpdate('reportHeightInformation', [int(self.topHeight)]) self.d_toonExitDemand() def onTrampolineTrigger(self, collEntry): if self.activityFSM.state == 'Idle' and self.toon == None and base.cr.playGame.getPlace().fsm.getCurrentState().getName() == 'walk': base.cr.playGame.getPlace().fsm.request('activity') self.d_toonJoinRequest() else: self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied, duration=2.0) return def onJump(self): self.notify.debug('got onJump') if self.toon != None and self.toon.getZ() < self.trampHeight: self.toonJumped = True self.b_requestAnim('Jump') else: self.notify.debug('z is less than tramp height') return def onLeft(self): self.turnLeft = True def onLeftUp(self): self.turnLeft = False def onRight(self): self.turnRight = True def onRightUp(self): self.turnRight = False def handleToonJoined(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonJoined') self.toon = self.getAvatar(toonId) if self.toon != None and not self.toon.isEmpty(): self.oldJumpSquatPlayRate = self.toon.getPlayRate('jump-squat') self.oldJumpLandPlayRate = self.toon.getPlayRate('jump-land') self.toon.setPlayRate(2.5, 'jump-squat') self.toon.setPlayRate(2.0, 'jump-land') self.turnLeft = False self.turnRight = False self.activityFSM.request('Rules') if self.toon.doId != base.localAvatar.doId: taskMgr.add(self.remoteUpdateTask, self.uniqueName('TrampolineActivity.remoteUpdateTask')) else: self.notify.warning('handleToonJoined could not get toon %d' % toonId) return def handleToonExited(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonExited') if self.toon != None: if self.toon.doId != base.localAvatar.doId: taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask')) self.surface.setZ(self.trampHeight) self.toon.setPlayRate(self.oldJumpSquatPlayRate, 'jump-squat') self.toon.setPlayRate(self.oldJumpLandPlayRate, 'jump-land') self.toon = None return def handleToonDisabled(self, toonId): DistributedPartyTrampolineActivity.notify.debug('handleToonDisabled') DistributedPartyTrampolineActivity.notify.debug('avatar ' + str(toonId) + ' disabled') if base.localAvatar.doId == toonId: self.releaseToon() def handleRulesDone(self): self.sendUpdate('toonReady') self.finishRules() def getTitle(self): if self.doJellyBeans: return TTLocalizer.PartyTrampolineJellyBeanTitle elif self.doTricks: return TTLocalizer.PartyTrampolineTricksTitle else: return DistributedPartyActivity.getTitle(self) def getInstructions(self): return TTLocalizer.PartyTrampolineActivityInstructions def updateTask(self, task): z = self.toon.getZ() dt = globalClock.getDt() if self.doSimulateStep: self.timeLeftToSimulate += dt while self.timeLeftToSimulate >= self.stepDT: z, a = self.simulateStep(z) self.timeLeftToSimulate -= self.stepDT self.toon.setZ(z) if z <= self.trampHeight: self.surface.setZ(z) else: self.surface.setZ(self.trampHeight) self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor) if self.turnLeft: self.toon.setH(self.toon.getH() + self.turnFactor * dt) if self.turnRight: self.toon.setH(self.toon.getH() - self.turnFactor * dt) currentPos = base.camera.getPos(self.toon) vec = self.targetCameraPos - currentPos newPos = currentPos + vec * (dt * self.cameraSpeed) base.camera.setPos(self.toon, newPos) base.camera.lookAt(self.toon) #if z > self.trampHeight: # heightFactor = 1.0 - min(1.0, (z - self.trampHeight) / self.dropShadowCutoff) # self.toon.dropShadow.setAlphaScale(heightFactor) # self.toon.dropShadow.setScale(max(0.1, heightFactor)) #else: # self.toon.dropShadow.setAlphaScale(1.0) # self.toon.dropShadow.setScale(1.0) if self.leavingTrampoline and z < self.trampHeight and abs(a) < 0.1: self.releaseToon() return Task.cont def simulateStep(self, z): if z >= self.trampHeight: a = self.g self.toonJumped = False else: a = self.g + self.trampK * (self.trampHeight - z) - self.trampB * self.toonVelocity if self.toonJumped: if self.lastPeak > self.earlyJumpThreshold or self.toonVelocity >= -300000.0: a += self.jumpBoost if self.lastPeak < self.beginningBoostThreshold: a += self.beginningBoost lastVelocity = self.toonVelocity self.toonVelocity += a * self.stepDT if lastVelocity > 0.0 and self.toonVelocity <= 0.0: topOfJump = True bottomOfJump = False elif lastVelocity < 0.0 and self.toonVelocity >= 0.0: topOfJump = False bottomOfJump = True else: topOfJump = False bottomOfJump = False newZ = z + self.toonVelocity * self.stepDT if newZ > self.topHeight: self.topHeight = newZ if self.doJellyBeans: self.collectJellyBeans(newZ) if topOfJump: self.lastPeak = newZ if newZ >= self.minHeightForText: self.heightTextInterval.start() if topOfJump: if newZ > self.trampHeight + 20.0: self.b_requestAnim('Falling') elif self.animFSM.state == 'Jump': self.b_requestAnim('Falling') if newZ <= self.trampHeight and z > self.trampHeight: if self.animFSM.state == 'Falling': self.b_requestAnim('Land') elif self.animFSM.state != 'Neutral': self.b_requestAnim('Neutral') if bottomOfJump and a > self.boingThreshold: base.playSfx(self.boingSound) return (newZ, a) def collectJellyBeans(self, z): beansToRemove = [] for i in self.beansToCollect: height = self.beanDetails[i][0] if height <= z: beansToRemove.append(i) if len(beansToRemove) > 0: base.playSfx(self.jellyBeanSound) self.numBeansCollected += len(beansToRemove) self.b_removeBeans(beansToRemove) def remoteUpdateTask(self, task): if self.toon != None and not self.toon.isEmpty(): z = self.toon.getZ() if z <= self.trampHeight: self.surface.setZ(z) else: self.surface.setZ(self.trampHeight) return Task.cont def poofBean(self, bean, beanAnim): if bean == None: self.notify.warning('poofBean, returning immediately as bean is None') return if bean.isEmpty(): self.notify.warning('poofBean, returning immediately as bean is empty') return currentAlpha = bean.getColorScale()[3] currentScale = bean.getScale() poofAnim = Sequence(Parallel(LerpFunc(bean.setAlphaScale, fromData=currentAlpha, toData=0.0, duration=0.25), LerpFunc(bean.setScale, fromData=currentScale, toData=currentScale * 5.0, duration=0.25)), Func(bean.stash), Func(beanAnim.finish), Func(bean.setAlphaScale, currentAlpha), Func(bean.setScale, currentScale)) poofAnim.start() return def _showFlashMessage(self, message): if self.isDisabled(): return if self.flashTextInterval is not None and self.flashTextInterval.isPlaying(): self.flashTextInterval.finish() self.flashText.setText(message) self.flashText.setAlphaScale(1.0) self.flashText.unstash() return def _hideFlashMessage(self, duration = 0.0): if self.isDisabled(): pass self.flashTextInterval = Sequence(Wait(duration), LerpFunc(self.flashText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), Func(self.flashText.stash)) self.flashTextInterval.start() def flashMessage(self, message, duration = 0.5): self._showFlashMessage(message) self._hideFlashMessage(duration)
class DistributedPartyGate(DistributedObject.DistributedObject): notify = DirectNotifyGlobal.directNotify.newCategory("DistributedPartyGate") def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.publicPartyChooseGuiDoneEvent = "doneChoosingPublicParty" self.publicPartyGui = PublicPartyGui(self.publicPartyChooseGuiDoneEvent) self.publicPartyGui.stash() self.loadClockSounds() self.hourSoundInterval = Sequence() self.accept("stoppedAsleep", self.handleSleep) def loadClockSounds(self): self.clockSounds = [] for i in range(1, 13): if i < 10: si = "0%d" % i else: si = "%d" % i self.clockSounds.append(base.loadSfx("phase_4/audio/sfx/clock%s.mp3" % si)) def generate(self): DistributedObject.DistributedObject.generate(self) loader = self.cr.playGame.hood.loader partyGate = loader.geom.find("**/partyGate_grp") if partyGate.isEmpty(): self.notify.warning("Could not find partyGate_grp in loader.geom") return None self.clockFlat = partyGate.find("**/clock_flat") collSphere = CollisionSphere(0, 0, 0, 6.9000000000000004) collSphere.setTangible(1) self.partyGateSphere = CollisionNode("PartyGateSphere") self.partyGateSphere.addSolid(collSphere) self.partyGateCollNodePath = partyGate.find("**/partyGate_stepsLocator").attachNewNode(self.partyGateSphere) self._DistributedPartyGate__enableCollisions() self.toontownTimeGui = ServerTimeGui(partyGate, hourCallback=self.hourChange) self.toontownTimeGui.setPos( partyGate.find("**/clockText_locator").getPos() + Point3(0.0, 0.0, -0.20000000000000001) ) self.toontownTimeGui.setHpr(partyGate.find("**/clockText_locator").getHpr()) self.toontownTimeGui.setScale(12.0, 1.0, 26.0) self.toontownTimeGui.amLabel.setPos(-0.035000000000000003, 0, -0.032000000000000001) self.toontownTimeGui.amLabel.setScale(0.5) self.toontownTimeGui.updateTime() self.setupSignText() def setupSignText(self): loader = self.cr.playGame.hood.loader partyGate = loader.geom.find("**/partyGateSignGroup") if partyGate.isEmpty(): self.notify.warning("Could not find partyGate_grp in loader.geom") return None gateFont = ToontownGlobals.getMinnieFont() leftSign = partyGate.find("**/signTextL_locatorBack") signScale = 0.34999999999999998 wordWrap = 8 leftText = DirectLabel.DirectLabel( parent=leftSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateLeftSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.69999999999999996, 0.29999999999999999, 0.29999999999999999, 1.0), scale=signScale, ) rightSign = partyGate.find("**/signTextR_locatorFront") rightText = DirectLabel.DirectLabel( parent=rightSign, pos=(0, 0.0, 0.0), relief=None, text=TTLocalizer.PartyGateRightSign, text_align=TextNode.ACenter, text_font=gateFont, text_wordwrap=wordWrap, text_fg=Vec4(0.69999999999999996, 0.29999999999999999, 0.29999999999999999, 1.0), scale=signScale, ) def announceGenerate(self): DistributedObject.DistributedObject.announceGenerate(self) if ToontownGlobals.dnaMap.has_key(self.zoneId): playground = ToontownGlobals.dnaMap[self.zoneId] else: playground = ToontownGlobals.dnaMap[2000] self.toontownTimeGui.hourLabel["text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.colonLabel["text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.minutesLabel["text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] self.toontownTimeGui.amLabel["text_fg"] = PartyGlobals.PlayGroundToPartyClockColors[playground] def disable(self): DistributedObject.DistributedObject.disable(self) self._DistributedPartyGate__disableCollisions() self.toontownTimeGui.ival.finish() self.hourSoundInterval.finish() if self.publicPartyGui: self.publicPartyGui.stash() self.publicPartyGui.destroy() self.publicPartyGui = None def delete(self): DistributedObject.DistributedObject.delete(self) self.toontownTimeGui.destroy() del self.toontownTimeGui self.hourSoundInterval.finish() del self.hourSoundInterval del self.clockFlat if self.publicPartyGui: self.publicPartyGui.destroy() del self.publicPartyGui self.partyGateCollNodePath.removeNode() del self.partyGateCollNodePath self.ignoreAll() def showMessage(self, message): self.messageDoneEvent = self.uniqueName("messageDoneEvent") self.acceptOnce(self.messageDoneEvent, self._DistributedPartyGate__handleMessageDone) self.messageGui = TTDialog.TTGlobalDialog( doneEvent=self.messageDoneEvent, message=message, style=TTDialog.Acknowledge ) def _DistributedPartyGate__handleMessageDone(self): self.ignore(self.messageDoneEvent) self.freeAvatar() self.messageGui.cleanup() self.messageGui = None def _DistributedPartyGate__handleAskDone(self): DistributedPartyGate.notify.debug("__handleAskDone") self.ignore(self.publicPartyChooseGuiDoneEvent) doneStatus = self.publicPartyGui.doneStatus self.publicPartyGui.stash() if doneStatus is None: self.freeAvatar() return None self.sendUpdate("partyChoiceRequest", [base.localAvatar.doId, doneStatus[0], doneStatus[1]]) def partyRequestDenied(self, reason): DistributedPartyGate.notify.debug( "partyRequestDenied( reason=%s )" % PartyGlobals.PartyGateDenialReasons.getString(reason) ) if reason == PartyGlobals.PartyGateDenialReasons.Unavailable: self.showMessage(TTLocalizer.PartyGatePartyUnavailable) elif reason == PartyGlobals.PartyGateDenialReasons.Full: self.showMessage(TTLocalizer.PartyGatePartyFull) def setParty(self, partyInfoTuple): DistributedPartyGate.notify.debug("setParty") self.freeAvatar() if partyInfoTuple[0] == 0: DistributedPartyGate.notify.debug("Public Party closed before toon could get to it.") return None (shardId, zoneId, numberOfGuests, hostName, activityIds, lane) = partyInfoTuple if base.localAvatar.defaultShard == shardId: shardId = None base.cr.playGame.getPlace().requestLeave( { "loader": "safeZoneLoader", "where": "party", "how": "teleportIn", "hoodId": ToontownGlobals.PartyHood, "zoneId": zoneId, "shardId": shardId, "avId": -1, } ) def freeAvatar(self): base.localAvatar.posCamera(0, 0) base.cr.playGame.getPlace().setState("walk") def hourChange(self, currentHour): currentHour = currentHour % 12 if currentHour == 0: currentHour = 12 self.hourSoundInterval = Parallel() seq1 = Sequence() for i in range(currentHour): seq1.append(SoundInterval(self.clockSounds[i])) seq1.append(Wait(0.20000000000000001)) timeForEachDeformation = seq1.getDuration() / currentHour seq2 = Sequence() for i in range(currentHour): seq2.append( self.clockFlat.scaleInterval( timeForEachDeformation / 2.0, Vec3(0.90000000000000002, 1.0, 1.2), blendType="easeInOut" ) ) seq2.append( self.clockFlat.scaleInterval( timeForEachDeformation / 2.0, Vec3(1.2, 1.0, 0.90000000000000002), blendType="easeInOut" ) ) seq2.append( self.clockFlat.scaleInterval(timeForEachDeformation / 2.0, Vec3(1.0, 1.0, 1.0), blendType="easeInOut") ) self.hourSoundInterval.append(seq1) self.hourSoundInterval.append(seq2) self.hourSoundInterval.start() def handleEnterGateSphere(self, collEntry): self.notify.debug("Entering steps Sphere....") base.cr.playGame.getPlace().fsm.request("stopped") self.sendUpdate("getPartyList", [base.localAvatar.doId]) def listAllPublicParties(self, publicPartyInfo): self.notify.debug("listAllPublicParties : publicPartyInfo = %s" % publicPartyInfo) self.acceptOnce(self.publicPartyChooseGuiDoneEvent, self._DistributedPartyGate__handleAskDone) self.publicPartyGui.refresh(publicPartyInfo) self.publicPartyGui.unstash() def _DistributedPartyGate__enableCollisions(self): self.accept("enterPartyGateSphere", self.handleEnterGateSphere) self.partyGateSphere.setCollideMask(OTPGlobals.WallBitmask) def _DistributedPartyGate__disableCollisions(self): self.ignore("enterPartyGateSphere") self.partyGateSphere.setCollideMask(BitMask32(0)) def handleSleep(self): if hasattr(self, "messageGui") and self.messageGui: self._DistributedPartyGate__handleMessageDone()