def initCollisions(self): # Make a sphere, give it a unique name, and parent it # to the suit. self.collSphere = CollisionSphere(0, 0, 0, 1.25) # Make he sphere intangible self.collSphere.setTangible(1) name = "CogThiefSphere-%d" % self.cogIndex self.collSphereName = self.uniqueName(name) self.collNode = CollisionNode(self.collSphereName) self.collNode.setIntoCollideMask(CTGG.BarrelBitmask | ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.suit.attachNewNode(self.collNode) #self.collNodePath.hide() # Add a hook looking for collisions with localToon self.accept('enter' + self.collSphereName, self.handleEnterSphere) # we need a taller collision tube to collide against for pie self.pieCollSphere = CollisionTube(0, 0, 0, 0, 0, 4, self.CollisionRadius) # Make he sphere intangible self.pieCollSphere.setTangible(1) name = "CogThiefPieSphere-%d" % self.cogIndex self.pieCollSphereName = self.uniqueName(name) self.pieCollNode = CollisionNode(self.pieCollSphereName) self.pieCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.pieCollNode.addSolid(self.pieCollSphere) self.pieCollNodePath = self.suit.attachNewNode(self.pieCollNode)
def _initCollisions(self, triggerRadius, triggerOffset): self.collSphere = CollisionSphere(triggerOffset[0], triggerOffset[1], triggerOffset[2], triggerRadius) self.collSphere.setTangible(0) self.collNode = CollisionNode(self.getName()) self.collNode.addSolid(self.collSphere) self.collNodePath = self.attachNewNode(self.collNode)
def loadAssets(self): """Load our assets.""" self.root = render.attachNewNode('golfSpot-%d' % self.index) self.root.setPos(*self.positions[self.index]) self.ballModel = loader.loadModel('phase_6/models/golf/golf_ball') self.ballColor = VBase4(1, 1, 1, 1) if self.index < len(GolfGlobals.PlayerColors): self.ballColor = VBase4(*GolfGlobals.PlayerColors[self.index]) self.ballModel.setColorScale(self.ballColor) self.ballModel.reparentTo(self.root) self.club = loader.loadModel('phase_6/models/golf/putter') self.clubLookatSpot = self.root.attachNewNode('clubLookat') self.clubLookatSpot.setY(-(GolfGlobals.GOLF_BALL_RADIUS + 0.1)) # create a collision sphere to trigger when we touch the ball # Make a trigger sphere so we can detect when the local avatar # runs up to the controls. We bury the sphere mostly under # the floor to minimize accidental collisions. cs = CollisionSphere(0, 0, 0, 1) cs.setTangible(0) cn = CollisionNode(self.triggerName) cn.addSolid(cs) cn.setIntoCollideMask(ToontownGlobals.WallBitmask) self.trigger = self.root.attachNewNode(cn) self.trigger.stash() self.hitBallSfx = loader.loadSfx('phase_6/audio/sfx/Golf_Hit_Ball.mp3')
def _initCollisions(self): offset = Globals.WaterCoolerTriggerOffset self.collSphere = CollisionSphere(offset[0], offset[1], offset[2], Globals.WaterCoolerTriggerRadius) self.collSphere.setTangible(0) name = Globals.WaterCoolerCollisionName self.collNode = CollisionNode(name) self.collNode.addSolid(self.collSphere) self.collNodePath = self.attachNewNode(self.collNode)
def _initCollisions(self): name = "CogdoMazeLock-%d" % self.id collSphere = CollisionSphere(0, 0, 0.0, 0.25) collSphere.setTangible(0) collNode = CollisionNode(name) collNode.setFromCollideMask(ToontownGlobals.CatchGameBitmask) collNode.addSolid(collSphere) self.model.attachNewNode(collNode) self.enterCollisionEventName = "enter" + name
def initCollision(self): self.collSphere = CollisionSphere(0, 0, 0, 0) self.collSphere.setTangible(0) self.collNode = CollisionNode('%s-%s' % (self.CollSphereName, self.index)) self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.suit.attachNewNode(self.collNode) self.collNodePath.hide() self.accept('enter%s-%s' % (self.CollSphereName, self.index), self.handleEnterSphere) self.setCollSphereToNest()
def pieThrow(self, avId, timestamp, heading, pos, power): """Show local or remote toon throwing a pie.""" toon = self.activity.getAvatar(avId) if toon is None: return tossTrack, pieTrack, flyPie = self.getTossPieInterval( toon, pos[0], pos[1], pos[2], heading, 0, 0, power) if avId == base.localAvatar.doId: flyPie.setTag('throwerId', str(avId)) collSphere = CollisionSphere(0, 0, 0, 0.5) # Make the sphere intangible collSphere.setTangible(0) name = "PieSphere-%d" % avId collSphereName = self.activity.uniqueName(name) collNode = CollisionNode(collSphereName) collNode.setFromCollideMask(ToontownGlobals.PieBitmask) collNode.addSolid(collSphere) collNP = flyPie.attachNewNode(collNode) base.cTrav.addCollider(collNP, self.pieHandler) self.toonPieEventNames[collNP] = 'pieHit-' + collSphereName self.accept(self.toonPieEventNames[collNP], self.handlePieCollision) else: player = self.players.get(avId) if player is not None: player.faceForward() def matchRunningAnim(toon=toon): toon.playingAnim = None toon.setSpeed(toon.forwardSpeed, toon.rotateSpeed) newTossTrack = Sequence(tossTrack, Func(matchRunningAnim)) pieTrack = Parallel(newTossTrack, pieTrack, name="PartyCogActivity.pieTrack-%d-%s" % (avId, timestamp)) elapsedTime = globalClockDelta.localElapsedTime(timestamp) if elapsedTime < 16. / 24.: elapsedTime = 16. / 24. # make the pie fly immediately pieTrack.start(elapsedTime) self.pieIvals.append(pieTrack) self.toonPieTracks[avId] = pieTrack
def createThrowGag(self, gag): throwGag = CogdoMazePlayer.createThrowGag(self, gag) collSphere = CollisionSphere(0, 0, 0, 0.5) collSphere.setTangible(0) name = Globals.GagCollisionName collNode = CollisionNode(name) collNode.setFromCollideMask(ToontownGlobals.PieBitmask) collNode.addSolid(collSphere) colNp = throwGag.attachNewNode(collNode) base.cTrav.addCollider(colNp, self.gagHandler) return throwGag
def __initCollisions(self): collSphere = CollisionSphere(0, 0, 0, Globals.PlayerCollisionRadius) collSphere.setTangible(0) self.mazeCollisionName = Globals.LocalPlayerCollisionName collNode = CollisionNode(self.mazeCollisionName) collNode.addSolid(collSphere) collNodePath = self.toon.attachNewNode(collNode) collNodePath.hide() handler = CollisionHandlerEvent() handler.addInPattern('%fn-into-%in') base.cTrav.addCollider(collNodePath, handler) self.handler = handler self._collNodePath = collNodePath
def setupHeadSphere(self, avatarNodePath): collSphere = CollisionSphere(0, 0, 0, 1) collSphere.setTangible(1) collNode = CollisionNode('Flyer.cHeadCollSphere') collNode.setFromCollideMask(ToontownGlobals.CeilingBitmask) collNode.setIntoCollideMask(BitMask32.allOff()) collNode.addSolid(collSphere) self.cHeadSphereNodePath = avatarNodePath.attachNewNode(collNode) self.cHeadSphereNodePath.setZ(base.localAvatar.getHeight() + 1.0) self.headCollisionEvent = CollisionHandlerEvent() self.headCollisionEvent.addInPattern('%fn-enter-%in') self.headCollisionEvent.addOutPattern('%fn-exit-%in') base.cTrav.addCollider(self.cHeadSphereNodePath, self.headCollisionEvent)
def setupEventSphere(self, bitmask, avatarRadius): self.avatarRadius = avatarRadius cSphere = CollisionSphere(0.0, 0.0, self.avatarRadius + 0.75, self.avatarRadius * 1.04) cSphere.setTangible(0) cSphereNode = CollisionNode('Flyer.cEventSphereNode') cSphereNode.addSolid(cSphere) cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode) cSphereNode.setFromCollideMask(bitmask) cSphereNode.setIntoCollideMask(BitMask32.allOff()) self.event = CollisionHandlerEvent() self.event.addInPattern('enter%in') self.event.addOutPattern('exit%in') self.cEventSphereNodePath = cSphereNodePath
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 loadModel(self): """Load the necessary assets.""" self.hill = loader.loadModel("phase_12/models/bossbotHQ/mole_hole") self.hill.setZ(0.0) self.hill.reparentTo(self) #self.hill.setScale(20.0) # find the collision node of the hill and rename it #hillCollision = self.hill.find('**/dirt_collision') self.hillColName = 'moleHillCol-%d-%d' % (self.moleField.doId, self.index) #hillCollision.setName(self.hillColName) self.moleField.accept('enter' + self.hillColName, self.moleField.handleEnterHill) self.mole = self.attachNewNode("mole")#loader.loadModel("phase_12/models/bossbotHQ/mole_norm") self.mole.reparentTo(self) self.mole.setScale(0.75) self.mole.setZ(-2.5) self.moleHead = loader.loadModel("phase_12/models/bossbotHQ/mole_norm") self.moleHead.reparentTo(self.mole) # setup mole collision moleColName = "moleCol-%d-%s" % (self.moleField.doId,self.index) moleSphere = CollisionSphere(0, 0, 0, 1.0) collNode = CollisionNode(moleColName) collNode.setIntoCollideMask(ToontownGlobals.WallBitmask) collNode.addSolid(moleSphere) self.moleColNodePath = self.mole.attachNewNode(collNode) self.moleColNodePath.stash() self.moleColNodePath.setScale(1.0) self.moleField.accept('enter' + moleColName, self.moleField.handleEnterMole)
def setupElevatorKart(self): """Setup elevator related fields.""" # Establish a collision sphere. There must be an easier way! collisionRadius = ElevatorConstants.ElevatorData[self.type]['collRadius'] self.elevatorSphere = CollisionSphere(0, 0, 0, collisionRadius) self.elevatorSphere.setTangible(1) self.elevatorSphereNode = CollisionNode(self.uniqueName("elevatorSphere")) self.elevatorSphereNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.elevatorSphereNode.addSolid(self.elevatorSphere) self.elevatorSphereNodePath = self.getElevatorModel().attachNewNode( self.elevatorSphereNode) self.elevatorSphereNodePath.hide() self.elevatorSphereNodePath.reparentTo(self.getElevatorModel()) self.elevatorSphereNodePath.stash() self.boardedAvIds = {} self.finishSetup()
def generateInit(self): DistributedFireworkShow.DistributedFireworkShow.generateInit(self) """generateInit(self) This method is called when the DistributedObject is first introduced to the world... Not when it is pulled from the cache. """ self.fireworksSphereEvent = self.uniqueName("fireworksSphere") self.fireworksSphereEnterEvent = "enter" + self.fireworksSphereEvent self.fireworksGuiDoneEvent = "fireworksGuiDone" self.shootEvent = "fireworkShootEvent" self.collSphere = CollisionSphere(0, 0, 0, 2.5) # Make the sphere intangible self.collSphere.setTangible(1) self.collNode = CollisionNode(self.fireworksSphereEvent) self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.geom.attachNewNode(self.collNode)
def setupFloorEventSphere(self, avatarNodePath, bitmask, avatarRadius): cSphere = CollisionSphere(0.0, 0.0, 0.0, 0.75) cSphereNode = CollisionNode('Flyer.cFloorEventSphere') cSphereNode.addSolid(cSphere) cSphereNodePath = avatarNodePath.attachNewNode(cSphereNode) cSphereNode.setFromCollideMask(bitmask) cSphereNode.setIntoCollideMask(BitMask32.allOff()) self.floorCollisionEvent = CollisionHandlerEvent() self.floorCollisionEvent.addInPattern('%fn-enter-%in') self.floorCollisionEvent.addAgainPattern('%fn-again-%in') self.floorCollisionEvent.addOutPattern('%fn-exit-%in') base.cTrav.addCollider(cSphereNodePath, self.floorCollisionEvent) self.cFloorEventSphereNodePath = cSphereNodePath
def getFlyBallBubble(self): if self.__flyBallBubble == None: bubble = CollisionSphere(0, 0, 0, GolfGlobals.GOLF_BALL_RADIUS) node = CollisionNode('flyBallBubble') node.addSolid(bubble) node.setFromCollideMask(ToontownGlobals.PieBitmask | ToontownGlobals.CameraBitmask | ToontownGlobals.FloorBitmask) node.setIntoCollideMask(BitMask32.allOff()) self.__flyBallBubble = NodePath(node) self.flyBallHandler = CollisionHandlerEvent() self.flyBallHandler.addInPattern('flyBallHit-%d' % self.index) #self.flyBallHandler.addInPattern('flyBallHit-%d--%in') return self.__flyBallBubble
def setupWallSphere(self, bitmask, avatarRadius): self.avatarRadius = avatarRadius cSphere = CollisionSphere(0.0, 0.0, self.avatarRadius + 0.75, self.avatarRadius) cSphereNode = CollisionNode('Flyer.cWallSphereNode') cSphereNode.addSolid(cSphere) cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode) cSphereNode.setFromCollideMask(bitmask) cSphereNode.setIntoCollideMask(BitMask32.allOff()) if ConfigVariableBool('want-fluid-pusher', 0).getValue(): self.pusher = CollisionHandlerFluidPusher() else: self.pusher = CollisionHandlerPusher() self.pusher.addCollider(cSphereNodePath, self.avatarNodePath) self.cWallSphereNodePath = cSphereNodePath
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 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)
class CogdoGameGatherable(NodePath, DirectObject): EnterEventName = 'CogdoGameGatherable_Enter' def __init__(self, serialNum, model, triggerRadius, triggerOffset=(0, 0, 0), animate=True, animDuration=0.2, instanceModel=True, name='CogdoGameGatherable'): NodePath.__init__(self, '%s-%d' % (name, serialNum)) self.serialNum = serialNum self._animate = animate if instanceModel: model.instanceTo(self) self._model = self else: self._model = model self._model.reparentTo(self) self._model.setPosHpr(0, 0, 0, 0, 0, 0) self._animDuration = animDuration self._animSeq = None self._initCollisions(triggerRadius, triggerOffset) self._update = None self._wasPickedUp = False return def _initCollisions(self, triggerRadius, triggerOffset): self.collSphere = CollisionSphere(triggerOffset[0], triggerOffset[1], triggerOffset[2], triggerRadius) self.collSphere.setTangible(0) self.collNode = CollisionNode(self.getName()) self.collNode.addSolid(self.collSphere) self.collNodePath = self.attachNewNode(self.collNode) def destroy(self): self.disable() del self._model if self._animSeq is not None: self._animSeq.finish() self._animSeq = None self.collNodePath.removeNode() self.removeNode() return def enable(self): self.accept('enter' + self.getName(), self._handleEnterCollision) self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask) def disable(self): self.ignoreAll() self.collNode.setIntoCollideMask(BitMask32(0)) def show(self): if not self.wasPickedUp(): NodePath.show(self) self.enable() def hide(self): self.disable() NodePath.hide(self) def _handleEnterCollision(self, collEntry): messenger.send(CogdoGameGatherable.EnterEventName, [self]) def wasPickedUp(self): return self._wasPickedUp def wasPickedUpByToon(self): pass def update(self, dt): pass def getModel(self): return self._model def pickUp(self, toon, elapsedSeconds=0.0): self._wasPickedUp = True if self._animSeq is not None: self._animSeq.finish() self._animSeq = None if self._animate: def lerpFlyToToon(t): vec = toon.getPos(render) - self.getPos(render) vec[2] += toon.getHeight() self.setPos(self.getPos() + vec * t) self.setScale(1.0 - t * 0.8) self._animSeq = Sequence( LerpFunc(lerpFlyToToon, fromData=0.0, toData=1.0, duration=self._animDuration), Wait(0.1), Func(self.hide)) self._animSeq.start(elapsedSeconds) else: self.hide() return
class CogThief(DirectObject): """This represents a single cog thief in the cog thief game""" notify = directNotify.newCategory("CogThief") DefaultSpeedWalkAnim = 4. CollisionRadius = 1.25 MaxFriendsVisible = 4 Infinity = 100000.0 # just a really big number SeparationDistance = 6.0 MinUrgency = 0.5 MaxUrgency = 0.75 def __init__(self, cogIndex, suitType, game, cogSpeed): self.cogIndex = cogIndex self.suitType = suitType self.game = game self.cogSpeed = cogSpeed suit = Suit.Suit() d = SuitDNA.SuitDNA() d.newSuit(suitType) suit.setDNA(d) # cache the walk anim suit.pose('walk', 0) self.suit = suit self.goal = CTGG.NoGoal self.goalId = CTGG.InvalidGoalId self.lastLocalTimeStampFromAI = 0 self.lastPosFromAI = Point3(0, 0, 0) self.lastThinkTime = 0 self.doneAdjust = False self.barrel = CTGG.NoBarrelCarried self.signalledAtReturnPos = False self.defaultPlayRate = 1.0 self.netTimeSentToStartByHit = 0 # steering loosely based on boid code game programming gems #1 # "Portions Copyright (C) Steven Woodcock, 2000" self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) self.bodyLength = self.CollisionRadius * 2 # Desired distance from closest neighbor when flying. self.cruiseDistance = 2 * self.bodyLength self.maxVelocity = self.cogSpeed # Maximum magnitude of acceleration as a fraction of maxSpeed. self.maxAcceleration = 5.0 self.perceptionRange = 6 self.notify.debug('cogSpeed=%s' % self.cogSpeed) self.kaboomSound = loader.loadSfx( "phase_4/audio/sfx/MG_cannon_fire_alt.mp3") self.kaboom = loader.loadModel( 'phase_4/models/minigames/ice_game_kaboom') self.kaboom.setScale(2.0) self.kaboom.setBillboardPointEye() self.kaboom.hide() self.kaboomTrack = None splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.mp3') def destroy(self): self.ignoreAll() self.suit.delete() self.game = None def uniqueName(self, baseStr): return baseStr + '-' + str(self.game.doId) def handleEnterSphere(self, collEntry): """Handle the suit colliding with localToon.""" #assert self.notify.debugStateCall(self) intoNp = collEntry.getIntoNodePath() self.notify.debug('handleEnterSphere suit %d hit %s' % (self.cogIndex, intoNp)) if self.game: self.game.handleEnterSphere(collEntry) def gameStart(self, gameStartTime): self.gameStartTime = gameStartTime self.initCollisions() self.startWalkAnim() def gameEnd(self): self.moveIval.pause() del self.moveIval self.shutdownCollisions() # keep the suits from walking in place self.suit.loop('neutral') def initCollisions(self): # Make a sphere, give it a unique name, and parent it # to the suit. self.collSphere = CollisionSphere(0, 0, 0, 1.25) # Make he sphere intangible self.collSphere.setTangible(1) name = "CogThiefSphere-%d" % self.cogIndex self.collSphereName = self.uniqueName(name) self.collNode = CollisionNode(self.collSphereName) self.collNode.setIntoCollideMask(CTGG.BarrelBitmask | ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.suit.attachNewNode(self.collNode) #self.collNodePath.hide() # Add a hook looking for collisions with localToon self.accept('enter' + self.collSphereName, self.handleEnterSphere) # we need a taller collision tube to collide against for pie self.pieCollSphere = CollisionTube(0, 0, 0, 0, 0, 4, self.CollisionRadius) # Make he sphere intangible self.pieCollSphere.setTangible(1) name = "CogThiefPieSphere-%d" % self.cogIndex self.pieCollSphereName = self.uniqueName(name) self.pieCollNode = CollisionNode(self.pieCollSphereName) self.pieCollNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.pieCollNode.addSolid(self.pieCollSphere) self.pieCollNodePath = self.suit.attachNewNode(self.pieCollNode) #self.pieCollNodePath.show() # Add a hook looking for collisions with localToon #self.accept('enter' + self.pieCollSphereName, # self.handleEnter) def shutdownCollisions(self): self.ignore(self.uniqueName('enter' + self.collSphereName)) del self.collSphere self.collNodePath.removeNode() del self.collNodePath del self.collNode def updateGoal(self, timestamp, inResponseClientStamp, goalType, goalId, pos): """Update our goal and position.""" assert self.notify.debugStateCall(self) self.notify.debug('self.netTimeSentToStartByHit =%s' % self.netTimeSentToStartByHit) if not self.game: self.notify.debug('updateGoal self.game is None, just returning') return if not self.suit: self.notify.debug('updateGoal self.suit is None, just returning') return if self.goal == CTGG.NoGoal: self.startWalkAnim() if goalType == CTGG.NoGoal: self.notify.debug('updateGoal setting position to %s' % pos) self.suit.setPos(pos) self.lastThinkTime = 0 self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) if goalType == CTGG.RunAwayGoal: #import pdb; pdb.set_trace() pass if inResponseClientStamp < self.netTimeSentToStartByHit and \ self.goal == CTGG.NoGoal and \ goalType == CTGG.RunAwayGoal: #import pdb; pdb.set_trace() self.notify.warning( 'ignoring newGoal %s as cog %d was recently hit responsetime=%s hitTime=%s' % (CTGG.GoalStr[goalType], self.cogIndex, inResponseClientStamp, self.netTimeSentToStartByHit)) else: self.lastLocalTimeStampFromAI = globalClockDelta.networkToLocalTime( timestamp, bits=32) self.goal = goalType self.goalId = goalId self.lastPosFromAI = pos self.doneAdjust = False self.signalledAtReturnPos = False # TODO move the suit to where we expect him to be given the time difference def startWalkAnim(self): if self.suit: self.suit.loop('walk') speed = self.cogSpeed # float(MazeData.CELL_WIDTH) / self.cellWalkDuration self.defaultPlayRate = float(self.cogSpeed / self.DefaultSpeedWalkAnim) self.suit.setPlayRate(self.defaultPlayRate, 'walk') def think(self): """Calculate where we should go.""" if self.goal == CTGG.ToonGoal: self.thinkAboutCatchingToon() elif self.goal == CTGG.BarrelGoal: self.thinkAboutGettingBarrel() elif self.goal == CTGG.RunAwayGoal: self.thinkAboutRunAway() def thinkAboutCatchingToon(self): if not self.game: return av = self.game.getAvatar(self.goalId) if av: if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime avPos = av.getPos() myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.notify.debug( 'thinkAboutCatchingToon not doneAdjust setting pos %s' % myPos) self.doneAdjust = True self.suit.setPos(myPos) if self.game.isToonPlayingHitTrack(self.goalId): # do nothing, just look at toon self.suit.headsUp(av) self.velocity = Vec3(0, 0, 0) self.oldVelocity = Vec3(0, 0, 0) self.acceleration = Vec3(0, 0, 0) else: self.commonMove() newPos = self.suit.getPos() self.adjustPlayRate(newPos, myPos, diffTime) self.lastThinkTime = globalClock.getFrameTime() def convertNetworkStampToGameTime(self, timestamp): """Convert a network timestamp to game time.""" localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) gameTime = self.game.local2GameTime(localStamp) return gameTime def respondToToonHit(self, timestamp): """The toon hit us, react appropriately.""" assert self.notify.debugStateCall(self) localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) # using 1.0 sec as fudge #if localStamp > self.lastLocalTimeStampFromAI: if self.netTimeSentToStartByHit < timestamp: self.clearGoal() self.showKaboom() # move him to his starting postion startPos = CTGG.CogStartingPositions[self.cogIndex] oldPos = self.suit.getPos() self.suit.setPos(startPos) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'localStamp = %s, lastLocalTimeStampFromAI=%s, ignoring respondToToonHit' % (localStamp, self.lastLocalTimeStampFromAI)) self.notify.debug( 'respondToToonHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearGoal(self): """Clear goal and goal id.""" self.goal = CTGG.NoGoal self.goalId = CTGG.InvalidGoalId def thinkAboutGettingBarrel(self): """Go for a barrel.""" if not self.game: return if not hasattr(self.game, 'barrels'): return if not self.goalId in range(len(self.game.barrels)): return if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime barrel = self.game.barrels[self.goalId] barrelPos = barrel.getPos() myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.notify.debug( 'thinkAboutGettingBarrel not doneAdjust setting position to %s' % myPos) self.suit.setPos(myPos) """ diffTime = globalClock.getFrameTime()- self.lastLocalTimeStampFromAI self.notify.debug('doing adjust, diffTime = %s' % diffTime) if diffTime < 0: # it just looks really weird when it moves backwards diffTime = 0 self.notify.debug('forcing diffTime to %s' % diffTime) """ self.doneAdjust = True displacement = barrelPos - myPos distanceToToon = displacement.length() #self.notify.debug('diffTime = %s' % diffTime) self.suit.headsUp(barrel) lengthTravelled = diffTime * self.cogSpeed #self.notify.debug('lengthTravelled = %s' % lengthTravelled) # don't overshoot our target if lengthTravelled > distanceToToon: lengthTravelled = distanceToToon #self.notify.debug('overshooting lengthTravelled = %s' % lengthTravelled) displacement.normalize() dirVector = displacement dirVector *= lengthTravelled newPos = myPos + dirVector # always keep them grounded newPos.setZ(0) self.suit.setPos(newPos) self.adjustPlayRate(newPos, myPos, diffTime) self.lastThinkTime = globalClock.getFrameTime() def stopWalking(self, timestamp): """Stop the cog from walking.""" localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) if localStamp > self.lastLocalTimeStampFromAI: self.suit.loop('neutral') self.clearGoal() def thinkAboutRunAway(self): """Go for a barrel.""" if not self.game: return if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() diffTime = globalClock.getFrameTime() - self.lastThinkTime returnPos = CTGG.CogReturnPositions[self.goalId] myPos = self.suit.getPos() if not self.doneAdjust: myPos = self.lastPosFromAI self.suit.setPos(myPos) """ diffTime = globalClock.getFrameTime()- self.lastLocalTimeStampFromAI self.notify.debug('run away doing adjust, diffTime = %s' % diffTime) if diffTime < 0: # it just looks really weird when it moves backwards diffTime = 0 self.notify.debug('forcing diffTime to %s' % diffTime) """ self.doneAdjust = True displacement = returnPos - myPos distanceToToon = displacement.length() #self.notify.debug('diffTime = %s' % diffTime) tempNp = render.attachNewNode('tempRet') tempNp.setPos(returnPos) self.suit.headsUp(tempNp) tempNp.removeNode() lengthTravelled = diffTime * self.cogSpeed #self.notify.debug('lengthTravelled = %s' % lengthTravelled) # don't overshoot our target if lengthTravelled > distanceToToon: lengthTravelled = distanceToToon #self.notify.debug('overshooting lengthTravelled = %s' % lengthTravelled) displacement.normalize() dirVector = displacement dirVector *= lengthTravelled newPos = myPos + dirVector # always keep them grounded newPos.setZ(0) self.suit.setPos(newPos) self.adjustPlayRate(newPos, myPos, diffTime) if (self.suit.getPos() - returnPos).length() < 0.0001: if not self.signalledAtReturnPos and self.barrel >= 0: # tell the AI we're at return Pos self.game.sendCogAtReturnPos(self.cogIndex, self.barrel) self.signalledAtReturnPos = True self.lastThinkTime = globalClock.getFrameTime() def makeCogCarryBarrel(self, timestamp, inResponseClientStamp, barrelModel, barrelIndex, cogPos): """Handle the AI telling us the barrel is attached to a cog.""" #assert self.notify.debugStateCall(self) if not self.game: return localTimeStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) # TODO validate time? self.lastLocalTimeStampFromAI = localTimeStamp inResponseGameTime = self.convertNetworkStampToGameTime( inResponseClientStamp) self.notify.debug('inResponseGameTime =%s timeSentToStart=%s' % (inResponseGameTime, self.netTimeSentToStartByHit)) if inResponseClientStamp < self.netTimeSentToStartByHit and \ self.goal == CTGG.NoGoal: self.notify.warning('ignoring makeCogCarrybarrel') else: barrelModel.setPos(0, -1.0, 1.5) barrelModel.reparentTo(self.suit) self.suit.setPos(cogPos) self.barrel = barrelIndex def makeCogDropBarrel(self, timestamp, inResponseClientStamp, barrelModel, barrelIndex, barrelPos): """Handle the AI telling us the barrel is attached to a cog.""" #assert self.notify.debugStateCall(self) localTimeStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) # TODO validate time? self.lastLocalTimeStampFromAI = localTimeStamp barrelModel.reparentTo(render) barrelModel.setPos(barrelPos) self.barrel = CTGG.NoBarrelCarried # #self.suit.setPos(cogPos) def respondToPieHit(self, timestamp): """The toon hit us, react appropriately.""" assert self.notify.debugStateCall(self) localStamp = globalClockDelta.networkToLocalTime(timestamp, bits=32) # argh using 1.0 sec as fudge #if localStamp > self.lastLocalTimeStampFromAI: if self.netTimeSentToStartByHit < timestamp: self.clearGoal() self.showSplat() # move him to his starting postion startPos = CTGG.CogStartingPositions[self.cogIndex] oldPos = self.suit.getPos() self.suit.setPos(startPos) 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 cleanup(self): """Do whatever is necessary to cleanup properly.""" self.clearGoal() self.ignoreAll() self.suit.delete() if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.suit = None self.game = None def adjustPlayRate(self, newPos, oldPos, diffTime): """Adjust animation rate based on how far he's moved.""" # lets slowdown playrate if they're not moving much lengthTravelled = (newPos - oldPos).length() if diffTime: speed = lengthTravelled / diffTime else: speed = self.cogSpeed rateMult = speed / self.cogSpeed newRate = rateMult * self.defaultPlayRate self.suit.setPlayRate(newRate, 'walk') def commonMove(self): """Move the cog thief. Common for all 3 behaviors """ if not self.lastThinkTime: self.lastThinkTime = globalClock.getFrameTime() dt = globalClock.getFrameTime() - self.lastThinkTime # Step 1: Update our position. # Update our position based on the velocity # vector we computed last time around. self.oldpos = self.suit.getPos() # save off our previous position pos = self.suit.getPos() pos += self.velocity * dt # apply velocities. self.suit.setPos(pos) # Step 2: SeeFriends. # Determine if we can see any of our flockmates. self.seeFriends() acc = Vec3(0, 0, 0) # well first off we want to move to our target self.accumulate(acc, self.getTargetVector()) # Step 3: Flocking behavior. # Do we see any of our flockmates? If yes, it's time to implement # the first Three Rules (they don't matter if we can't see anybody) if self.numFlockmatesSeen > 0: #if hasattr(base,'doDebug') and base.doDebug: # import pdb; pdb.set_trace() keepDistanceVector = self.keepDistance() oldAcc = Vec3(acc) self.accumulate(acc, keepDistanceVector) if self.cogIndex == 0: #self.notify.debug('oldAcc=%s, keepDist=%s newAcc=%s' % # (oldAcc,keepDistanceVector, acc)) pass # Step 8: Constrain acceleration # If our acceleration change is more than we allow, constrain it if (acc.length() > self.maxAcceleration): # definitely too much...constrain to maximum change acc.normalize() acc *= self.maxAcceleration # Step 9: Implementation. # Here's where we apply our newly computed acceleration vector # to create a new velocity vector to use next update cycle. self.oldVelocity = self.velocity # save off our previous velocity # now add in the acceleration self.velocity += acc # Step 10: constraint Y velocity changes. # Attempt to restrict flight straight up/down by damping out Y axis velocity. # This isn't strictly necessary, but does lead to more realistic looking flight. # Step 11: Constrain our speed. # If we're moving faster than we're allowed to move, constrain our velocity. if self.velocity.length() > self.maxVelocity: self.velocity.normalize() self.velocity *= self.maxVelocity # Step 12: Compute roll/pitch/yaw. # Compute our orientation after all this speed adjustment nonsense. # bah no need, we turn on a dime towards our velocity forwardVec = Vec3(1, 0, 0) heading = rad2Deg(math.atan2(self.velocity[1], self.velocity[0])) heading -= 90 self.suit.setH(heading) def getTargetVector(self): """Return a vector to my goal.""" targetPos = Point3(0, 0, 0) if self.goal == CTGG.ToonGoal: av = self.game.getAvatar(self.goalId) if av: targetPos = av.getPos() elif self.goal == CTGG.BarrelGoal: barrel = self.game.barrels[self.goalId] targetPos = barrel.getPos() elif self.goal == CTGG.RunAwayGoal: targetPos = CTGG.CogReturnPositions[self.goalId] targetPos.setZ(0) myPos = self.suit.getPos() diff = targetPos - myPos if diff.length() > 1.0: diff.normalize() diff *= 1.0 return diff def accumulate(self, accumulator, valueToAdd): """Return the magnitude of the accumulated vector.""" accumulator += valueToAdd return accumulator.length() def seeFriends(self): """Determines which flockmates a given flock boid can see.""" # clear the existing visibility list of any holdover from last round self.clearVisibleList() for cogIndex in list(self.game.cogInfo.keys()): if cogIndex == self.cogIndex: continue if self.sameGoal(cogIndex): dist = self.canISee(cogIndex) if dist != self.Infinity: self.addToVisibleList(cogIndex) if dist < self.distToNearestFlockmate: self.nearestFlockmate = cogIndex self.distToNearestFlockmate = dist return self.numFlockmatesSeen def clearVisibleList(self): """Clears the visibility list and associated fields.""" self.visibleFriendsList = [] self.numFlockmatesSeen = 0 self.nearestFlockmate = None self.distToNearestFlockmate = self.Infinity def addToVisibleList(self, cogIndex): """Add the cog to the visible list.""" # test: do we see enough buddies already? if self.numFlockmatesSeen < self.MaxFriendsVisible: #nope--we can add to this one to the list self.visibleFriendsList.append(cogIndex) self.numFlockmatesSeen += 1 if self.cogIndex == 0: #self.notify.debug('self.numFlockmatesSeen = %s' % self.numFlockmatesSeen) pass def canISee(self, cogIndex): """Return distance if I can see the other cog, infinity otherwise""" if self.cogIndex == cogIndex: # well we should never see ourself return self.Infinity cogThief = self.game.getCogThief(cogIndex) distance = self.suit.getDistance(cogThief.suit) if distance < self.perceptionRange: #self.notify.debug('%s can see %s' % (self.cogIndex, cogIndex)) return distance # fell through; can not see it return self.Infinity def sameGoal(self, cogIndex): """Return true if we have the same goal.""" cogThief = self.game.getCogThief(cogIndex) result = (cogThief.goalId == self.goalId) and (cogThief.goal == self.goal) return result def keepDistance(self): """Generates a vector for a flock boid to maintain his desired separation distance from the nearest flockmate he sees. """ ratio = self.distToNearestFlockmate / self.SeparationDistance nearestThief = self.game.getCogThief(self.nearestFlockmate) change = nearestThief.suit.getPos() - self.suit.getPos() if ratio < self.MinUrgency: ratio = self.MinUrgency if ratio > self.MaxUrgency: ratio = self.MaxUrgency # test: are we too close to our nearest flockmate? if self.distToNearestFlockmate < self.SeparationDistance: #self.notify.debug('%d is too close to %d' % (self.cogIndex, self.nearestFlockmate)) # too close...move away from our neighbor change.normalize() change *= -(1 - ratio ) # the close we are the more we are pushed away elif self.distToNearestFlockmate > self.SeparationDistance: # too far away move towards our neighbor change.normalize() change *= ratio else: # in the UNLIKELY event we're exactly the right distance away, do nothing change = Vec3(0, 0, 0) return change def showKaboom(self): """Show the kaboom graphic and sound.""" if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboom.reparentTo(render) self.kaboom.setPos(self.suit.getPos()) self.kaboom.setZ(3) self.kaboomTrack = Parallel( SoundInterval(self.kaboomSound, volume=0.5), Sequence( Func(self.kaboom.showThrough), LerpScaleInterval(self.kaboom, duration=0.5, scale=Point3(10, 10, 10), startScale=Point3(1, 1, 1), blendType='easeOut'), Func(self.kaboom.hide), )) self.kaboomTrack.start() def showSplat(self): """Show the splat graphic and sound.""" if self.kaboomTrack and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.splat.reparentTo(render) self.splat.setPos(self.suit.getPos()) self.splat.setZ(3) self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0), Sequence( Func(self.splat.showThrough), LerpScaleInterval(self.splat, duration=0.5, scale=1.75, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Func(self.splat.hide), )) self.kaboomTrack.start()
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": self.actor.pose("down", self.actor.getNumFrames("down") - 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 CogdoMazeWaterCooler(NodePath, DirectObject): UpdateTaskName = 'CogdoMazeWaterCooler_Update' def __init__(self, serialNum, model): NodePath.__init__(self, 'CogdoMazeWaterCooler-%i' % serialNum) self.serialNum = serialNum self._model = model self._model.reparentTo(self) self._model.setPosHpr(0, 0, 0, 0, 0, 0) self._initCollisions() self._initArrow() self._update = None self.__startUpdateTask() return def destroy(self): self.ignoreAll() self.__stopUpdateTask() self.collNodePath.removeNode() self.removeNode() def _initCollisions(self): offset = Globals.WaterCoolerTriggerOffset self.collSphere = CollisionSphere(offset[0], offset[1], offset[2], Globals.WaterCoolerTriggerRadius) self.collSphere.setTangible(0) name = Globals.WaterCoolerCollisionName self.collNode = CollisionNode(name) self.collNode.addSolid(self.collSphere) self.collNodePath = self.attachNewNode(self.collNode) def _initArrow(self): matchingGameGui = loader.loadModel('phase_3.5/models/gui/matching_game_gui') arrow = matchingGameGui.find('**/minnieArrow') arrow.setScale(Globals.CoolerArrowScale) arrow.setColor(*Globals.CoolerArrowColor) arrow.setPos(0, 0, Globals.CoolerArrowZ) arrow.setHpr(0, 0, 90) arrow.setBillboardAxis() self._arrow = NodePath('Arrow') arrow.reparentTo(self._arrow) self._arrow.reparentTo(self) self._arrowTime = 0 self.accept(Globals.WaterCoolerShowEventName, self.showArrow) self.accept(Globals.WaterCoolerHideEventName, self.hideArrow) matchingGameGui.removeNode() def showArrow(self): self._arrow.unstash() def hideArrow(self): self._arrow.stash() def update(self, dt): newZ = math.sin(globalClock.getFrameTime() * Globals.CoolerArrowSpeed) * Globals.CoolerArrowBounce self._arrow.setZ(newZ) def __startUpdateTask(self): self.__stopUpdateTask() self._update = taskMgr.add(self._updateTask, self.UpdateTaskName, 45) def __stopUpdateTask(self): if self._update is not None: taskMgr.remove(self._update) return def _updateTask(self, task): dt = globalClock.getDt() self.update(dt) return Task.cont
def loadLever(self): """ SubClasses can override this if they want to move their lever somewhere special... call this, then change the position. """ self.lever = self.root.attachNewNode('%sLever' % self.activityName) self.leverModel = self.party.defaultLeverModel.copyTo(self.lever) # Do some crazy reparenting so you can scale the whole thing nicely self.controlColumn = NodePath('cc') column = self.leverModel.find('**/column') column.getChildren().reparentTo(self.controlColumn) self.controlColumn.reparentTo(column) self.stickHinge = self.controlColumn.attachNewNode('stickHinge') self.stick = self.party.defaultStickModel.copyTo(self.stickHinge) self.stickHinge.setHpr(0.0, 90.0, 0.0) self.stick.setHpr(0, -90.0, 0) self.stick.flattenLight() self.bottom = self.leverModel.find('**/bottom') self.bottom.wrtReparentTo(self.controlColumn) self.bottomPos = self.bottom.getPos() # Make a trigger sphere so we can detect when the local avatar # runs up to the lever. cs = CollisionSphere(0.0, 1.35, 2.0, 1.0) cs.setTangible(False) cn = CollisionNode(self.leverTriggerEvent) cn.addSolid(cs) cn.setIntoCollideMask(OTPGlobals.WallBitmask) self.leverTrigger = self.root.attachNewNode(cn) self.leverTrigger.reparentTo(self.lever) self.leverTrigger.stash() # Also, a solid tube to keep us from running through the # lever itself. This one scales with the control # model. cs = CollisionTube(0.0, 2.7, 0.0, 0.0, 2.7, 3.0, 1.2) cn = CollisionNode('levertube') cn.addSolid(cs) cn.setIntoCollideMask(OTPGlobals.WallBitmask) self.leverTube = self.leverModel.attachNewNode(cn) # Let's set the height of the lever to the height of the host host = base.cr.doId2do.get(self.party.partyInfo.hostId) if host is None: self.notify.debug( "%s loadLever : Host has left the game before lever could be created." % self.activityName) return # We start by figuring out where we are going by setting the # scale and position appropriately # origScale = self.leverModel.getSz() # origCcPos = self.controlColumn.getPos() # origBottomPos = self.bottom.getPos() # origStickHingeHpr = self.stickHinge.getHpr() # First, scale the thing overall to match the host's scale, # including cheesy effect scales. scale = host.getGeomNode().getChild(0).getSz(render) self.leverModel.setScale(scale) # Then get the position of the host's right hand when he's # standing at the controls in a leverNeutral pose. self.controlColumn.setPos(0, 0, 0) host.setPosHpr(self.lever, 0, 0, 0, 0, 0, 0) host.pose('leverNeutral', 0) host.update() pos = host.rightHand.getPos(self.controlColumn) # Now set the control column to the right height and position # to put the top of the stick approximately in his hand. self.controlColumn.setPos(pos[0], pos[1], pos[2] - 1) # And put the bottom piece back on the floor, wherever that # is from here. self.bottom.setZ(host, 0.0) self.bottom.setPos(self.bottomPos[0], self.bottomPos[1], self.bottom.getZ()) # Also put the joystick in his hand. lookAtPoint = Point3(0.3, 0, 0.1) lookAtUp = Vec3(0, -1, 0) self.stickHinge.lookAt(host.rightHand, lookAtPoint, lookAtUp) host.play('walk') host.update()
def _initCollisions(self): collSphere = CollisionSphere(0, 0, 0, 3.0) collSphere.setTangible(0) self.collNode = CollisionNode(self.getName()) self.collNode.addSolid(collSphere) self.collNP = self.attachNewNode(self.collNode)
def __init__(self, model, pos, serialNum, gameId, penalty=False): # there are going to be MANY (~650) of these created and destroyed # all at once for 4-player games; make it lean self.serialNum = serialNum self.penalty = penalty # the fruit has a bit of height, lets recenter center = model.getBounds().getCenter() center = Point3(0, 0, 0) self.nodePath = model.copyTo(render) self.nodePath.setPos(pos[0] - center[0], pos[1] - center[1], pos[2] - center[2]) self.nodePath.setZ(0) # real assets have bottom at zero self.notify.debug('newPos = %s' % self.nodePath.getPos()) #self.nodePath.setScale(1.0) #if self.penalty: # self.nodePath.setColorScale(0.5,0.5,0.5,1.0) # Make a sphere, name it uniquely, and child it # to the nodepath. if self.penalty: self.sphereName = "penaltySphere-%s-%s" % (gameId, self.serialNum) else: self.sphereName = "treasureSphere-%s-%s" % (gameId, self.serialNum) self.collSphere = CollisionSphere(center[0], center[1], center[2], self.RADIUS) # Make the sphere intangible self.collSphere.setTangible(0) self.collNode = CollisionNode(self.sphereName) self.collNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = render.attachNewNode(self.collNode) self.collNodePath.setPos(pos[0] - center[0], pos[1] - center[1], pos[2] - center[2]) self.collNodePath.hide() self.track = None # Add a hook looking for collisions with localToon #self.accept('enter' + self.sphereName, self.__handleEnterSphere) # now that the treasure and sphere have been placed, flatten the # whole silly thing # self.nodePath.flattenLight() if self.penalty: #self.nodePath.setScale(1,1,0.5) self.tip = self.nodePath.find('**/fusetip') #self.tip.setX(2) #self.tip.setY(0.5) #self.tip.setZ(1.5) sparks = BattleParticles.createParticleEffect(file='icetnt') self.sparksEffect = sparks sparks.start(self.tip) self.penaltyGrabSound = loader.loadSfx( "phase_4/audio/sfx/MG_cannon_fire_alt.mp3") self.penaltyGrabSound.setVolume(0.75) kaboomAttachPoint = self.nodePath.attachNewNode('kaboomAttach') kaboomAttachPoint.setZ(3) self.kaboom = loader.loadModel( 'phase_4/models/minigames/ice_game_kaboom') self.kaboom.reparentTo(kaboomAttachPoint) #self.kaboom.hide() self.kaboom.setScale(2.0) self.kaboom.setBillboardPointEye()
class IceTreasure(DirectObject): """ Treasures toons can pickup swinging from ice to ice. Based on MazeTreasure """ notify = DirectNotifyGlobal.directNotify.newCategory("IceTreasure") RADIUS = 1.0 def __init__(self, model, pos, serialNum, gameId, penalty=False): # there are going to be MANY (~650) of these created and destroyed # all at once for 4-player games; make it lean self.serialNum = serialNum self.penalty = penalty # the fruit has a bit of height, lets recenter center = model.getBounds().getCenter() center = Point3(0, 0, 0) self.nodePath = model.copyTo(render) self.nodePath.setPos(pos[0] - center[0], pos[1] - center[1], pos[2] - center[2]) self.nodePath.setZ(0) # real assets have bottom at zero self.notify.debug('newPos = %s' % self.nodePath.getPos()) #self.nodePath.setScale(1.0) #if self.penalty: # self.nodePath.setColorScale(0.5,0.5,0.5,1.0) # Make a sphere, name it uniquely, and child it # to the nodepath. if self.penalty: self.sphereName = "penaltySphere-%s-%s" % (gameId, self.serialNum) else: self.sphereName = "treasureSphere-%s-%s" % (gameId, self.serialNum) self.collSphere = CollisionSphere(center[0], center[1], center[2], self.RADIUS) # Make the sphere intangible self.collSphere.setTangible(0) self.collNode = CollisionNode(self.sphereName) self.collNode.setIntoCollideMask(ToontownGlobals.PieBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = render.attachNewNode(self.collNode) self.collNodePath.setPos(pos[0] - center[0], pos[1] - center[1], pos[2] - center[2]) self.collNodePath.hide() self.track = None # Add a hook looking for collisions with localToon #self.accept('enter' + self.sphereName, self.__handleEnterSphere) # now that the treasure and sphere have been placed, flatten the # whole silly thing # self.nodePath.flattenLight() if self.penalty: #self.nodePath.setScale(1,1,0.5) self.tip = self.nodePath.find('**/fusetip') #self.tip.setX(2) #self.tip.setY(0.5) #self.tip.setZ(1.5) sparks = BattleParticles.createParticleEffect(file='icetnt') self.sparksEffect = sparks sparks.start(self.tip) self.penaltyGrabSound = loader.loadSfx( "phase_4/audio/sfx/MG_cannon_fire_alt.mp3") self.penaltyGrabSound.setVolume(0.75) kaboomAttachPoint = self.nodePath.attachNewNode('kaboomAttach') kaboomAttachPoint.setZ(3) self.kaboom = loader.loadModel( 'phase_4/models/minigames/ice_game_kaboom') self.kaboom.reparentTo(kaboomAttachPoint) #self.kaboom.hide() self.kaboom.setScale(2.0) self.kaboom.setBillboardPointEye() #self.kaboom.setBin('fixed', serialNum) #self.kaboom.setDepthTest(False) #self.kaboom.setDepthWrite(False) def destroy(self): self.ignoreAll() if self.penalty: self.sparksEffect.cleanup() if self.track: self.track.finish() self.nodePath.removeNode() del self.nodePath del self.collSphere self.collNodePath.removeNode() del self.collNodePath del self.collNode ## def __handleEnterSphere(self, collEntry): ## self.ignoreAll() ## # announce that this treasure was grabbed ## self.notify.debug('treasuerGrabbed') ## messenger.send("IceTreasureGrabbed", [self.serialNum]) def showGrab(self): self.nodePath.hide() self.collNodePath.hide() # disable collisions self.collNode.setIntoCollideMask(BitMask32(0)) if self.penalty: self.track = Parallel( SoundInterval(self.penaltyGrabSound), Sequence( Func(self.kaboom.showThrough), LerpScaleInterval(self.kaboom, duration=0.5, scale=Point3(10, 10, 10), blendType='easeOut'), Func(self.kaboom.hide), )) self.track.start()
class DistributedCogKart(DistributedElevatorExt.DistributedElevatorExt): notify = DirectNotifyGlobal.directNotify.newCategory("DistributedCogKart") JumpOutOffsets = ((6.5, -2, -0.025), (-6.5, -2, -0.025), (3.75, 5, -0.025), (-3.75, 5, -0.025)) def __init__(self, cr): """__init__(cr) """ DistributedElevatorExt.DistributedElevatorExt.__init__(self, cr) self.type = ElevatorConstants.ELEVATOR_COUNTRY_CLUB # note since we did elevator init last, self.fsm is DistributedElevator.fsm self.kartModelPath = 'phase_12/models/bossbotHQ/Coggolf_cart3.bam' self.leftDoor = None self.rightDoor = None self.fillSlotTrack = None 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. """ DistributedElevatorExt.DistributedElevatorExt.generate(self) # Get the state machine stuff for playGame self.loader = self.cr.playGame.hood.loader if(self.loader): self.notify.debug("Loader has been loaded") self.notify.debug(str(self.loader)) else: self.notify.debug("Loader has not been loaded") self.golfKart = render.attachNewNode('golfKartNode') self.kart = loader.loadModel(self.kartModelPath) self.kart.setPos(0, 0, 0) self.kart.setScale(1) self.kart.reparentTo(self.golfKart) self.golfKart.reparentTo(self.loader.geom) # Wheels self.wheels = self.kart.findAllMatches('**/wheelNode*') self.numWheels = self.wheels.getNumPaths() def announceGenerate(self): """Setup other fields dependent on the required fields.""" DistributedElevatorExt.DistributedElevatorExt.announceGenerate(self) angle = self.startingHpr[0] angle -= 90 radAngle = deg2Rad(angle) unitVec = Vec3( math.cos(radAngle), math.sin(radAngle), 0) unitVec *= 45.0 self.endPos = self.startingPos + unitVec self.endPos.setZ(0.5) dist = Vec3(self.endPos - self.enteringPos).length() wheelAngle = (dist / (4.8 * 1.4 * math.pi)) * 360 self.kartEnterAnimateInterval = Parallel( # start a lerp HPR for each wheel LerpHprInterval(self.wheels[0], 5.0, Vec3(self.wheels[0].getH(), wheelAngle, self.wheels[0].getR())), LerpHprInterval(self.wheels[1], 5.0, Vec3(self.wheels[1].getH(), wheelAngle, self.wheels[1].getR())), LerpHprInterval(self.wheels[2], 5.0, Vec3(self.wheels[2].getH(), wheelAngle, self.wheels[2].getR())), LerpHprInterval(self.wheels[3], 5.0, Vec3(self.wheels[3].getH(), wheelAngle, self.wheels[3].getR())), name = "CogKartAnimate") trolleyExitTrack1 = Parallel( LerpPosInterval(self.golfKart, 5.0, self.endPos), self.kartEnterAnimateInterval, name = "CogKartExitTrack") self.trolleyExitTrack = Sequence( trolleyExitTrack1, # Func(self.hideSittingToons), # we may not need this ) self.trolleyEnterTrack = Sequence( LerpPosInterval(self.golfKart, 5.0, self.startingPos, startPos = self.enteringPos)) self.closeDoors = Sequence( self.trolleyExitTrack, Func(self.onDoorCloseFinish)) self.openDoors = Sequence( self.trolleyEnterTrack ) def delete(self): """ This method is called when the DistributedObject is permanently removed from the world and deleted from the cache. """ DistributedElevatorExt.DistributedElevatorExt.delete(self) if hasattr(self, 'elevatorFSM') : del self.elevatorFSM def setBldgDoId(self, bldgDoId): """Handle the AI telling us the associated bldg doid.""" # The doId is junk, there is no building object for the factory # exterior elevators. Do the appropriate things that # DistributedElevator.gotBldg does. self.bldg = None self.setupElevatorKart() def setupElevatorKart(self): """Setup elevator related fields.""" # Establish a collision sphere. There must be an easier way! collisionRadius = ElevatorConstants.ElevatorData[self.type]['collRadius'] self.elevatorSphere = CollisionSphere(0, 0, 0, collisionRadius) self.elevatorSphere.setTangible(1) self.elevatorSphereNode = CollisionNode(self.uniqueName("elevatorSphere")) self.elevatorSphereNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.elevatorSphereNode.addSolid(self.elevatorSphere) self.elevatorSphereNodePath = self.getElevatorModel().attachNewNode( self.elevatorSphereNode) self.elevatorSphereNodePath.hide() self.elevatorSphereNodePath.reparentTo(self.getElevatorModel()) self.elevatorSphereNodePath.stash() self.boardedAvIds = {} self.finishSetup() def setColor(self, r, g, b): """Ignore this AI message to make it look cog grayish.""" pass def getElevatorModel(self): return self.golfKart def enterWaitEmpty(self, ts): """Handle entering the wait empty state.""" DistributedElevatorExt.DistributedElevatorExt.enterWaitEmpty(self, ts) def exitWaitEmpty(self): """Handle exiting the wait empty state.""" DistributedElevatorExt.DistributedElevatorExt.exitWaitEmpty(self) def forceDoorsOpen(self): """Deliberately do nothing.""" pass def forceDoorsClosed(self): """Deliberately do nothing.""" pass def setPosHpr(self, x, y, z, h, p ,r): """Set the pos hpr as dictated by the AI.""" self.startingPos = Vec3(x, y, z) self.enteringPos = Vec3(x, y, z - 10) self.startingHpr = Vec3(h, 0, 0) self.golfKart.setPosHpr( x, y, z, h, 0, 0 ) def enterClosing(self, ts): # Close the elevator doors if self.localToonOnBoard: elevator = self.getPlaceElevator() if elevator: elevator.fsm.request("elevatorClosing") self.closeDoors.start(ts) def enterClosed(self, ts): self.forceDoorsClosed() self.kartDoorsClosed(self.getZoneId()) return def kartDoorsClosed(self, zoneId): assert(self.notify.debug('doorsClosed()')) if (self.localToonOnBoard): hoodId = ZoneUtil.getHoodId(zoneId) doneStatus = { 'loader' : 'suitInterior', 'where' : 'suitInterior', 'hoodId' : hoodId, 'zoneId' : zoneId, 'shardId' : None, } elevator = self.elevatorFSM #self.getPlaceElevator() del self.elevatorFSM elevator.signalDone(doneStatus) def setCountryClubInteriorZone(self, zoneId): if (self.localToonOnBoard): hoodId = self.cr.playGame.hood.hoodId countryClubId = self.countryClubId if bboard.has('countryClubIdOverride'): countryClubId = bboard.get('countryClubIdOverride') doneStatus = { 'loader' : "cogHQLoader", 'where' : "countryClubInterior", 'how' : "teleportIn", 'zoneId' : zoneId, 'countryClubId' : self.countryClubId, 'hoodId' : hoodId, } self.cr.playGame.getPlace().elevator.signalDone(doneStatus) def setCountryClubInteriorZoneForce(self, zoneId): place = self.cr.playGame.getPlace() if place: place.fsm.request("elevator", [self, 1]) hoodId = self.cr.playGame.hood.hoodId countryClubId = self.countryClubId if bboard.has('countryClubIdOverride'): countryClubId = bboard.get('countryClubIdOverride') doneStatus = { 'loader' : "cogHQLoader", 'where' : "countryClubInterior", 'how' : "teleportIn", 'zoneId' : zoneId, 'countryClubId' : self.countryClubId, 'hoodId' : hoodId, } if hasattr(place, 'elevator') and place.elevator: place.elevator.signalDone(doneStatus) else: self.notify.warning("setMintInteriorZoneForce: Couldn't find playGame.getPlace().elevator, zoneId: %s" %zoneId) else: self.notify.warning("setCountryClubInteriorZoneForce: Couldn't find playGame.getPlace(), zoneId: %s" %zoneId) def setCountryClubId(self, countryClubId): self.countryClubId = countryClubId def getZoneId(self): return 0 def fillSlot(self, index, avId, wantBoardingShow = 0): """Put someone in the kart, as dictated by the AI.""" self.notify.debug("%s.fillSlot(%s, %s, ... %s)" % (self.doId, index, avId, globalClock.getRealTime())) request = self.toonRequests.get(index) if request: self.cr.relatedObjectMgr.abortRequest(request) del self.toonRequests[index] if avId == 0: # This means that the slot is now empty, and no action should # be taken. pass elif avId not in self.cr.doId2do: # It's someone who hasn't been generated yet. func = PythonUtil.Functor( self.gotToon, index, avId) assert index not in self.toonRequests self.toonRequests[index] = self.cr.relatedObjectMgr.requestObjects( [avId], allCallback = func) elif not self.isSetup: # We haven't set up the elevator yet. self.deferredSlots.append((index, avId, wantBoardingShow)) else: # If localToon is boarding, he needs to change state if avId == base.localAvatar.getDoId(): place = base.cr.playGame.getPlace() if not place: return elevator = self.getPlaceElevator() if elevator == None: place.fsm.request('elevator') elevator = self.getPlaceElevator() if not elevator: return self.localToonOnBoard = 1 if hasattr(localAvatar, "boardingParty") and localAvatar.boardingParty: localAvatar.boardingParty.forceCleanupInviteePanel() localAvatar.boardingParty.forceCleanupInviterPanels() # Cleanup any leftover elevator messages before boarding the elevator. if hasattr(base.localAvatar, "elevatorNotifier"): base.localAvatar.elevatorNotifier.cleanup() cameraTrack = Sequence() # Move the camera towards and face the elevator. cameraTrack.append(Func(elevator.fsm.request, "boarding", [self.getElevatorModel()])) # Enable the Hop off button. cameraTrack.append(Func(elevator.fsm.request, "boarded")) toon = self.cr.doId2do[avId] # Parent it to the elevator toon.stopSmooth() toon.wrtReparentTo(self.golfKart) sitStartDuration = toon.getDuration("sit-start") jumpTrack = self.generateToonJumpTrack(toon, index) track = Sequence( jumpTrack, Func(toon.setAnimState, "Sit", 1.0), Func(self.clearToonTrack, avId), name = toon.uniqueName("fillElevator"), autoPause = 1) if wantBoardingShow: boardingTrack, boardingTrackType = self.getBoardingTrack(toon, index, True) track = Sequence(boardingTrack, track) if avId == base.localAvatar.getDoId(): cameraWaitTime = 2.5 if (boardingTrackType == BoardingGroupShow.TRACK_TYPE_RUN): cameraWaitTime = 0.5 cameraTrack = Sequence(Wait(cameraWaitTime), cameraTrack) if self.canHideBoardingQuitBtn(avId): track = Sequence(Func(localAvatar.boardingParty.groupPanel.disableQuitButton), track) # Start the camera track in parallel here if avId == base.localAvatar.getDoId(): track = Parallel(cameraTrack, track) track.delayDelete = DelayDelete.DelayDelete(toon, 'CogKart.fillSlot') self.storeToonTrack(avId, track) track.start() self.fillSlotTrack = track assert avId not in self.boardedAvIds self.boardedAvIds[avId] = None def generateToonJumpTrack(self, av, seatIndex): """Return an interval of the toon jumping into the golf kart.""" av.pose('sit', 47) hipOffset = av.getHipsParts()[2].getPos(av) def getToonJumpTrack( av, seatIndex ): # using a local func allows the ProjectileInterval to # calculate this pos at run-time def getJumpDest(av = av, node = self.golfKart): dest = Point3(0,0,0) if hasattr(self, 'golfKart') and self.golfKart: dest = Vec3(self.golfKart.getPos(av.getParent())) seatNode = self.golfKart.find("**/seat" + str(seatIndex + 1)) dest += seatNode.getPos(self.golfKart) dna = av.getStyle() dest -= hipOffset if(seatIndex < 2): dest.setY( dest.getY() + 2 * hipOffset.getY()) dest.setZ(dest.getZ() + 0.1) else: self.notify.warning('getJumpDestinvalid golfKart, returning (0,0,0)') return dest def getJumpHpr(av = av, node = self.golfKart): hpr = Point3(0,0,0) if hasattr(self, 'golfKart') and self.golfKart: hpr = self.golfKart.getHpr(av.getParent()) if(seatIndex < 2): hpr.setX( hpr.getX() + 180) else: hpr.setX( hpr.getX() ) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) else: self.notify.warning('getJumpHpr invalid golfKart, returning (0,0,0)') return hpr toonJumpTrack = Parallel(ActorInterval( av, 'jump' ), Sequence(Wait( 0.43 ), Parallel(LerpHprInterval(av, hpr = getJumpHpr, duration = .9 ), ProjectileInterval(av, endPos = getJumpDest, duration = .9 ), ), ), ) return toonJumpTrack def getToonSitTrack( av ): toonSitTrack = Sequence( ActorInterval( av, 'sit-start' ), Func( av.loop, 'sit' ) ) return toonSitTrack toonJumpTrack = getToonJumpTrack( av, seatIndex ) toonSitTrack = getToonSitTrack( av ) jumpTrack = Sequence( Parallel( toonJumpTrack, Sequence( Wait(1), toonSitTrack, ), ), ## Func( av.wrtReparentTo, self.golfKart ), ) return jumpTrack def emptySlot(self, index, avId, bailFlag, timestamp, timeSent=0): """Remove someone as dictated by the AI.""" if self.fillSlotTrack: self.fillSlotTrack.finish() self.fillSlotTrack = None # If localToon is exiting, he needs to change state if avId == 0: # This means that no one is currently exiting, and no action # should be taken pass elif not self.isSetup: # We haven't set up the elevator yet. Remove the toon # from the deferredSlots list, if it is there. newSlots = [] for slot in self.deferredSlots: if slot[0] != index: newSlots.append(slot) self.deferredSlots = newSlots else: if avId in self.cr.doId2do: # See if we need to reset the clock # (countdown assumes we've created a clockNode already) if (bailFlag == 1 and hasattr(self, 'clockNode')): if (timestamp < self.countdownTime and timestamp >= 0): self.countdown(self.countdownTime - timestamp) else: self.countdown(self.countdownTime) # If the toon exists, look it up toon = self.cr.doId2do[avId] # avoid wrtReparent so that we don't muck with the toon's scale # Parent it to render #toon.wrtReparentTo(render) toon.stopSmooth() sitStartDuration = toon.getDuration("sit-start") jumpOutTrack = self.generateToonReverseJumpTrack(toon, index) # Place it on the appropriate spot relative to the # elevator track = Sequence( # TODO: Find the right coords for the elevator jumpOutTrack, # Tell the toon he is free to roam now Func(self.notifyToonOffElevator, toon), Func(self.clearToonTrack, avId), name = toon.uniqueName("emptyElevator"), autoPause = 1) if self.canHideBoardingQuitBtn(avId): # Enable the Boarding Group Panel Quit Button here if it is relevant. track.append(Func(localAvatar.boardingParty.groupPanel.enableQuitButton)) # Enable the Boarding Group GO Button here if it is relevant. track.append(Func(localAvatar.boardingParty.enableGoButton)) track.delayDelete = DelayDelete.DelayDelete(toon, 'CogKart.emptySlot') self.storeToonTrack(toon.doId, track) track.start() # Tell localToon he is exiting (if localToon is on board) if avId == base.localAvatar.getDoId(): messenger.send("exitElevator") # if the elevator is generated as a toon is leaving it, # we will not have gotten a corresponding 'fillSlot' message # for that toon, hence the toon will not be found in # boardedAvIds if avId in self.boardedAvIds: del self.boardedAvIds[avId] else: self.notify.warning("toon: " + str(avId) + " doesn't exist, and" + " cannot exit the elevator!") def generateToonReverseJumpTrack( self, av, seatIndex ): """Return an interval of the toon jumping out of the golf kart.""" self.notify.debug("av.getH() = %s" % av.getH()) def getToonJumpTrack( av, destNode ): # using a local func allows the ProjectileInterval to # calculate this pos at run-time def getJumpDest(av = av, node = destNode): dest = node.getPos(av.getParent()) dest += Vec3(*self.JumpOutOffsets[seatIndex]) return dest def getJumpHpr(av = av, node = destNode): hpr = node.getHpr(av.getParent()) hpr.setX( hpr.getX() + 180) angle = PythonUtil.fitDestAngle2Src(av.getH(), hpr.getX()) hpr.setX(angle) return hpr toonJumpTrack = Parallel( ActorInterval( av, 'jump' ), Sequence( Wait( 0.1), #43 ), Parallel( #LerpHprInterval( av, # hpr = getJumpHpr, # duration = .9 ), ProjectileInterval( av, endPos = getJumpDest, duration = .9 ) ) ) ) return toonJumpTrack toonJumpTrack = getToonJumpTrack( av, self.golfKart) jumpTrack = Sequence( toonJumpTrack, Func( av.loop, 'neutral' ), Func( av.wrtReparentTo, render ), #Func( self.av.setPosHpr, self.exitMovieNode, 0,0,0,0,0,0 ), ) return jumpTrack def startCountdownClock(self, countdownTime, ts): """Start the countdown clock.""" # just reverse the text counter DistributedElevatorExt.DistributedElevatorExt.startCountdownClock(self, countdownTime, ts) self.clock.setH(self.clock.getH() + 180) def rejectBoard(self, avId, reason = 0): """Show the reason why he was rejected.""" # Only difference from base clase is the use of KartMinLaff # This should only be sent to us if our localToon requested # permission to board the elevator. # reason 0: unknown, 1: shuffle, 2: too low laff, 3: no seat, 4: need promotion print(("rejectBoard %s" % (reason))) if hasattr(base.localAvatar, "elevatorNotifier"): if reason == ElevatorConstants.REJECT_SHUFFLE: base.localAvatar.elevatorNotifier.showMe(TTLocalizer.ElevatorHoppedOff) elif reason == ElevatorConstants.REJECT_MINLAFF: base.localAvatar.elevatorNotifier.showMe((TTLocalizer.KartMinLaff % (self.minLaff))) elif reason == ElevatorConstants.REJECT_PROMOTION: base.localAvatar.elevatorNotifier.showMe(TTLocalizer.BossElevatorRejectMessage) elif reason == ElevatorConstants.REJECT_NOT_YET_AVAILABLE: base.localAvatar.elevatorNotifier.showMe(TTLocalizer.NotYetAvailable) assert(base.localAvatar.getDoId() == avId) doneStatus = { 'where' : 'reject', } elevator = self.getPlaceElevator() if elevator: elevator.signalDone(doneStatus) def getDestName(self): if self.countryClubId == ToontownGlobals.BossbotCountryClubIntA: return TTLocalizer.ElevatorBossBotCourse0 elif self.countryClubId == ToontownGlobals.BossbotCountryClubIntB: return TTLocalizer.ElevatorBossBotCourse1 elif self.countryClubId == ToontownGlobals.BossbotCountryClubIntC: return TTLocalizer.ElevatorBossBotCourse2
class DistributedFireworksCannon(DistributedFireworkShow.DistributedFireworkShow): notify = directNotify.newCategory("DistributedFireworksCannon") def __init__(self, cr): DistributedFireworkShow.DistributedFireworkShow.__init__(self,cr) self.fireworksGui = None self.load() def generateInit(self): DistributedFireworkShow.DistributedFireworkShow.generateInit(self) """generateInit(self) This method is called when the DistributedObject is first introduced to the world... Not when it is pulled from the cache. """ self.fireworksSphereEvent = self.uniqueName("fireworksSphere") self.fireworksSphereEnterEvent = "enter" + self.fireworksSphereEvent self.fireworksGuiDoneEvent = "fireworksGuiDone" self.shootEvent = "fireworkShootEvent" self.collSphere = CollisionSphere(0, 0, 0, 2.5) # Make the sphere intangible self.collSphere.setTangible(1) self.collNode = CollisionNode(self.fireworksSphereEvent) self.collNode.setIntoCollideMask(ToontownGlobals.WallBitmask) self.collNode.addSolid(self.collSphere) self.collNodePath = self.geom.attachNewNode(self.collNode) 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. """ DistributedFireworkShow.DistributedFireworkShow.generate(self) def announceGenerate(self): self.notify.debug("announceGenerate") self.accept(self.fireworksSphereEnterEvent, self.__handleEnterSphere) def disable(self): self.notify.debug("disable") self.ignore(self.fireworksSphereEnterEvent) self.ignore(self.shootEvent) self.ignore(self.fireworksGuiDoneEvent) if self.fireworksGui: self.fireworksGui.destroy() self.fireworksGui = None DistributedFireworkShow.DistributedFireworkShow.disable(self) def delete(self): self.notify.debug("delete") self.geom.removeNode() DistributedFireworkShow.DistributedFireworkShow.delete(self) def load(self): self.geom = loader.loadModel("phase_5/models/props/trashcan_TT.bam") self.geom.reparentTo(base.cr.playGame.hood.loader.geom) self.geom.setScale(.5) def __handleEnterSphere(self, collEntry): self.notify.debug("handleEnterSphere()") # don't let other toons access the fireworks now self.ignore(self.fireworksSphereEnterEvent) self.sendUpdate("avatarEnter", []) def __handleFireworksDone(self): self.ignore(self.fireworksGuiDoneEvent) self.ignore(self.shootEvent) self.sendUpdate("avatarExit") self.fireworksGui.destroy() self.fireworksGui = None def freeAvatar(self): """ This is a message from the AI used to free the avatar from movie mode """ # If we are the local toon and we have simply taken too long, # just free us base.localAvatar.posCamera(0,0) base.cr.playGame.getPlace().setState("walk") # Start accepting the fireworks collision sphere event again self.accept(self.fireworksSphereEnterEvent, self.__handleEnterSphere) def setMovie(self, mode, avId, timestamp): """ This is a message from the AI describing a movie between this fireworks cannon and a Toon that has approached us. """ timeStamp = globalClockDelta.localElapsedTime(timestamp) # See if this is the local toon isLocalToon = (avId == base.localAvatar.doId) if (mode == FIREWORKS_MOVIE_CLEAR): self.notify.debug("setMovie: clear") return elif (mode == FIREWORKS_MOVIE_GUI): self.notify.debug("setMovie: gui") if isLocalToon: self.fireworksGui = FireworksGui.FireworksGui(self.fireworksGuiDoneEvent, self.shootEvent) self.accept(self.fireworksGuiDoneEvent, self.__handleFireworksDone) self.accept(self.shootEvent, self.localShootFirework) return else: self.notify.warning("unknown mode in setMovie: %s" % (mode)) def setPosition(self, x, y, z): self.pos = [x,y,z] self.geom.setPos(x,y,z) def localShootFirework(self, index): style = index col1,col2 = self.fireworksGui.getCurColor() amp = 30 # attach a dummy node to the toon that always in front of him. # This is where the fireworks will shoot from. dummy = base.localAvatar.attachNewNode("dummy") dummy.setPos(0,100,60) pos = dummy.getPos(render) dummy.removeNode() print(("lauFirework: %s, col=%s" % (index,col1))) self.d_requestFirework(pos[0],pos[1],pos[2],style,col1,col2)