示例#1
0
 def delete(self):
     try:
         self.Avatar_deleted
     except:
         self.Avatar_deleted = 1
         self.removeLoopTask()
         Actor.delete(self)
示例#2
0
class HealthGoblet():

    healthGivenFactor = 8
    minHealthGiven = 5

    def __init__(self, mainRef, enemyRef):
        print 'HealthGoblet instantiated'
        self._enemyRef = enemyRef
        self._playerRef = mainRef.player

        self.healthGobletNode = mainRef.mainNode.attachNewNode(
            'healthGobletNode')

        self.initAttributes()
        self.initModel()

        taskMgr.doMethodLater(1.5, self.updateHealthGoblet,
                              'updateHealthGobletTask')

    def initAttributes(self):
        self.healthGiven = utils.getDXY(
            self.minHealthGiven, self._enemyRef.level * self.healthGivenFactor)
        self.perceptionRange = 0.5

        self.healthGobletNode.setPos(self._enemyRef.enemyNode.getPos())

    def initModel(self):
        self.healthGobletModel = Actor('models/HealthGoblet',
                                       {'float': 'models/HealthGoblet-anim'})
        self.healthGobletModel.reparentTo(self.healthGobletNode)

        self.healthGobletModel.setCollideMask(BitMask32.allOff())
        self.healthGobletModel.setScale(0.5)

        self.healthGobletModel.loop('float')

    def updateHealthGoblet(self, task):
        playerNode = self._playerRef.playerNode
        if utils.getIsInRange(playerNode.getPos(),
                              self.healthGobletNode.getPos(),
                              self.perceptionRange):
            print 'healed player for:', self.healthGiven
            self._playerRef.heal(self.healthGiven)

            self.healthGobletModel.stop()

            self.suicide()
            return task.done

        return task.again

    def suicide(self):
        # Cleanup the healthGobletModel
        self.healthGobletModel.cleanup()
        self.healthGobletModel.delete()

        self.healthGobletNode.removeNode()

        self._enemyRef = None
        self._playerRef = None
示例#3
0
 def delete(self):
     try:
         self.DistributedActor_deleted
     except:
         self.DistributedActor_deleted = 1
         DistributedSmoothNode.delete(self)
         Actor.delete(self)
示例#4
0
文件: Avatar.py 项目: coginvasion/src
 def delete(self):
     try:
         self.Avatar_deleted
     except:
         self.Avatar_deleted = 1
         self.removeLoopTask()
         Actor.delete(self)
示例#5
0
class FieldActor(FSM):
    def __init__(self, name, indexNumber, modelName, stage, actorsList, hero):
        self.indexNumber = indexNumber
        self.modelName = modelName
        self.stage = stage
        self.name = name
        self.actorsList = actorsList
        self.hero = hero
        FSM.__init__(
            self, "FSM-FieldActor-{}_{}".format(self.name, self.indexNumber))
        self.initActor()

    def initActor(self):
        faEmpty = self.stage.find("**/{}_{}".format(self.name,
                                                    self.indexNumber))
        faPos = faEmpty.getPos()
        self.actor = Actor(
            "{}".format(self.modelName), {
                "idle": "{}-idle".format(self.modelName),
                "walk": "{}-walk".format(self.modelName)
            })
        self.actor.reparentTo(self.stage)
        self.actor.setPos(faPos)

        cNode = CollisionNode("{}_{}".format(self.name, self.indexNumber))
        cNode.addSolid(CollisionBox(0, 1.5, 1.5, 1))
        faCollision = self.actor.attachNewNode(cNode)
        #####################################################
        # faCollision.show()
        #####################################################
        base.pusher.addCollider(faCollision, self.actor, base.drive.node())
        base.cTrav.addCollider(faCollision, base.pusher)
        self.actorsList.append(self)

        AIchar = AICharacter("{}_{}".format(self.name, self.indexNumber),
                             self.actor, 100, 0.05, 5)
        base.AIworld.addAiChar(AIchar)
        self.AIbehaviors = AIchar.getAiBehaviors()

    # FSM ##################################################################
    def enterIdle(self):
        self.actor.loop('idle')

    def enterWander(self):
        self.actor.loop('walk')
        self.AIbehaviors.wander(5, 0, 10, 1.0)

    def enterPursue(self):
        self.actor.loop('walk')
        self.AIbehaviors.pursue(self.hero)

    def enterHide(self):
        self.actor.hide()

    def enterShow(self):
        self.actor.show()

    def enterDeleteActor(self):
        self.actor.delete()
示例#6
0
 def delete(self):
     try:
         self.Avatar_deleted
     except:
         Actor.cleanup(self)
         self.Avatar_deleted = 1
         del self.__font
         del self.style
         Actor.delete(self)
示例#7
0
class MachineGun:
    def __init__(self, cycle, mount):
        self.cycle = cycle

        self.actor = Actor("../Models/MGActor.egg")
        self.model = loader.loadModel("../Models/MachineGun.bam")
        self.actor.reparentTo(mount)
        self.model.reparentTo(self.actor)
        self.flashModel = loader.loadModel("../Models/LaserFlash.bam")
        self.projModel = loader.loadModel("../Models/LaserProj.bam")
        self.projModel.setScale(.25, 1, .25)

        self.refNP = self.cycle.trgtrMount.attachNewNode("MGRefNP")

        self.muzzle = self.actor.exposeJoint(None, "modelRoot", "Muzzle")

        reloadTime = .25

        self.flashLerp = LerpScaleInterval(self.flashModel, reloadTime * .75,
                                           Point3(1, 1, 1), Point3(.1, .1, .1))

        self.firePar = Parallel(Func(self.setEffects), self.flashLerp)

        self.fireSeq = Sequence(self.firePar, Func(self.clearEffects),
                                Wait(reloadTime * .25))

    def fire(self):
        if (self.fireSeq.isPlaying() == False):
            self.refNP.setPos(0, 15, 0)
            self.fireSeq.start()
        return

    def setEffects(self):
        self.flashModel.reparentTo(self.muzzle)
        self.projModel.reparentTo(self.muzzle)
        self.projModel.lookAt(self.refNP.getPos(self.muzzle))
        self.projModel.setSy(
            trueDist(Point3(0, 0, 0), self.refNP.getPos(self.muzzle)) * 2)
        return

    def clearEffects(self):
        self.flashModel.detachNode()
        self.projModel.detachNode()
        return

    def destroy(self):
        self.actor.delete()
        self.model.removeNode()
        self.flashModel.removeNode()
        self.projModel.removeNode()
        self.refNP.removeNode()
        self.cycle = None
        self.flashLerp = None
        self.firePar = None
        self.fireSeq = None
        return
示例#8
0
class HealthGoblet():

    healthGivenFactor = 8
    minHealthGiven = 5

    def __init__(self, mainRef, enemyRef):
        print 'HealthGoblet instantiated'
        self._enemyRef = enemyRef
        self._playerRef = mainRef.player

        self.healthGobletNode = mainRef.mainNode.attachNewNode('healthGobletNode')

        self.initAttributes()
        self.initModel()

        taskMgr.doMethodLater(1.5, self.updateHealthGoblet, 'updateHealthGobletTask')


    def initAttributes(self):
        self.healthGiven = utils.getDXY(self.minHealthGiven, self._enemyRef.level * self.healthGivenFactor)
        self.perceptionRange = 0.5

        self.healthGobletNode.setPos(self._enemyRef.enemyNode.getPos())

    def initModel(self):
        self.healthGobletModel = Actor('models/HealthGoblet',
                                    {'float':'models/HealthGoblet-anim'})
        self.healthGobletModel.reparentTo(self.healthGobletNode)

        self.healthGobletModel.setCollideMask(BitMask32.allOff())
        self.healthGobletModel.setScale(0.5)

        self.healthGobletModel.loop('float')

    def updateHealthGoblet(self, task):
        playerNode = self._playerRef.playerNode
        if utils.getIsInRange(playerNode.getPos(), self.healthGobletNode.getPos(), self.perceptionRange):
            print 'healed player for:', self.healthGiven
            self._playerRef.heal(self.healthGiven)

            self.healthGobletModel.stop()

            self.suicide()
            return task.done

        return task.again

    def suicide(self):
        # Cleanup the healthGobletModel
        self.healthGobletModel.cleanup()
        self.healthGobletModel.delete()

        self.healthGobletNode.removeNode()

        self._enemyRef = None
        self._playerRef = None
示例#9
0
 def delete(self):
     try:
         self.Avatar_deleted
     except:
         Actor.cleanup(self)
         self.Avatar_deleted = 1
         self.style = None
         self.collTube = None
         self.hpText = None
         self.hpTextGenerator = None
         ShadowCaster.delete(self)
         Actor.delete(self)
示例#10
0
 def delete(self):
     try:
         self.Avatar_deleted
     except:
         self.deleteNametag3d()
         Actor.cleanup(self)
         self.Avatar_deleted = 1
         del self.__font
         del self.style
         del self.soundChatBubble
         self.nametag.destroy()
         del self.nametag
         self.nametag3d.removeNode()
         ShadowCaster.delete(self)
         Actor.delete(self)
示例#11
0
 def delete(self):
     try:
         self.Avatar_deleted
     except:
         self.deleteNametag3d()
         Actor.cleanup(self)
         if self.ManagesNametagAmbientLightChanged:
             self.ignoreNametagAmbientLightChange()
         self.Avatar_deleted = 1
         del self.__font
         del self.style
         del self.soundChatBubble
         del self.nametag
         self.nametag3d.removeNode()
         ShadowCaster.delete(self)
         Actor.delete(self)
示例#12
0
 def delete(self):
     try:
         self.Avatar_deleted
     except:
         self.deleteNametag3d()
         Actor.cleanup(self)
         if self.ManagesNametagAmbientLightChanged:
             self.ignoreNametagAmbientLightChange()
         self.Avatar_deleted = 1
         del self.__font
         del self.style
         del self.soundChatBubble
         del self.nametag
         self.nametag3d.removeNode()
         ShadowCaster.delete(self)
         Actor.delete(self)
示例#13
0
class SpellInst():
	def __init__(self,spell,caster,pos,rot,worldNP,bullet):
		self.spell=spell
		self.caster=caster
		# Load spell model
		self.model=Actor(spell.model)
		
		shape=BulletSphereShape(0.666)
		self.collNP=worldNP.attachNewNode(BulletGhostNode('SpellSphere'))
		self.collNP.setCollideMask(BitMask32.allOn())
		self.collNP.node().addShape(shape)
		self.collNP.setPos(pos+move_forwards(rot,1.0))
		self.collNP.setHpr(Vec3(rot,0,0))
		bullet.attachGhost(self.collNP.node())
		self.collNP.reparentTo(worldNP)
		
		self.bullet=bullet
		
		# Reparent the model to render.
		self.model.reparentTo(self.collNP)
		
		self.distance=0
		
		self.remove_me=False
	
	def __del__(self):
		self.bullet.removeGhost(self.collNP.node())
		self.collNP.removeNode()
		self.model.delete()
	
	def update(self,dt,bulletworld):
		retval=''
		if self.collNP.node().getNumOverlappingNodes()>0:
			for node in self.collNP.node().getOverlappingNodes():
				if node.getName()==self.caster:
					retval='hit owner'
				else:
					retval=node.getName()
		vel=move_forwards(self.collNP.getH(),self.spell.speed)
		self.collNP.setPos(self.collNP.getPos()+vel*dt)
		self.distance+=vel.length()*dt
		if self.distance>self.spell.range:
			retval='over range'
		return retval
示例#14
0
    def delete(self):
        try:
            self.Avatar_deleted
            return
        except:
            self.Avatar_deleted = 1

        self.setBlend(frameBlend=False)
        self.deleteNametag3d()
        Actor.cleanup(self)
        if self.ManagesNametagAmbientLightChanged:
            self.ignoreNametagAmbientLightChange()
        del self.__font
        del self.style
        del self.soundChatBubble
        self.nametag.destroy()
        del self.nametag
        self.nametag3d.removeNode()
        ShadowCaster.delete(self)
        Actor.delete(self)
示例#15
0
文件: persona.py 项目: fnadalt/mundo
class Persona(DirectObject):
    def __init__(self, contexto, _input):
        # referencias
        self.contexto = contexto
        self.input = _input
        self.topografia = None
        # componentes
        self.actor = None

    def iniciar(self):
        log.info("iniciar")
        b = self.contexto.base
        # referencias
        self.topografia = self.contexto.obtener_proveedor(Topografia.Nombre)
        # actor
        self.actor = Actor("modelos/hombre/male.egg")
        self.actor.reparentTo(b.render)
        # tasks
        self.contexto.base.taskMgr.add(self._update, "Persona_update")
        #
        return True

    def terminar(self):
        log.info("terminar")
        # tasks
        self.contexto.base.taskMgr.remove("Persona_update")
        # referencias
        self.input = None
        self.topografia = None
        # actor
        if self.actor:
            self.actor.delete()
            self.actor = None

    def _update(self, task):
        pos2d = Vec2(self.actor.getX(), self.actor.getY())
        self.actor.setZ(self.topografia.obtener_altitud(pos2d))
        return task.cont
class DistributedPartyFireworksActivity(DistributedPartyActivity, FireworkShowMixin):
    notify = directNotify.newCategory('DistributedPartyFireworksActivity')

    def __init__(self, cr):
        DistributedPartyFireworksActivity.notify.debug('__init__')
        DistributedPartyActivity.__init__(self, cr, ActivityIds.PartyFireworks, ActivityTypes.HostInitiated, wantLever=True)
        FireworkShowMixin.__init__(self, restorePlaygroundMusic=True, startDelay=FireworksPostLaunchDelay)

    def setEventId(self, eventId):
        DistributedPartyFireworksActivity.notify.debug('setEventId( %s )' % FireworkShows.getString(eventId))
        self.eventId = eventId

    def setShowStyle(self, showStyle):
        DistributedPartyFireworksActivity.notify.debug('setShowStyle( %d )' % showStyle)
        self.showStyle = showStyle
    
    def setSongId(self, songId):
        self.songId = songId

    def load(self):
        DistributedPartyFireworksActivity.notify.debug('load')
        DistributedPartyActivity.load(self)
        self.eventId = PartyGlobals.FireworkShows.Summer
        self.launchPadModel = loader.loadModel('phase_13/models/parties/launchPad')
        self.launchPadModel.setH(90.0)
        self.launchPadModel.setPos(0.0, -18.0, 0.0)
        self.launchPadModel.reparentTo(self.root)
        railingsCollection = self.launchPadModel.findAllMatches('**/launchPad_mesh/*railing*')
        for i in xrange(railingsCollection.getNumPaths()):
            railingsCollection[i].setAttrib(AlphaTestAttrib.make(RenderAttrib.MGreater, 0.75))

        leverLocator = self.launchPadModel.find('**/RocketLever_locator')
        self.lever.setPosHpr(Vec3.zero(), Vec3.zero())
        self.lever.reparentTo(leverLocator)
        self.toonPullingLeverInterval = None
        self.sign.reparentTo(self.launchPadModel.find('**/launchPad_sign_locator'))
        self.rocketActor = Actor('phase_13/models/parties/rocket_model', {'launch': 'phase_13/models/parties/rocket_launch'})
        rocketLocator = self.launchPadModel.find('**/rocket_locator')
        self.rocketActor.reparentTo(rocketLocator)
        self.rocketActor.node().setBound(OmniBoundingVolume())
        self.rocketActor.node().setFinal(True)
        effectsLocator = self.rocketActor.find('**/joint1')
        self.rocketExplosionEffect = RocketExplosion(effectsLocator, rocketLocator)
        self.rocketParticleSeq = None
        self.launchSound = base.loadSfx('phase_13/audio/sfx/rocket_launch.ogg')
        self.activityFSM = FireworksActivityFSM(self)
        self.activityFSM.request('Idle')
        return

    def unload(self):
        DistributedPartyFireworksActivity.notify.debug('unload')
        taskMgr.remove(self.taskName('delayedStartShow'))
        if self.rocketParticleSeq:
            self.rocketParticleSeq.pause()
            self.rocketParticleSeq = None
        self.launchPadModel.removeNode()
        del self.launchPadModel
        del self.toonPullingLeverInterval
        self.rocketActor.delete()
        self.rocketExplosionEffect.destroy()
        self.activityFSM.request('Disabled')
        del self.rocketActor
        del self.launchSound
        del self.activityFSM
        del self.eventId
        del self.showStyle
        DistributedPartyActivity.unload(self)
        return

    def _leverPulled(self, collEntry):
        DistributedPartyFireworksActivity.notify.debug('_leverPulled')
        hostPulledLever = DistributedPartyActivity._leverPulled(self, collEntry)
        if self.activityFSM.getCurrentOrNextState() == 'Active':
            self.showMessage(TTLocalizer.PartyFireworksAlreadyActive)
        elif self.activityFSM.getCurrentOrNextState() == 'Disabled':
            self.showMessage(TTLocalizer.PartyFireworksAlreadyDone)
        elif self.activityFSM.getCurrentOrNextState() == 'Idle':
            if hostPulledLever:
                base.cr.playGame.getPlace().fsm.request('activity')
                self.toonPullingLeverInterval = self.getToonPullingLeverInterval(base.localAvatar)
                self.toonPullingLeverInterval.append(Func(self.d_toonJoinRequest))
                self.toonPullingLeverInterval.append(Func(base.cr.playGame.getPlace().fsm.request, 'walk'))
                self.toonPullingLeverInterval.start()
            else:
                self.showMessage(TTLocalizer.PartyOnlyHostLeverPull)

    def setState(self, newState, timestamp):
        DistributedPartyFireworksActivity.notify.debug('setState( newState=%s, ... )' % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        if newState == 'Active':
            self.activityFSM.request(newState, timestamp)
        else:
            self.activityFSM.request(newState)

    def startIdle(self):
        DistributedPartyFireworksActivity.notify.debug('startIdle')

    def finishIdle(self):
        DistributedPartyFireworksActivity.notify.debug('finishIdle')

    def startActive(self, showStartTimestamp):
        DistributedPartyFireworksActivity.notify.debug('startActive')
        messenger.send(FireworksStartedEvent)
        timeSinceStart = globalClockDelta.localElapsedTime(showStartTimestamp)
        if timeSinceStart > self.rocketActor.getDuration('launch'):
            self.rocketActor.hide()
            if timeSinceStart < 60:
                self.startShow(self.eventId, self.showStyle, self.songId, showStartTimestamp)
        else:
            self.rocketActor.play('launch')
            self.rocketParticleSeq = Sequence(Wait(RocketSoundDelay), Func(base.playSfx, self.launchSound), Func(self.rocketExplosionEffect.start), Wait(RocketDirectionDelay), LerpHprInterval(self.rocketActor, 4.0, Vec3(0, 0, -60)), Func(self.rocketExplosionEffect.end), Func(self.rocketActor.hide))
            self.rocketParticleSeq.start()
            taskMgr.doMethodLater(FireworksPostLaunchDelay, self.startShow, self.taskName('delayedStartShow'), extraArgs=[self.eventId,
             self.showStyle,
             self.songId,
             showStartTimestamp,
             self.root])

    def finishActive(self):
        self.rocketParticleSeq = None
        DistributedPartyFireworksActivity.notify.debug('finishActive')
        messenger.send(FireworksFinishedEvent)
        taskMgr.remove(self.taskName('delayedStartShow'))
        FireworkShowMixin.disable(self)
        return

    def startDisabled(self):
        DistributedPartyFireworksActivity.notify.debug('startDisabled')
        if not self.rocketActor.isEmpty():
            self.rocketActor.hide()

    def finishDisabled(self):
        DistributedPartyFireworksActivity.notify.debug('finishDisabled')

    def handleToonDisabled(self, toonId):
        self.notify.warning('handleToonDisabled no implementation yet')
class DistributedPartyJukeboxActivityBase(DistributedPartyActivity):
    notify = directNotify.newCategory("DistributedPartyJukeboxActivityBase")

    def __init__(self, cr, actId, phaseToMusicData):
        DistributedPartyActivity.__init__(self, cr, actId,
                                          ActivityTypes.Continuous)
        self.phaseToMusicData = phaseToMusicData
        self.jukebox = None
        self.gui = None

        self.tunes = []
        self.music = None
        # Data is tuple (phase, filename)
        self.currentSongData = None

        self.localQueuedSongInfo = None
        self.localQueuedSongListItem = None

    def generateInit(self):
        self.gui = JukeboxGui(self.phaseToMusicData)

    def load(self):
        DistributedPartyActivity.load(self)

        # Load Jukebox actor
        self.jukebox = Actor(
            "phase_13/models/parties/jukebox_model",
            {"dance": "phase_13/models/parties/jukebox_dance"})
        self.jukebox.reparentTo(self.root)

        # Create collision area for jukebox
        self.collNode = CollisionNode(self.getCollisionName())
        self.collNode.setCollideMask(ToontownGlobals.CameraBitmask
                                     | ToontownGlobals.WallBitmask)

        collTube = CollisionTube(0, 0, 0, 0.0, 0.0, 4.25, 2.25)
        collTube.setTangible(1)
        self.collNode.addSolid(collTube)
        self.collNodePath = self.jukebox.attachNewNode(self.collNode)

        self.sign.setPos(-5.0, 0, 0)

        self.activate()

    def unload(self):
        DistributedPartyActivity.unload(self)

        self.gui.unload()

        if self.music is not None:
            self.music.stop()

        self.jukebox.stop()
        self.jukebox.delete()
        self.jukebox = None

        self.ignoreAll()

    def getCollisionName(self):
        return self.uniqueName("jukeboxCollision")

    def activate(self):
        self.accept("enter" + self.getCollisionName(),
                    self.__handleEnterCollision)

#===============================================================================
# Enter/Exit Jukebox
#===============================================================================

    def __handleEnterCollision(self, collisionEntry):
        if base.cr.playGame.getPlace().fsm.getCurrentState().getName(
        ) == "walk":
            base.cr.playGame.getPlace().fsm.request("activity")
            self.d_toonJoinRequest()

    def joinRequestDenied(self, reason):
        DistributedPartyActivity.joinRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyJukeboxOccupied)

    # Distributed (broadcast ram)
    def handleToonJoined(self, toonId):
        """
        Toon requested to use the jukebox and the request has been granted.
        """
        toon = base.cr.doId2do.get(toonId)
        if toon:
            self.jukebox.lookAt(base.cr.doId2do[toonId])
            self.jukebox.setHpr(self.jukebox.getH() + 180.0, 0, 0)

        if toonId == base.localAvatar.doId:
            self.__localUseJukebox()

    def handleToonExited(self, toonId):
        """
        Typically called when toon times out.
        """
        if toonId == base.localAvatar.doId and self.gui.isLoaded():
            self.__deactivateGui()

    def handleToonDisabled(self, toonId):
        """
        A toon dropped unexpectedly from the game. Handle it!
        """
        self.notify.warning("handleToonDisabled no implementation yet")

    def __localUseJukebox(self):
        """
        Sets the local toon to use the jukebox, including activating the GUI and
        changing the client into the appropriate state.
        """
        base.localAvatar.disableAvatarControls()
        base.localAvatar.stopPosHprBroadcast()

        self.__activateGui()

        self.accept(JukeboxGui.CLOSE_EVENT, self.__handleGuiClose)

        # We are locking exiting now in case the AI times the toon out of the Jukebox.
        taskMgr.doMethodLater(0.5,
                              self.__localToonWillExitTask,
                              self.uniqueName("toonWillExitJukeboxOnTimeout"),
                              extraArgs=None)

        self.accept(JukeboxGui.ADD_SONG_CLICK_EVENT, self.__handleQueueSong)
        if self.isUserHost():
            self.accept(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT,
                        self.__handleMoveSongToTop)

    def __localToonWillExitTask(self, task):
        self.localToonExiting()
        return Task.done

    def __activateGui(self):
        self.gui.enable(timer=JUKEBOX_TIMEOUT)
        self.gui.disableAddSongButton()
        if self.currentSongData is not None:
            self.gui.setSongCurrentlyPlaying(self.currentSongData[0],
                                             self.currentSongData[1])
        self.d_queuedSongsRequest()

    def __deactivateGui(self):
        self.ignore(JukeboxGui.CLOSE_EVENT)
        self.ignore(JukeboxGui.SONG_SELECT_EVENT)
        self.ignore(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT)

        base.cr.playGame.getPlace().setState("walk")
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.enableAvatarControls()

        self.gui.unload()
        self.__localClearQueuedSong()

    def isUserHost(self):
        """
        Checks if the localAvatar is the host of the party
        Returns
            true if localAvatar is the host of the party
        """
        return (self.party.partyInfo.hostId == base.localAvatar.doId)

    # Distributed (clsend airecv)
    def d_queuedSongsRequest(self):
        self.sendUpdate("queuedSongsRequest")

    # Distributed (only sender receives this response)
    def queuedSongsResponse(self, songInfoList, index):
        """
        Gets a list of songs and adds them to the queue.
        Called when the toon first interacts with the jukebox.
        
        Parameters:
            songInfoList is the list of songs
            index is the item # on the list for a song previously queued by the player.
        """
        if self.gui.isLoaded():
            for i in range(len(songInfoList)):
                songInfo = songInfoList[i]

                self.__addSongToQueue(songInfo,
                                      isLocalQueue=(index >= 0 and i == index))

            self.gui.enableAddSongButton()

    def __handleGuiClose(self):
        """
        Closes Jukebox GUI, cleans up event handlers, and sets client state to normal.
        Typically triggered when the player clicks the close
        button in the jukebox, which fires CLOSE_EVENT.
        """
        self.__deactivateGui()
        self.d_toonExitDemand()

#===============================================================================
# Queueing songs
#===============================================================================

    def __handleQueueSong(self, name, values):
        """
        Requests to queue a song.
        Triggered when the localAvatar clicks the "Add/Replace Song button".
        """
        self.d_setNextSong(values[0], values[1])

    # Distributed (clsend airecv)
    def d_setNextSong(self, phase, filename):
        self.sendUpdate("setNextSong", [(phase, filename)])

    # Distributed (sender only gets it back)
    def setSongInQueue(self, songInfo):
        if self.gui.isLoaded():
            phase = sanitizePhase(songInfo[0])
            filename = songInfo[1]
            data = self.getMusicData(phase, filename)

            if data:
                if self.localQueuedSongListItem is not None:
                    self.localQueuedSongListItem["text"] = data[0]
                else:
                    self.__addSongToQueue(songInfo, isLocalQueue=True)

    def __addSongToQueue(self, songInfo, isLocalQueue=False):
        """
        Adds a song to the queue. If it's the localAvatar's queued song, then
        it marks it.
        
        Parameters:
            songInfo is a list of phase and data
            isLocalQueue is flag marking whether this is the localAvatar's queued song
        """
        isHost = (isLocalQueue and self.isUserHost())

        data = self.getMusicData(sanitizePhase(songInfo[0]), songInfo[1])
        if data:
            listItem = self.gui.addSongToQueue(data[0],
                                               highlight=isLocalQueue,
                                               moveToTopButton=isHost)
            if isLocalQueue:
                self.localQueuedSongInfo = songInfo
                self.localQueuedSongListItem = listItem

    def __localClearQueuedSong(self):
        """
        Clears the queued song records.
        """
        self.localQueuedSongInfo = None
        self.localQueuedSongListItem = None

#===============================================================================
# Music Playback
#===============================================================================

    def __play(self, phase, filename, length):
        """
        Plays some music!
        """
        assert self.notify.debugStateCall(self)
        self.music = base.loadMusic((MUSIC_PATH + "%s") % (phase, filename))
        if self.music:
            if self.__checkPartyValidity() and hasattr(
                    base.cr.playGame.getPlace().loader,
                    "music") and base.cr.playGame.getPlace().loader.music:
                base.cr.playGame.getPlace().loader.music.stop()
            base.resetMusic.play()
            self.music.setTime(0.0)
            self.music.setLoopCount(getMusicRepeatTimes(length))
            self.music.play()
            jukeboxAnimControl = self.jukebox.getAnimControl("dance")
            if not jukeboxAnimControl.isPlaying():
                self.jukebox.loop("dance")
            self.currentSongData = (phase, filename)

    def __stop(self):
        """
        Stops animations and and clears GUI.
        """
        self.jukebox.stop()
        self.currentSongData = None

        if self.music:
            self.music.stop()

        if self.gui.isLoaded():
            self.gui.clearSongCurrentlyPlaying()

    # Distributed (broadcast ram)
    def setSongPlaying(self, songInfo, toonId):
        """
        Sets the song from the AI to play in the client.
        Parameters:
            songInfo is a list with two items: phase and filename
        """

        phase = sanitizePhase(songInfo[0])
        filename = songInfo[1]
        assert (self.notify.debug("setSongPlaying phase_%d/%s" %
                                  (phase, filename)))

        # setSongPlaying sends empty filename if songs have stop playing
        # in order for the client to clean up.
        if not filename:
            self.__stop()
            return

        data = self.getMusicData(phase, filename)
        if data:
            self.__play(phase, filename, data[1])
            self.setSignNote(data[0])

            # Update the gui if it's active:
            if self.gui.isLoaded():
                item = self.gui.popSongFromQueue()
                self.gui.setSongCurrentlyPlaying(phase, filename)

                if item == self.localQueuedSongListItem:
                    self.__localClearQueuedSong()

        if toonId == localAvatar.doId:
            localAvatar.setSystemMessage(0, TTLocalizer.PartyJukeboxNowPlaying)

#===============================================================================
# Host only: Push his/her queued song to the top of the playlist.
#===============================================================================

    def __handleMoveSongToTop(self):
        """
        Requests to move the localAvatar's queued song to top.
        It is triggered when the user clicks on the "moveToTopButton" on the GUI.
        This is only enabled for the host of the party.
        """
        if self.isUserHost() and self.localQueuedSongListItem is not None:
            self.d_moveHostSongToTopRequest()

    # Distributed (clsend airecv)
    def d_moveHostSongToTopRequest(self):
        self.notify.debug("d_moveHostSongToTopRequest")
        self.sendUpdate("moveHostSongToTopRequest")

    # Distributed (only host gets it)
    def moveHostSongToTop(self):
        self.notify.debug("moveHostSongToTop")
        if self.gui.isLoaded():
            self.gui.pushQueuedItemToTop(self.localQueuedSongListItem)

    def getMusicData(self, phase, filename):
        data = []
        phase = sanitizePhase(phase)
        phase = self.phaseToMusicData.get(phase)
        if phase:
            data = phase.get(filename, [])
        return data

    def __checkPartyValidity(self):
        """ Function that checks the validity of a street,
        it's loader and the geometry"""
        if hasattr(base.cr.playGame, "getPlace") and base.cr.playGame.getPlace() and \
        hasattr(base.cr.playGame.getPlace(), "loader") and base.cr.playGame.getPlace().loader:
            return True
        else:
            return False
示例#18
0
文件: Npc.py 项目: jaimodha/MMOG
class Npc():

    def __init__(self,controlPointId,id, anchorx, anchory, anchorz,render,team):
        self.id = id
        self.anchorx = anchorx
        self.anchory = anchory
        self.anchorz = anchorz
        self.controlPointId = controlPointId
        self.target = None
        self.isMoving = False
        self.health = 200
        self.isCurrentUser = False
        self.damage = 8
        self.attackTimer = 0
        self._is_dead = False
        self._team = team
        
        self.render = render
        '''Initializing NPC actors'''
        self.npc = Actor("models/priest",
                                {"walk": "models/priest-walk", "attack":"models/priest-attack", "hurt":"models/priest-hit", "die":"models/priest-die"})
        if self._team==0:
            self.npcTex = loader.loadTexture("models/tex/guard_red.png")
        else:
            self.npcTex = loader.loadTexture("models/tex/guard_blue.png")
        self.npc.setTexture(self.npcTex)
        self.npc.setScale(0.5, 0.5, 0.5)
        self.npc.clearColor()
        self.npc.clearColorScale()
        self.npc.setColor(255, 0, 0, 0)
        self.npc.setColorScale(255, 0, 0, 0)
        self.npc.reparentTo(self.render)
        self.npc.setPos(anchorx,anchory,anchorz)
        
        self.AIchar = AICharacter("npc"+str(self.id),self.npc, 100, 0.05, 5)
        self.AIbehaviors = self.AIchar.getAiBehaviors()
        
        self.hb = HealthBar(1.5, value=self.health)
        #self._floater = NodePath(PandaNode("char_info"))
        #self._floater.reparentTo(self.npc)
        self.hb.setPos(0, 0, 11.9)
        self.hb.reparentTo(self.npc)
        #self.hb.reparentTo(self.npc)
        
    def renderBlue(self,AIworld):
        if not self._is_dead:
            self.AIbehaviors.removeAi("pursue")
            self.npc.detachNode()
        
        print "Started delete procedure for npc ",
        print self.id    
        self.npc.delete()
        self.npc = Actor("models/priest",
                                {"walk": "models/priest-walk", "attack":"models/priest-attack", "hurt":"models/priest-hit", "die":"models/priest-die"})
        self.npcTex = loader.loadTexture("models/tex/guard_blue.png")
        self.npc.setTexture(self.npcTex)
        self.npc.setScale(0.5, 0.5, 0.5)
        self.npc.clearColor()
        self.npc.clearColorScale()
        self.npc.setColor(255, 0, 0, 0)
        self.npc.setColorScale(255, 0, 0, 0)
        self.npc.reparentTo(self.render)
        self.npc.setPos(self.anchorx,self.anchory,self.anchorz)
        
        AIworld.removeAiChar("npc"+str(self.id))
        self.AIchar = AICharacter("npc"+str(self.id),self.npc, 100, 0.05, 5)
        self.AIbehaviors = self.AIchar.getAiBehaviors()
        AIworld.addAiChar(self.AIchar)
        
        self.hb = HealthBar(1.5, value=self.health)
        self.hb.setPos(0, 0, 18.1)
        self.hb.reparentTo(self.npc)
        #self.hb.reparentTo(self.npc)
        
    def renderRed(self,AIworld):
        if not self._is_dead:
            self.AIbehaviors.removeAi("pursue")
            self.npc.detachNode()
            
        self.npc.delete()
        self.npc = Actor("models/priest",
                                {"walk": "models/priest-walk", "attack":"models/priest-attack", "hurt":"models/priest-hit", "die":"models/priest-die"})
        self.npcTex = loader.loadTexture("models/tex/guard_red.png")
        self.npc.setTexture(self.npcTex)
        self.npc.setScale(0.5, 0.5, 0.5)
        self.npc.clearColor()
        self.npc.clearColorScale()
        self.npc.setColor(255, 0, 0, 0)
        self.npc.setColorScale(255, 0, 0, 0)
        self.npc.reparentTo(self.render)
        self.npc.setPos(self.anchorx,self.anchory,self.anchorz)
        
        AIworld.removeAiChar("npc"+str(self.id))
        self.AIchar = AICharacter("npc"+str(self.id),self.npc, 100, 0.05, 5)
        self.AIbehaviors = self.AIchar.getAiBehaviors()
        AIworld.addAiChar(self.AIchar)
        AIworld.update()
        
        self.hb = HealthBar(1.5, value=self.health)
        self.hb.setPos(0, 0, 8.1)
        self.hb.reparentTo(self.npc)
        
    def switchTeam(self,AIworld):
        print self.id,
        print " from team ",
        print self._team,
        print " getting deleted."
        if self._team==0:
            self._team=1
            self.renderBlue(AIworld)
        else:
            self._team=0
            self.renderRed(AIworld)
            
        if self.isCurrentUser:
            main.freeDeadNpc(self.id)
            
        self.target = None
        self.isMoving = False
        self.health = 200
        self.isCurrentUser = False
        self.damage = 8
        self.attackTimer = 0
        self._is_dead = False
            
        
    def set_health(self, health):
        self.health = health
        
    def take_damage(self, health_change):
        health = self.health
        if health <= health_change and not self._is_dead:
            self.killNpc()
        else:
            health = health-health_change
            self.set_health(health)
            self.hb.setValue(self.health)
            self.npc.play("hurt")
            
    def killNpc(self):
        self.set_health(0)
        self.hb.setValue(0)
        self.AIbehaviors.removeAi("pursue")
        hurt_interval = self.npc.actorInterval("hurt")
        death_interval = self.npc.actorInterval("die")
        seq = Sequence(hurt_interval, death_interval)
        seq.start()
        self.npc.pose("die",45)
        self._is_dead = True
        self.npc.detachNode()
        if self.isCurrentUser:
            main.freeDeadNpc(self.id)
            #main.cManager.sendRequest(Constants.CMSG_NPCDEATH, [self.id])
            print Constants.CMSG_NPCDEATH,
            print " + ",
            print self.id
            
            
    def chaseTarget(self, target, status = False):
        if(not self.isMoving):
            self.target = target
            self.AIbehaviors.pursue(self.target)
            self.npc.loop("walk")
            self.isMoving = True
            self.isCurrentUser = status
            
    def stopChase(self):
        
        #self.AIbehaviors.pauseAi("pursue")
        if not self._is_dead:
            self.AIbehaviors.removeAi("pursue")
            p1 = LerpHprInterval(self.npc, 4, Point3(180,0,0))
            p2 = LerpPosInterval(self.npc, 4, Point3(self.anchorx, self.anchory, self.anchorz))
            animInterval = self.npc.actorInterval("walk", loop = 1, duration=4)
            p2.start()
            p1.start()
            animInterval.start()
            self.isMoving = False
            self.target = None
            self.isCurrentUser = False
        
    def givNPCDistance(self,charachter):
        x = self.npc.getX()
        y = self.npc.getY()
        z = self.npc.getZ()
        minDist = math.sqrt( (charachter.getX()-x)*(charachter.getX()-x) + (charachter.getY()-y)*(charachter.getY()-y) + (charachter.getZ()-z)*(charachter.getZ()-z) )
        return minDist
    
    def checkNpcIsAlive(self):
        if(self.health>0):
            return True
        else:
            return False
                         
    def shouldAttack(self,currentTime,cManager):
        if not self._is_dead:
            if self.isMoving:
                if self.attackTimer>0:
                    self.attackTimer = self.attackTimer-currentTime
                    #print self.attackTimer
                if self.AIbehaviors.behaviorStatus("pursue")=="done":
                    #self.npc.stop("walk")
                    #print self.npc.getAnimControl("walk")
                    if self.attackTimer<=0:
                            if self.npc.getAnimControl("walk").isPlaying():
                                self.npc.stop("walk")
                            if not self.npc.getAnimControl("attack").isPlaying():
                                #self.npc.loop("attack")
                                self.npc.play("attack")
                                self.attackTimer = 2
                                #myInterval = self.npc.actorInterval("attack")
                                #seq = Sequence(myInterval)
                                #seq.append(Wait(3))
                                #seq.start()
                            if self.isCurrentUser:
                                cManager.sendRequest(Constants.CMSG_NPCATTACK, [self.id, self.damage])
                
                if self.AIbehaviors.behaviorStatus("pursue")=="active":
                    if self.npc.getAnimControl("attack").isPlaying():
                        self.npc.stop("attack")
                    if not self.npc.getAnimControl("walk").isPlaying():
                        self.npc.loop("walk") 
示例#19
0
class Monster():
    def __init__(self, id, parent, type, pos):
        self.id = id
        self.parent = parent
        self.hp = 100
        self.speed = 1
        self.can_move = True

        if type == 'baby':
            self.node = Actor(
                'models/baby', {
                    'walk': 'models/baby-walk',
                    'stand': 'models/baby-stand',
                    'idle': 'models/baby-idle',
                    'jump': 'models/baby-jump',
                    'bite1': 'models/baby-bite1',
                    'bite2': 'models/baby-bite2',
                    'head_attack': 'models/baby-head_attack',
                    'hit1': 'models/baby-hit1',
                    'hit2': 'models/baby-hit2',
                    'die': 'models/baby-die'
                })
            self.head_node = self.node.exposeJoint(None, "modelRoot",
                                                   "Bip01_Head")
            self.body_node = self.node.exposeJoint(None, "modelRoot",
                                                   "Bip01_Pelvis")
            self.node.setH(180)
            self.node.setScale(0.03)
            self.node.flattenLight()
            self.zpos = 0
            self.node.setPos(pos[0] * TILE_SIZE, pos[1] * TILE_SIZE, self.zpos)
            self.node.setTexture(loader.loadTexture('models/Zomby_D.png'))
            self.ts_normal = TextureStage('ts_normal')
            self.tex_normal = loader.loadTexture('models/Zomby_N.png')
            self.ts_normal.setMode(TextureStage.MNormal)
            self.node.setTexture(self.ts_normal, self.tex_normal)
            self.ts_gloss = TextureStage('ts_gloss')
            self.tex_gloss = loader.loadTexture('models/Zomby_S1.png')
            self.ts_gloss.setMode(TextureStage.MGloss)
            self.node.setTexture(self.ts_gloss, self.tex_gloss)
            self.ts_glow = TextureStage('ts_glow')
            self.tex_glow = loader.loadTexture('models/Zomby_I.png')
            self.ts_glow.setMode(TextureStage.MGlow)
            self.node.setTexture(self.ts_glow, self.tex_glow)
            self.node.reparentTo(render)
            self.node.loop('walk')
        elif type == 'nos':
            self.node = loader.loadModel('models/nos')
            self.zpos = 5
            self.node.setPos(pos[0] * TILE_SIZE, pos[1] * TILE_SIZE, self.zpos)
            self.node.setScale(2)
            if self.id == 1:
                self.node.setColor(1, 0, 0)
            elif self.id == 2:
                self.node.setColor(0, 1, 0)
            elif self.id == 3:
                self.node.setColor(0, 0, 1)
            else:
                self.node.setColor(1, 1, 1)
            self.node.reparentTo(render)

        #self.patrol_points = [(1,1), (4,11), (12,20), (18,4), (19,17)]

        #initialize 3d sound
        self.audio3d = Audio3DManager.Audio3DManager(base.sfxManagerList[0],
                                                     base.camera)
        self.shot_head = self.audio3d.loadSfx(
            'audio/Zombie In Pain-SoundBible.com-134322253.wav')
        self.shot_body = self.audio3d.loadSfx(
            'audio/Zombie Moan-SoundBible.com-565291980.wav')
        self.moan1 = self.audio3d.loadSfx(
            'audio/Mindless Zombie Awakening-SoundBible.com-255444348.wav')
        self.moan2 = self.audio3d.loadSfx(
            'audio/Zombie Brain Eater-SoundBible.com-1076387080.wav')
        self.aggro_sound = self.audio3d.loadSfx(
            'audio/Mummy Zombie-SoundBible.com-1966938763.wav')
        self.attack_sound = self.audio3d.loadSfx(
            'audio/Chopping Off Limb-SoundBible.com-884800545.wav')
        self.audio3d.attachSoundToObject(self.moan1, self.node)
        self.audio3d.attachSoundToObject(self.moan2, self.node)
        self.audio3d.attachSoundToObject(self.shot_head, self.node)
        self.audio3d.attachSoundToObject(self.shot_body, self.node)
        self.audio3d.attachSoundToObject(self.aggro_sound, self.node)
        self.audio3d.attachSoundToObject(self.attack_sound, self.node)
        delay0 = Wait(d(35))
        delay1 = Wait(25 + d(35))
        delay2 = Wait(25 + d(35))
        self.moan_sequence = Sequence(delay0,
                                      SoundInterval(self.moan1), delay1,
                                      SoundInterval(self.moan2), delay2)
        self.moan_sequence.loop()

        self.parent.collision_manager.createMonsterCollision(self)

        self.aggro_sound_last_played = 0
        #--------------------------brain-------------------------
        self.node.setH(160)

        self.pause = False

        self.action = ACTION_IDLE

        if percent(20):
            self.orders = ORDERS_PATROL
        else:
            self.orders = ORDERS_IDLE

        self.last_melee = 0

        self.player_last_seen_abs = None

        self.idle_timer = time.time()
        self.idle_value = 1

        self.current_waypoint = None

        #self.wait_until = None
        self.herding_timer = None

        self.path = None

        taskMgr.doMethodLater(1, self.behaviourTask,
                              'MonsterBehaviourTask' + str(self.id))
        taskMgr.doMethodLater(1, self.debugMoveTask,
                              'MonsterMoveTask' + str(self.id))

    def getLOS(self):
        return self.parent.collision_manager.checkMonsterPlayerLos(self)

    def sensePlayer(self):
        """Return True if player sensed, and his last known coordinates are stored in self.player_last_seen_abs"""

        # if the player is dead, do not sense him
        if self.parent.player.health <= 0:
            return False

        #get player's position
        p_pos_abs = self.parent.player.node.getPos()
        my_pos_abs = self.node.getPos()

        #--------------------------------SENSE---------------------------------
        #if player is within SENSING_RANGE we know he is there
        if self.distanceToPlayer() < SENSING_RANGE:
            #print "TOO CLOSE LOOSER!"
            self.player_last_seen_abs = p_pos_abs
            return True

        #---------------------------------HEAR----------------------------------
        #if player is within HEARING_RANGE we know he is there
        effective_hearing_range = HEARING_RANGE

        if self.parent.player.gunshot_at:
            effective_hearing_range *= 3
        else:
            if self.parent.player.sprint:
                effective_hearing_range *= 2
            if not self.parent.player.moving:
                effective_hearing_range = 0

        if self.distanceToPlayer() < effective_hearing_range:
            print "I HEAR U!"
            self.parent.player.adrenaline()
            #if we can see go chase him
            if self.getLOS():
                self.player_last_seen_abs = p_pos_abs
                return True

            #we cannot see him, build new path to that tile
            else:
                dest = getTile(p_pos_abs)
                path = pathFind(self.parent.level, getTile(self.node.getPos()),
                                dest)
                if path:
                    self.path = path
                    self.orders = ORDERS_PATROL
                    self.action = ACTION_FOLLOW_PATH
                    return False

        #-------------------------------SEE---------------------------------
        #if player is in front of us
        if self.angleToPlayerAbs() <= 45:
            #if he is close enough to see and we can see him
            if self.distanceToPlayer() <= VIEW_RANGE and self.getLOS():
                self.player_last_seen_abs = p_pos_abs
                #print "vidim!"
                return True

            #if player has a flashlight lit, and we can see him go after him
            if self.parent.player.flashlight and self.getLOS():
                self.player_last_seen_abs = p_pos_abs
                #print "vidim flashlight"
                return True

        #---------------------SEE MY OWN SHADOW---------------------------
        #if player is behind us and has a lit up flashlight and we have LOS to him
        if self.angleToPlayerAbs() > 135 and self.angleToPlayerAbs() < 225:
            if self.parent.player.flashlight and self.getLOS():

                #if he is looking at us
                my_pos_rel = self.node.getPos(self.parent.player.node)
                forward = Vec2(0, 1)
                if math.fabs(
                        forward.signedAngleDeg(
                            Vec2(my_pos_rel[0], my_pos_rel[1]))) <= 30:
                    #go after my own shadow
                    print "herding"
                    self.orders = ORDERS_HERDING
                    self.node.setH(self.parent.player.node.getH())
                    self.herding_timer = time.time()

        return False

    def distanceToPlayer(self):
        p_pos_abs = self.parent.player.node.getPos()
        my_pos_abs = self.node.getPos()
        return math.sqrt(
            math.pow(p_pos_abs[0] - my_pos_abs[0], 2) +
            math.pow(p_pos_abs[1] - my_pos_abs[1], 2))

    def angleToPlayer(self):
        p_pos_rel = self.parent.player.node.getPos(self.node)
        forward = Vec2(0, 1)
        return forward.signedAngleDeg(Vec2(p_pos_rel[0], p_pos_rel[1]))

    def angleToPlayerAbs(self):
        return math.fabs(self.angleToPlayer())

    def behaviourTask(self, task):
        if self.pause:
            return task.again

        #top priority, if we sense a player, go after him!
        if self.sensePlayer():
            if time.time() - self.aggro_sound_last_played > 5:
                self.aggro_sound.play()
                self.aggro_sound_last_played = time.time()

            self.action = ACTION_CHASE
            return task.again

        elif self.orders == ORDERS_IDLE:
            #percent chance to go on patrol
            if percent(10):
                self.orders = ORDERS_PATROL
                return task.again
            self.action = ACTION_IDLE

        elif self.orders == ORDERS_PATROL:
            #percent chance to get idle
            if percent(5):
                self.orders = ORDERS_IDLE
                return task.again

            #if we are already patroling, dont change anything
            if self.action == ACTION_FOLLOW_PATH:
                return task.again

            #build a new path for patrol
            dest = self.getNewPatrolPoint()
            self.path = pathFind(self.parent.level,
                                 getTile(self.node.getPos()), dest)
            self.action = ACTION_FOLLOW_PATH

        elif self.orders == ORDERS_HERDING:
            self.action = ACTION_MOVE
            if time.time() - self.herding_timer > HERDING_TIMEOUT:
                self.orders = ORDERS_IDLE

        return task.again

    def debugMoveTask(self, task):
        if self.pause:
            return task.cont

        #print "orders:", self.orders

        if self.action == ACTION_CHASE:
            self.parent.player.adrenaline()
            look_pos = Point3(self.player_last_seen_abs.getX(),
                              self.player_last_seen_abs.getY(), self.zpos)
            self.node.lookAt(look_pos)
            self.node.setFluidPos(self.node, 0,
                                  CHASE_SPEED * globalClock.getDt(), 0)

            if self.distanceToPlayer(
            ) <= MELEE_RANGE and self.angleToPlayerAbs() <= 45 and self.getLOS(
            ):
                if time.time() - self.last_melee >= MELEE_TIME:
                    self.attack_sound.play()
                    att = random.randint(0, 2)
                    if att == 0:
                        animname = 'bite1'
                    elif att == 1:
                        animname = 'bite2'
                    else:
                        animname = 'head_attack'
                    self.node.play(animname)
                    duration = self.node.getNumFrames(
                        animname) / 24  # animation play rate
                    taskMgr.doMethodLater(duration,
                                          self.finishedAnim,
                                          'FinishedAnim',
                                          extraArgs=[])
                    self.parent.player.getDamage()
                    self.last_melee = time.time()

        elif self.action == ACTION_IDLE:
            if time.time() - self.idle_timer > IDLE_TIME:
                #we are standing still and rotating, see on whic side we will rotate now
                self.idle_timer = time.time()
                if percent(20):
                    self.idle_value *= -1
            self.rotateBy(self.idle_value * IDLE_ROTATE_SPEED)

        elif self.action == ACTION_FOLLOW_PATH:
            #if we dont have a waypoint, calculate one
            if not self.current_waypoint:
                try:
                    #get next tile from path
                    tile = self.path[0]
                    self.path = self.path[1:]

                    #calculate waypoint
                    varx = 5 - (d(4) + d(4))
                    vary = 5 - (d(4) + d(4))
                    self.current_waypoint = (Point3(tile[0] * TILE_SIZE + varx,
                                                    tile[1] * TILE_SIZE + vary,
                                                    self.zpos), time.time())
                    #print "waypoint:", self.current_waypoint
                    self.node.lookAt(self.current_waypoint[0])

                except (IndexError, TypeError):
                    #we have reached the end of path
                    self.orders = ORDERS_IDLE
                    self.current_waypoint = None

            #if we have a waypoint move forward towards it, and check if we arrived at it
            else:
                self.node.setFluidPos(self.node, 0,
                                      NORMAL_SPEED * globalClock.getDt(), 0)
                my_pos = self.node.getPos()

                #if we are close enough to the waypoint or if we didnt get to waypoint in time, delete it so we know we need a new one
                if math.fabs( my_pos[0] - self.current_waypoint[0][0] ) < 1 and math.fabs( my_pos[1] - self.current_waypoint[0][1] ) < 2 \
                        or time.time() - self.current_waypoint[1] > WAYPOINT_TIMER:
                    self.current_waypoint = None

        elif self.action == ACTION_MOVE:
            self.node.setFluidPos(self.node, 0,
                                  NORMAL_SPEED * globalClock.getDt(), 0)

        return task.cont

    def finishedAnim(self):
        if not self.pause:
            self.node.loop('walk')

    def rotateBy(self, value):
        self.node.setH((self.node.getH() + value) % 360)

    def getNewPatrolPoint(self):
        lvl = self.parent.level
        allTiles = lvl.getFloorTiles()
        while True:
            t = (d(lvl.getMaxX()), d(lvl.getMaxY()))
            if t in allTiles:
                return t

    def hitWall(self):

        if self.action == ACTION_CHASE:
            return

        #print "lupio!"
        """self.moan1.play()
        self.rotateBy( 180 )
        self.node.setFluidPos(self.node, 0, CHASE_SPEED*globalClock.getDt(), 0)            
        #self.action = IDLE
        """
        """
        old = self.node.getH()
        rnd = 80 + random.randint( 0, 20 )

        forward = Vec2( 0, 1 )
        impact = Vec2( pos[0], pos[1] )

        angle = forward.signedAngleDeg( impact )
        #print "angle:", angle
        
        if angle < 0:
            #+ cause angle is negative
            rnd = 91 + angle
            self.node.setH( (self.node.getH() + rnd)%360 )            
        elif angle > 0:
            rnd = -91 + angle
            self.node.setH( (self.node.getH() + rnd)%360 )
        
        #print "stari:", old, "  novi:", self.node.getH()    
        """
        pass

    def pauze(self):
        if self.moan_sequence:
            self.moan_sequence.pause()
        self.pause = True

    def resume(self):
        if self.moan_sequence:
            self.moan_sequence.resume()
        self.pause = False

    def destroy(self):
        self.audio3d.detachSound(self.moan1)
        self.audio3d.detachSound(self.moan2)
        self.audio3d.detachSound(self.shot_head)
        self.audio3d.detachSound(self.shot_body)
        self.audio3d.detachSound(self.aggro_sound)
        self.audio3d.detachSound(self.attack_sound)
        if self.moan_sequence != None:
            self.moan_sequence.pause()
            self.moan_sequence = None
        taskMgr.remove('MonsterBehaviourTask' + str(self.id))
        taskMgr.remove('MonsterMoveTask' + str(self.id))
        self.cn_head.node().clearPythonTag('node')
        self.cn_body.node().clearPythonTag('node')
        self.cn_pusher.node().clearPythonTag('node')
        self.cn_ray.node().clearPythonTag('node')
        self.node.delete()
        self.node.cleanup()
        self.node.removeNode()

    """
示例#20
0
文件: Npc.py 项目: jaimodha/MMOG
class Npc():
    def __init__(self, controlPointId, id, anchorx, anchory, anchorz, render,
                 team):
        self.id = id
        self.anchorx = anchorx
        self.anchory = anchory
        self.anchorz = anchorz
        self.controlPointId = controlPointId
        self.target = None
        self.isMoving = False
        self.health = 200
        self.isCurrentUser = False
        self.damage = 8
        self.attackTimer = 0
        self._is_dead = False
        self._team = team

        self.render = render
        '''Initializing NPC actors'''
        self.npc = Actor(
            "models/priest", {
                "walk": "models/priest-walk",
                "attack": "models/priest-attack",
                "hurt": "models/priest-hit",
                "die": "models/priest-die"
            })
        if self._team == 0:
            self.npcTex = loader.loadTexture("models/tex/guard_red.png")
        else:
            self.npcTex = loader.loadTexture("models/tex/guard_blue.png")
        self.npc.setTexture(self.npcTex)
        self.npc.setScale(0.5, 0.5, 0.5)
        self.npc.clearColor()
        self.npc.clearColorScale()
        self.npc.setColor(255, 0, 0, 0)
        self.npc.setColorScale(255, 0, 0, 0)
        self.npc.reparentTo(self.render)
        self.npc.setPos(anchorx, anchory, anchorz)

        self.AIchar = AICharacter("npc" + str(self.id), self.npc, 100, 0.05, 5)
        self.AIbehaviors = self.AIchar.getAiBehaviors()

        self.hb = HealthBar(1.5, value=self.health)
        #self._floater = NodePath(PandaNode("char_info"))
        #self._floater.reparentTo(self.npc)
        self.hb.setPos(0, 0, 11.9)
        self.hb.reparentTo(self.npc)
        #self.hb.reparentTo(self.npc)

    def renderBlue(self, AIworld):
        if not self._is_dead:
            self.AIbehaviors.removeAi("pursue")
            self.npc.detachNode()

        print "Started delete procedure for npc ",
        print self.id
        self.npc.delete()
        self.npc = Actor(
            "models/priest", {
                "walk": "models/priest-walk",
                "attack": "models/priest-attack",
                "hurt": "models/priest-hit",
                "die": "models/priest-die"
            })
        self.npcTex = loader.loadTexture("models/tex/guard_blue.png")
        self.npc.setTexture(self.npcTex)
        self.npc.setScale(0.5, 0.5, 0.5)
        self.npc.clearColor()
        self.npc.clearColorScale()
        self.npc.setColor(255, 0, 0, 0)
        self.npc.setColorScale(255, 0, 0, 0)
        self.npc.reparentTo(self.render)
        self.npc.setPos(self.anchorx, self.anchory, self.anchorz)

        AIworld.removeAiChar("npc" + str(self.id))
        self.AIchar = AICharacter("npc" + str(self.id), self.npc, 100, 0.05, 5)
        self.AIbehaviors = self.AIchar.getAiBehaviors()
        AIworld.addAiChar(self.AIchar)

        self.hb = HealthBar(1.5, value=self.health)
        self.hb.setPos(0, 0, 18.1)
        self.hb.reparentTo(self.npc)
        #self.hb.reparentTo(self.npc)

    def renderRed(self, AIworld):
        if not self._is_dead:
            self.AIbehaviors.removeAi("pursue")
            self.npc.detachNode()

        self.npc.delete()
        self.npc = Actor(
            "models/priest", {
                "walk": "models/priest-walk",
                "attack": "models/priest-attack",
                "hurt": "models/priest-hit",
                "die": "models/priest-die"
            })
        self.npcTex = loader.loadTexture("models/tex/guard_red.png")
        self.npc.setTexture(self.npcTex)
        self.npc.setScale(0.5, 0.5, 0.5)
        self.npc.clearColor()
        self.npc.clearColorScale()
        self.npc.setColor(255, 0, 0, 0)
        self.npc.setColorScale(255, 0, 0, 0)
        self.npc.reparentTo(self.render)
        self.npc.setPos(self.anchorx, self.anchory, self.anchorz)

        AIworld.removeAiChar("npc" + str(self.id))
        self.AIchar = AICharacter("npc" + str(self.id), self.npc, 100, 0.05, 5)
        self.AIbehaviors = self.AIchar.getAiBehaviors()
        AIworld.addAiChar(self.AIchar)
        AIworld.update()

        self.hb = HealthBar(1.5, value=self.health)
        self.hb.setPos(0, 0, 8.1)
        self.hb.reparentTo(self.npc)

    def switchTeam(self, AIworld):
        print self.id,
        print " from team ",
        print self._team,
        print " getting deleted."
        if self._team == 0:
            self._team = 1
            self.renderBlue(AIworld)
        else:
            self._team = 0
            self.renderRed(AIworld)

        if self.isCurrentUser:
            main.freeDeadNpc(self.id)

        self.target = None
        self.isMoving = False
        self.health = 200
        self.isCurrentUser = False
        self.damage = 8
        self.attackTimer = 0
        self._is_dead = False

    def set_health(self, health):
        self.health = health

    def take_damage(self, health_change):
        health = self.health
        if health <= health_change and not self._is_dead:
            self.killNpc()
        else:
            health = health - health_change
            self.set_health(health)
            self.hb.setValue(self.health)
            self.npc.play("hurt")

    def killNpc(self):
        self.set_health(0)
        self.hb.setValue(0)
        self.AIbehaviors.removeAi("pursue")
        hurt_interval = self.npc.actorInterval("hurt")
        death_interval = self.npc.actorInterval("die")
        seq = Sequence(hurt_interval, death_interval)
        seq.start()
        self.npc.pose("die", 45)
        self._is_dead = True
        self.npc.detachNode()
        if self.isCurrentUser:
            main.freeDeadNpc(self.id)
            #main.cManager.sendRequest(Constants.CMSG_NPCDEATH, [self.id])
            print Constants.CMSG_NPCDEATH,
            print " + ",
            print self.id

    def chaseTarget(self, target, status=False):
        if (not self.isMoving):
            self.target = target
            self.AIbehaviors.pursue(self.target)
            self.npc.loop("walk")
            self.isMoving = True
            self.isCurrentUser = status

    def stopChase(self):

        #self.AIbehaviors.pauseAi("pursue")
        if not self._is_dead:
            self.AIbehaviors.removeAi("pursue")
            p1 = LerpHprInterval(self.npc, 4, Point3(180, 0, 0))
            p2 = LerpPosInterval(
                self.npc, 4, Point3(self.anchorx, self.anchory, self.anchorz))
            animInterval = self.npc.actorInterval("walk", loop=1, duration=4)
            p2.start()
            p1.start()
            animInterval.start()
            self.isMoving = False
            self.target = None
            self.isCurrentUser = False

    def givNPCDistance(self, charachter):
        x = self.npc.getX()
        y = self.npc.getY()
        z = self.npc.getZ()
        minDist = math.sqrt((charachter.getX() - x) * (charachter.getX() - x) +
                            (charachter.getY() - y) * (charachter.getY() - y) +
                            (charachter.getZ() - z) * (charachter.getZ() - z))
        return minDist

    def checkNpcIsAlive(self):
        if (self.health > 0):
            return True
        else:
            return False

    def shouldAttack(self, currentTime, cManager):
        if not self._is_dead:
            if self.isMoving:
                if self.attackTimer > 0:
                    self.attackTimer = self.attackTimer - currentTime
                    #print self.attackTimer
                if self.AIbehaviors.behaviorStatus("pursue") == "done":
                    #self.npc.stop("walk")
                    #print self.npc.getAnimControl("walk")
                    if self.attackTimer <= 0:
                        if self.npc.getAnimControl("walk").isPlaying():
                            self.npc.stop("walk")
                        if not self.npc.getAnimControl("attack").isPlaying():
                            #self.npc.loop("attack")
                            self.npc.play("attack")
                            self.attackTimer = 2
                            #myInterval = self.npc.actorInterval("attack")
                            #seq = Sequence(myInterval)
                            #seq.append(Wait(3))
                            #seq.start()
                        if self.isCurrentUser:
                            cManager.sendRequest(Constants.CMSG_NPCATTACK,
                                                 [self.id, self.damage])

                if self.AIbehaviors.behaviorStatus("pursue") == "active":
                    if self.npc.getAnimControl("attack").isPlaying():
                        self.npc.stop("attack")
                    if not self.npc.getAnimControl("walk").isPlaying():
                        self.npc.loop("walk")
示例#21
0
class Character(FSM.FSM,Vehicle):
    """
    An animated character with various steering behaviors. By enabling and
    disabling different steering behaviors Character can be used as
    a keyboard + mouse controlled player avatar, or can be controlled (for
    example) by a Finite State Machine and used to implement a non-player
    character.
    """

    # FIXME: Think it might be clearer and safer if Character has a FSM instead
    # of inheriting from FSM (classes that inherit from Character will likely
    # want to inherit from FSM too).

    def __init__(self,name='Ralph',model='models/ralph',run='models/ralph-run',
                 walk='models/ralph-walk',pos=None,avoidObstacles=True,
                 avoidVehicles=True,
                 hprs=(180,0,0,1,1,1), # Ralph's Y is backward
                 ):
        """Initialise the character.

        By default tries to load Panda3D's Ralph model: models/ralph,
        models/ralph-run and models/ralph-walk."""

        FSM.FSM.__init__(self,'Character')
        Vehicle.__init__(self,pos=pos,avoidObstacles=avoidObstacles,
                         avoidVehicles=avoidVehicles,radius=2.5)

        self.name = name
        self.lastPose = 0 # Used when transitioning between animations
        self.actor = Actor(model,{"run":run,"walk":walk})        
        self.actor.setHprScale(*hprs)
        self.actor.reparentTo(self.prime)

        # Add a task for this Character to the global task manager.
        self.characterStepTask=taskMgr.add(self.characterStep,"Character step task")

    def characterStep(self,task):
        """Update the character. Called every frame by Panda's global task
        manager."""

        # Update the orientation of the Character. Want to face in the
        # direction of the Vehicle's velocity in the X and Y dimensions, but
        # always face straight forward (not up or down) in the Z dimension.
        pr = self.prime.getP(),self.prime.getR()
        self.prime.lookAt((self._pos+self._velocity).getX(),
                          (self._pos+self._velocity).getY(),0)
        self.prime.setHpr(self.prime.getH(),*pr)

        # Animate the Character's Actor. The Character automatically changes
        # between stand, run and walk animations and varies the playrate of the
        # animations depending on the speed of the Character's Vehicle.
        speed = self.getspeed()
        if speed < .05:
            if self.getCurrentOrNextState() != 'Stand':
                self.request('Stand')
        elif speed < .25:
            self.actor.setPlayRate(speed*4,"walk")
            if self.getCurrentOrNextState() != 'Walk':
                self.request('Walk')
        else:
            self.actor.setPlayRate(speed*2,"run")
            if self.getCurrentOrNextState() != 'Run':
                self.request('Run')

        return Task.cont

    def destroy(self):
        """Prepare this Character to be garbage-collected by Python:
        
        Remove all of the Character's nodes from the scene graph, remove its
        CollisionSolids from the global CollisionTraverser, clear its
        CollisionHandler, remove tasks, destroy Actor.
        
        After executing this method, any remaining references to the Character
        object can be destroyed by the user module, and the Character will be
        garbage-collected by Python.
        """
    
        taskMgr.remove(self.characterStepTask)
        self.cleanup()
        self.actor.delete()
        Vehicle.destroy(self)

    # Methods for handling animations.

    def storeLastPose(self):
        currAnim=self.actor.getCurrentAnim()
        numFrames=self.actor.getNumFrames(currAnim)
        animFrame=self.actor.getCurrentFrame(currAnim)
        self.lastPose=float(animFrame)/float(numFrames)
        self.actor.stop(currAnim)

    def loopFromPose(self,animName):
        self.actor.pose(animName,frame=self.lastPose*self.actor.getNumFrames(animName))
        self.actor.loop(animName,restart=0)

    # FSM State handlers. Called when transitioning to a new state.
    def enterRun(self):  self.loopFromPose("run")
    def exitRun(self):   self.storeLastPose()
    def enterWalk(self): self.loopFromPose("walk")
    def exitWalk(self):  self.storeLastPose()
    def enterStand(self):
        standPoseFrame=6    # frame 6 (the most acceptable stand pose)
        numFrames=self.actor.getNumFrames("walk")
        lastFrame=self.lastPose*numFrames
        # "mirror" the frame to bring it closer to the most acceptable stand pose
        if lastFrame>.5*(numFrames-1):
           lastFrame=numFrames-1-lastFrame
        frameDiff=standPoseFrame-lastFrame
        # if already at stand pose, don't do anything
        if frameDiff==0:
           return
        # forward animation playback
        if frameDiff>=0:
           fromFrame=lastFrame
           toFrame=standPoseFrame
        else:
        # backward animation playback
           fromFrame=standPoseFrame
           toFrame=lastFrame
        playDir=2*frameDiff/numFrames
        self.actor.setPlayRate(playDir,"walk")
        self.actor.play("walk", fromFrame=fromFrame, toFrame=toFrame)
示例#22
0
class Enemy(FSM, Unit):

    # Declare private variables
    _enemyActive = False
    _removeCorpseDelay = 2  # seconds before corpse is cleaned

    def __init__(self, mainRef, attributes):
        print("Enemy instantiated")
        Unit.__init__(self)
        FSM.__init__(self, 'playerFSM')

        self._mainRef = mainRef
        self._playerRef = mainRef.player
        self._AIworldRef = mainRef.AIworld
        self._enemyListRef = mainRef.enemyList
        self._ddaHandlerRef = mainRef.DDAHandler
        self._stateHandlerRef = mainRef.stateHandler
        self._scenarioHandlerRef = mainRef.scenarioHandler

        #self.topEnemyNode = mainRef.mainNode.attachNewNode('topEnemyNode')
        self.initEnemyNode(mainRef.mainNode)

        utils.enemyDictionary[self.enemyNode.getName()] = self

        self.loadEnemyModel(attributes.modelName)
        self.initAttributes(attributes)
        self.initEnemyAi()

        self.initEnemyDDA()

        self.initEnemyCollisionHandlers()
        self.initEnemyCollisionSolids()

        #self.request('Idle')
        self.request('Disabled')

        # Start enemy updater task
        self.enemyUpdaterTask = taskMgr.add(self.enemyUpdater,
                                            'enemyUpdaterTask')

    def initEnemyNode(self, parentNode):
        enemyName = 'enemy' + str(len(self._enemyListRef))
        self.enemyNode = parentNode.attachNewNode(enemyName)
        self._enemyListRef.append(self)

    def loadEnemyModel(self, modelName):
        modelPrefix = 'models/' + modelName
        self.enemyModel = Actor(
            modelPrefix + '-model', {
                'walk': modelPrefix + '-walk',
                'attack': modelPrefix + '-attack',
                'idle': modelPrefix + '-idle',
                'awake': modelPrefix + '-awake',
                'stop': modelPrefix + '-stop',
                'hit': modelPrefix + '-hit',
                'death1': modelPrefix + '-death1',
                'death2': modelPrefix + '-death2'
            })
        self.enemyModel.reparentTo(self.enemyNode)

        self.enemyNode.setPos(Point3.zero())

        self.enemyNode.setDepthOffset(-1)

    def initAttributes(self, attributes):
        perceptionRangeMultiplier = 1.2
        combatRangeMultiplier = .3
        speedMultiplier = .1

        self.strength = attributes.strength
        self.constitution = attributes.constitution
        self.dexterity = attributes.dexterity

        self.mass = attributes.mass
        self.movementSpeed = speedMultiplier * attributes.movementSpeed
        self.perceptionRange = perceptionRangeMultiplier * attributes.perceptionRange
        self.combatRange = combatRangeMultiplier * attributes.combatRange
        self.attackBonus = attributes.attackBonus
        self.damageBonus = attributes.damageBonus
        self.damageRange = attributes.damageRange
        self.initiativeBonus = attributes.initiativeBonus
        self.fixedHealthPoints = attributes.fixedHealthPoints
        self.armorClass = attributes.armorClass

        if attributes.startLevel > 1:
            for i in range(attributes.startLevel - 1):
                self.increaseLevel()

        self.expAward = attributes.expAward

        self.initHealth()

    def initEnemyDDA(self):
        if self._scenarioHandlerRef.getHasDDA():
            maxLevelDifference = self._ddaHandlerRef.maxLevelDifference

            # Level enemy up to player's level minus maxLevelDifference
            levelDifference = self._playerRef.level - self.level
            if levelDifference >= maxLevelDifference:
                for i in range(levelDifference - maxLevelDifference):
                    self.increaseLevel()

    def getAttackBonus(self):
        modifier = self.getStrengthModifier() if self.getStrengthModifier(
        ) > self.getDexterityModifier() else self.getDexterityModifier()
        ab = self.attackBonus + (self.level / 2) + modifier  # + utils.getD20()

        if self._scenarioHandlerRef.getHasDDA():
            attackBonusModifier = self._ddaHandlerRef.attackBonusModifier
            if attackBonusModifier < 0:
                ab -= attackBonusModifier
                if ab < 1:
                    ab = 1

        return ab + utils.getD20()

    def initEnemyAi(self):
        self.enemyAI = AICharacter(
            'enemy',
            self.enemyNode,
            self.mass,  # Mass
            0.1,  # Movt force
            self.movementSpeed)  # Max force
        self._AIworldRef.addAiChar(self.enemyAI)

        self.enemyAIBehaviors = self.enemyAI.getAiBehaviors()
        #self.enemyAIBehaviors.obstacleAvoidance(1.0)

    def initEnemyCollisionHandlers(self):
        self.groundHandler = CollisionHandlerQueue()
        self.collPusher = CollisionHandlerPusher()

    def initEnemyCollisionSolids(self):
        # Enemy ground ray
        groundRay = CollisionRay(0, 0, 2, 0, 0, -1)
        groundColl = CollisionNode('enemyGroundRay')
        groundColl.addSolid(groundRay)

        groundColl.setIntoCollideMask(BitMask32.allOff())
        groundColl.setFromCollideMask(BitMask32.bit(1))

        self.groundRayNode = self.enemyNode.attachNewNode(groundColl)
        #self.groundRayNode.show()

        base.cTrav.addCollider(self.groundRayNode, self.groundHandler)

        # Enemy collision sphere
        collSphereNode = CollisionNode('enemyCollSphere')
        collSphere = CollisionSphere(0, 0, 0.1, 0.2)
        collSphereNode.addSolid(collSphere)

        collSphereNode.setIntoCollideMask(BitMask32.allOff())
        collSphereNode.setFromCollideMask(BitMask32.bit(2))

        self.sphereNode = self.enemyNode.attachNewNode(collSphereNode)
        #sphereNode.show()

        base.cTrav.addCollider(self.sphereNode, self.collPusher)
        self.collPusher.addCollider(self.sphereNode, self.enemyNode)

        # Enemy picker collision sphere
        pickerSphereCollNode = CollisionNode(self.enemyNode.getName())
        pickerCollSphere = CollisionSphere(0, 0, 0, 0.5)
        pickerSphereCollNode.addSolid(pickerCollSphere)

        pickerSphereCollNode.setFromCollideMask(BitMask32.allOff())
        pickerSphereCollNode.setIntoCollideMask(BitMask32.bit(1))

        self.pickerNode = self.enemyNode.attachNewNode(pickerSphereCollNode)
        #sphereNodePath.show()

        # Enemy attack collision sphere
        attackCollSphereNode = CollisionNode(self.enemyNode.getName() +
                                             'atkSph')
        attackCollSphere = CollisionSphere(0, 0, 0.1, 0.15)
        attackCollSphereNode.addSolid(attackCollSphere)

        attackCollSphereNode.setIntoCollideMask(BitMask32.bit(3))
        attackCollSphereNode.setFromCollideMask(BitMask32.allOff())

        attackSphereNode = self.enemyNode.attachNewNode(attackCollSphereNode)
        #attackSphereNode.show()

    def slowMovementByPercentage(self, percentage=30, slowDuration=20):
        #print self.enemyNode.getName(), ' slowed by ', percentage, ' %'
        oldSpeed = self.movementSpeed
        newSpeed = ((100.0 - percentage) / 100.0) * oldSpeed

        if newSpeed < 1.0:
            newSpeed = 1.0

        self.movementSpeed = newSpeed

        taskMgr.doMethodLater(slowDuration,
                              self.removeSlowMovement,
                              'removeSlowMovementTask',
                              extraArgs=[oldSpeed],
                              appendTask=True)

    def removeSlowMovement(self, oldSpeed, task):
        self.movementSpeed = oldSpeed
        return task.done

    def checkGroundCollisions(self):
        if self.groundHandler.getNumEntries() > 0:
            self.groundHandler.sortEntries()
            entries = []
            for i in range(self.groundHandler.getNumEntries()):
                entry = self.groundHandler.getEntry(i)
                #print('entry:', entry)
                entries.append(entry)

            entries.sort(lambda x, y: cmp(
                y.getSurfacePoint(render).getZ(),
                x.getSurfacePoint(render).getZ()))

            for i in range(len(entries)):
                if entries[i].getIntoNode().getName()[:6] == 'ground':
                    #print('entryFound:', entries[0])
                    newZ = entries[i].getSurfacePoint(base.render).getZ()
                    self.enemyNode.setZ(newZ)
                    #print('enemyZ:', newZ)
                    break

    def enemyUpdater(self, task):
        if self._stateHandlerRef.state != self._stateHandlerRef.PLAY or not self._enemyActive:
            self.enemyModel.stop()
            # Do not do anything when paused
            return task.cont

        self.checkGroundCollisions()

        if self.getIsDead():
            self.onDeath()
            return task.done

        if self._playerRef.getIsDead():
            return task.cont

        playerPos = self._playerRef.playerNode.getPos()
        enemyPos = self.enemyNode.getPos()

        # If player is within enemy perception range
        if utils.getIsInRange(playerPos, enemyPos, self.perceptionRange):

            # If enemy is not doing anything
            if self.state == 'Idle':
                # Start pursuing
                if self.state != 'Pursue':
                    self.request('Pursue')

            # If enemy is already pursueing
            elif self.state == 'Pursue':
                # If player is within combat range
                if utils.getIsInRange(playerPos, enemyPos, self.combatRange):
                    #print 'enemy go to combat'
                    # Go to combat
                    if self.state != 'Combat':
                        self.request('Combat')

            # If enemy is already in combat
            elif self.state == 'Combat':
                # If player has moved out of combat range
                if not utils.getIsInRange(playerPos, enemyPos,
                                          self.combatRange):
                    # Start pursuing
                    if self.state != 'Pursue':
                        self.request('Pursue')

            # If enemy is disabled
            elif self.state == 'Disabled':
                if self.enemyAI.getMaxForce() != self.movementSpeed:
                    self.enemyAI.setMaxForce(self.movementSpeed)

        # If player is not within perception range
        else:
            if self.state != 'Idle':
                self.request('Idle')

        return task.cont

    def pursuePlayer(self):
        taskMgr.add(self.pursue, 'pursueTask')

    def pursue(self, task):
        if self.state == 'Pursue' and not self.getIsDead():
            pitchRoll = self.enemyNode.getP(), self.enemyNode.getR()
            self.enemyNode.headsUp(self._playerRef.playerNode)
            self.enemyNode.setHpr(self.enemyNode.getH() - 180, *pitchRoll)

            speed = -self.movementSpeed * globalClock.getDt()
            self.enemyNode.setFluidPos(self.enemyNode, 0, speed, 0)

            return task.cont
        else:
            task.done

    def enterIdle(self):
        #print 'enemy enterIdle'
        stopEnemy = self.enemyModel.actorInterval('stop', loop=0)
        idleEnemy = self.enemyModel.actorInterval('idle',
                                                  startFrame=0,
                                                  endFrame=1,
                                                  loop=0)

        self.stopSequence = Sequence(stopEnemy, idleEnemy)
        self.stopSequence.start()

        self.isSleeping = True

    def exitIdle(self):
        #print('enemy exitIdle')
        self.stopSequence.finish()

    def enterPursue(self):
        #print('enemy enterPursue')
        loopWalkEnemy = Func(self.enemyModel.loop,
                             'walk',
                             fromFrame=0,
                             toFrame=12)

        # Only awake enemy if it comes from idle
        if self.isSleeping:
            self.isSleeping = False

            awakeEnemy = self.enemyModel.actorInterval('awake', loop=0)
            self.awakeSequence = Sequence(awakeEnemy, loopWalkEnemy,
                                          Func(self.pursuePlayer))
        else:
            self.awakeSequence = Sequence(loopWalkEnemy,
                                          Func(self.pursuePlayer))

        self.awakeSequence.start()

    def exitPursue(self):
        #print('enemy exitPursue')
        self.awakeSequence.finish()

    def enterCombat(self):
        #print('enemy enterCombat')
        self.enemyModel.stop()

        attackDelay = self.getInitiativeRoll()
        self.attackTask = taskMgr.doMethodLater(attackDelay, self.attackPlayer,
                                                'attackPlayerTask')

    def enterDisabled(self):
        #print 'enterDisable'
        pass

    def exitDisabled(self):
        #print 'exitDisable'
        pass

    def exitCombat(self):
        #print('enemy exitCombat')
        taskMgr.remove(self.attackTask)

    def enterDeath(self):
        #print('enemy enterDeath')
        self.enemyAIBehaviors.removeAi('all')
        randomDeathAnim = 'death' + str(utils.getD2())
        self.enemyModel.play(randomDeathAnim)

    def attack(self, other):
        if not self.getIsDead() and not other.getIsDead():
            if self.getAttackBonus() >= other.getArmorClass():
                dmg = self.getDamageBonus()
                #print(self.getName(), ' damaged ', other.getName(), ' for ', dmg, ' damage')
                other.receiveDamage(dmg)

                return 2  # Returns 2 when self damages other

            return 1  # Returns 1 when self attacks other, but misses

        return 0  # Returns 0 when either self or other is dead

    def attackPlayer(self, task):
        if self._stateHandlerRef.state != self._stateHandlerRef.PLAY or not self._enemyActive:
            # Do not do anything when paused
            return task.again

        if self._playerRef.getIsDead():
            print('player is already dead')
            self.request('Idle')
            return task.done

        elif self.getIsDead():
            return task.done

        else:
            #print('Attack player!')
            # Make sure enemy is facing player when attacking
            pitchRoll = self.enemyNode.getP(), self.enemyNode.getR()
            self.enemyNode.headsUp(self._playerRef.playerNode)
            self.enemyNode.setHpr(self.enemyNode.getH() - 180, *pitchRoll)

            attacked = self.attack(self._playerRef)
            if attacked != 0:
                self.playAttackAnimation()
                if attacked == 2:
                    self._playerRef.playerModel.play('hit')

            return task.again

    def playAttackAnimation(self):
        self.enemyModel.play('attack', fromFrame=0, toFrame=12)

    def playHitAnimation(self):
        self.enemyModel.play('hit')

    def moveEnemy(self, x, y):
        self.enemyNode.setPos(x, y, .01)

    def handleHealthGlobe(self):
        global dropChanceFactor
        global dropChance
        global maxDropChance

        # if we drop, create health goblet
        chance = dropChanceFactor + dropChance
        if self._scenarioHandlerRef.getHasDDA():
            chance *= self._ddaHandlerRef.healthGobletModifier

        if utils.getD100() <= chance:
            HealthGoblet(self._mainRef, self)
            print 'dropping health goblet'
        # Otherwise, increase dropChance
        else:
            if dropChance + dropChanceFactor <= maxDropChance:
                dropChance += dropChanceFactor

    def suicide(self):
        print('suicide: ', self)
        # Remove AI behavior
        self.enemyAIBehaviors.removeAi('all')

        # Remove enemy picker sphere (handlerQueue)
        self.pickerNode.removeNode()

        taskMgr.add(self.removeCorpse, 'removeCorpseTask')

    def onDeath(self):
        if self.getIsDead():
            # Remove AI behavior
            self.enemyAIBehaviors.removeAi('all')

            # Award the player exp
            self._playerRef.receiveEXP(self.expAward)

            # Remove enemy picker sphere (handlerQueue)
            self.pickerNode.removeNode()

            # Change state
            self.request('Death')

            # Increase DDA death count
            if self._scenarioHandlerRef.getHasDDA():
                self._ddaHandlerRef.enemyDeathCount += 1

            # Handle health globe
            self.handleHealthGlobe()

            # Remove enemy corpse and clean up
            taskMgr.doMethodLater(self._removeCorpseDelay, self.removeCorpse,
                                  'removeCorpseTask')

    def removeCorpse(self, task):
        # Remove enemy collision sphere (pusher)
        self.sphereNode.removeNode()

        # Stop the collision pusher
        self.collPusher = None

        # Remove enemy from enemyList
        self._enemyListRef.remove(self)

        # Cleanup the enemy model
        self.enemyModel.cleanup()
        self.enemyModel.delete()

        # Cleanup FSM
        self.cleanup()

        # Remove the enemy node
        self.enemyNode.removeNode()
        #self.topEnemyNode.removeNode()

        # Remove enemy updater tasks
        taskMgr.remove(self.enemyUpdaterTask)

        # Remove the passive regeneration task (from Unit class)
        self.removePassiveRegeneration()

        # Remove references
        self._mainRef = None
        self._playerRef = None
        self._AIworldRef = None
        self._enemyListRef = None
        self._stateHandlerRef = None

        return task.done
示例#23
0
文件: Player.py 项目: czorn/Modifire
class Player(DirectObject):
    
    #----------------
    # Initialization
    #----------------
    
    def __init__(self):
        self.pNode = render.attachNewNode('playerRoot')     # The root node of the player
        self.eyeHeight = 1.5                                # The z height of the camera
        self.selectedBlock = 0
        self.adjacentBlock = 0
        self.selectedPlayer = None
        self.playerState = PlayerState(self)
        self.inputBuffer = InputBuffer()
        self.currentItem = None
        self.itemModels = {}
        self.playerModel = None
        
        # The bounding box of the player for collision with environment geometry
        self.boundingBoxCenterNode = self.pNode.attachNewNode('bboxCenter')
        self.boundingBoxCenterNode.setPos(0, 0, 0.9)
        self.boundingBox = BoundingBox(self.boundingBoxCenterNode, [0.2, 0.2, 0.9])
        
        self.animFSM = PlayerAnimationFSM(self)
        self.animFSM.request('Idle')
        
        self.camNode = self.pNode.attachNewNode('cam')      # The position of the player's eyes
        self.camNode.setPos(0, 0, self.eyeHeight)
        
        self.playerParent = self.pNode.attachNewNode('playerParent')
        
        # Change this back so items follow player turning
        #self.itemNode = self.playerParent.attachNewNode('3rdPersonItem')
        self.itemNode = self.pNode.attachNewNode('3rdPersonItem')
        self.itemNode.setPos(0, 0, 1.2)
        
        self.camItemNode = self.camNode.attachNewNode('1stPersonItem')
        
        # Node for name text
        self.nameText = None
        self.nameNode = self.pNode.attachNewNode('NameNode')
        self.nameNode.setPos(0, 0, 1.97)
        
        self.lookingRayNode = self.pNode.attachNewNode('lookingRayNode')
        self.lookingRayNode.setPos(0, 0, self.eyeHeight)
        
        lookingSeg = CollisionSegment(0, 0, 0, 0, 100, 0)
        self.lookingRay = self.lookingRayNode.attachNewNode(CollisionNode('lookingRay'))
        self.lookingRay.node().addSolid(lookingSeg)
        self.lookingRay.node().setFromCollideMask(Globals.BLOCK_PICKER_BITMASK | Globals.PLAYER_BITMASK)
        self.lookingRay.node().setIntoCollideMask(BitMask32.allOff())
        
        self.lookingRayCollisionEntry = None
        
        self.pickerCollisionHandler = CollisionHandlerQueue()
        self.pickerTraverser = CollisionTraverser('pickerTraverser')
        self.pickerTraverser.addCollider(self.lookingRay, self.pickerCollisionHandler)
        if(not Settings.IS_SERVER):
            self.selectionGeom = SelectionGeom()
        else:
            self.selectionGeom = None
        
        self.CreateCollisionGeoms()
        self.LoadModels()
        
    def CreateCollisionGeoms(self):
        self.collisionNode = self.pNode.attachNewNode('CollisionNode')
        
        collisionGeom = self.collisionNode.attachNewNode(CollisionNode("legsPlayer"))
        collisionGeom.node().addSolid(CollisionSphere(0, 0, 0.35, 0.3))
        collisionGeom.node().setFromCollideMask(Globals.ITEM_BITMASK)
        collisionGeom.node().setIntoCollideMask(Globals.PLAYER_BITMASK)
        #collisionGeom.show()
        collisionGeom.setPythonTag(Globals.TAG_COLLISION, Globals.COLLISION_LEG)
        collisionGeom.setPythonTag(Globals.TAG_PLAYER, self)
        
        collisionGeom = self.collisionNode.attachNewNode(CollisionNode("bodyPlayer"))
        collisionGeom.node().addSolid(CollisionSphere(0, 0, 0.9, 0.3))
        collisionGeom.node().setFromCollideMask(BitMask32.allOff())
        collisionGeom.node().setIntoCollideMask(Globals.PLAYER_BITMASK)
        #collisionGeom.show()
        collisionGeom.setPythonTag(Globals.TAG_COLLISION, Globals.COLLISION_BODY)
        collisionGeom.setPythonTag(Globals.TAG_PLAYER, self)
        
        collisionGeom = self.collisionNode.attachNewNode(CollisionNode("headPlayer"))
        collisionGeom.node().addSolid(CollisionSphere(0, 0, 1.45, 0.35))
        collisionGeom.node().setFromCollideMask(BitMask32.allOff())
        collisionGeom.node().setIntoCollideMask(Globals.PLAYER_BITMASK)
        collisionGeom.setPythonTag(Globals.TAG_COLLISION, Globals.COLLISION_HEAD)
        collisionGeom.setPythonTag(Globals.TAG_PLAYER, self)
        
    def CreateNameTextNode(self, name):
        self.nameText = PlayerName(name, self.nameNode)
        
    def RemoveSelectionGeom(self):
        if(self.selectionGeom is not None):
            self.selectionGeom.Destroy()
            self.selectionGeom = None
        
    def LoadModels(self, teamId = Game.SPECTATE):
        if(self.playerModel is not None):
            self.playerModel.cleanup()
        
        if(teamId == Game.TEAM_1):
            self.playerModel = Actor('Assets/Models/Players/ralph',
                                     {"run":"Assets/Models/Players/ralph-run",
                                      "walk":"Assets/Models/Players/ralph-walk"})
        #elif(teamId == Game.TEAM_2):
        else:
            self.playerModel = Actor('Assets/Models/Players/ralph2',
                                     {"run":"Assets/Models/Players/ralph-run",
                                      "walk":"Assets/Models/Players/ralph-walk"})
        self.playerModel.setScale(0.36)
        self.playerModel.reparentTo(self.playerParent)
        self.playerModel.setH(180)
        #self.playerModel.hide()
        
        self.playerModel.enableBlend() 
        self.playerModel.loop('run')
        self.playerModel.pose('walk', 5)
        
#        self.outlineFilter = CommonFilters(base.win, base.cam)
#        if(not self.outlineFilter.setCartoonInk(0.5)):
#            print 'ERROR CARTOON FILTER'
        
    #--------------------
    # Controlling models
    #--------------------
        
    def HidePlayerModel(self):
        self.playerModel.hide()
        
    def ShowPlayerModel(self):
        self.playerModel.show()
        
    def LoopAnimation(self, animation):
        self.playerModel.setPlayRate(1.0, animation)
        self.playerModel.loop(animation)
        
    def RequestFSMTransition(self, animFSMState):
        self.animFSM.request(animFSMState)
        
    #--------------------
    # Updating
    #--------------------
        
    def Update(self, deltaTime):
        if(self.currentItem):
            self.currentItem.IncreaseTimeSinceLastUse(deltaTime)
                
    def UpdateLookingDirection(self, lookingDirection):
        if(not self.playerModel.isHidden() and self.GetPlayerState().GetValue(PlayerState.PLAYING_STATE) == PlayerState.PS_PLAYING):
            facingDirection = Vec3(lookingDirection.getX(), lookingDirection.getY(), 0)
            facingDirection.normalize()
            self.playerParent.lookAt(Point3(facingDirection))
            self.itemNode.lookAt(Point3(self.itemNode.getPos() + lookingDirection))
            
    def UpdateLookingRayDirection(self, lookingDirection):
        self.lookingRayNode.lookAt(Point3(lookingDirection.getX(), lookingDirection.getY(), lookingDirection.getZ() + self.eyeHeight))
    
    def MovePosToPriorSnapshot(self, numFramesBack):
        self.pNode.setPos(self.GetPlayerState().GetValue(PlayerState.POSITION_HISTORY).GetPosition(numFramesBack))
        
    def ReturnToCurrentPosition(self):
        self.pNode.setPos(self.currentPosition)
    
    #-----------------------
    # Weapons / items
    #-----------------------
    
    def OnSelectedItemChangeEvent(self, event):
        if(event.GetItemStack()):
            self.ChangeItem(event.GetItemStack().GetItem())
        else:
            self.ChangeItem(None)
        
    def ChangeItem(self, item):
        print 'CHANGE ITEM curr', self.currentItem, 'new', item, self.GetPlayerState().GetValue(PlayerState.PID)
        
#        if(self.currentItem):
#            self.playerState.UpdateValue(PlayerState.CURRENT_ITEM, self.currentItem.GetItemId())
#        else:
#            self.playerState.UpdateValue(PlayerState.CURRENT_ITEM, ItemId.NoItem)
        
        if(item != self.currentItem):
        
            oldItem = self.currentItem
            self.currentItem = item
                
            if(self.currentItem):
                self.playerState.UpdateValue(PlayerState.CURRENT_ITEM, self.currentItem.GetItemId())
            else:
                self.playerState.UpdateValue(PlayerState.CURRENT_ITEM, ItemId.NoItem)
                
            
            #If both are item objects, equip dequip
            if(self.currentItem and oldItem):
                if(not Settings.IS_SERVER):
                    self.currentItem.LoadContent()
                    self.currentItem.ReparentTo(self.camItemNode)
                self.currentItem.EquipDequip(oldItem)
                
            
            # If just the old item is an obj, dequip it
            elif(oldItem):
                oldItem.Dequip()
                
            # If just the new item is an obj, equip it
            elif(self.currentItem):
                if(not Settings.IS_SERVER):
                    self.currentItem.LoadContent()
                    self.currentItem.ReparentTo(self.camItemNode)
                self.currentItem.Equip()
            
    # Change the item as though this is ourself, but then
    # reparent it so that it shows up properly in 3rd person
    def ThirdPersonChangeItem(self, item):
        self.ChangeItem(item)
        if(item and not Settings.IS_SERVER):
            self.currentItem.ReparentTo(self.itemNode)
            
    def ChangeBlockToPlace(self, direction):
        if(isinstance(self.currentItem, Builder)):
            if(direction > 0):
                self.currentItem.IncreaseBlock()
            else:
                self.currentItem.DecreaseBlock()
                
    def Reload(self):
        if(isinstance(self.currentItem, Firearm)):
            self.currentItem.Reload()
            
            # If we reloaded, tell fire an event
            if(self.GetPlayerState().GetValue(PlayerState.PID) == Globals.MY_PID):
                PlayerReloadEvent(self).Fire()
                
    def OnTeamChange(self, teamId):
        self.GetPlayerState().UpdateValue(PlayerState.TEAM, teamId)
        self.LoadModels(teamId)
        if(self.GetPlayerState().GetValue(PlayerState.PID) == Globals.MY_PID):
            self.HidePlayerModel()
        else:  
            if(teamId != Globals.MY_TEAM):
                self.nameText.reshowOnInView = False
                self.nameText.Hide()
                
            else:
                self.nameText.reshowOnInView = True
                self.ShowNameAboveHead()
                
            self.nameText.SetColor(Globals.TEAM_COLORS[teamId])
        
        #self.nameTextNode.setTextColor(Globals.TEAM_COLORS[teamId])
        
    #------------------
    # Death / Respawn
    #-------------------
    
    def OnDeath(self):
        self.collisionNode.stash()
        LerpHprInterval(self.playerParent, 0.7, (self.playerParent.getH(), 90, self.playerParent.getR())).start()
        self.itemNode.hide()
        self.camItemNode.hide()
        self.GetPlayerState().UpdateValue(PlayerState.PLAYING_STATE, PlayerState.PS_PLAYING_DEAD)
        
        # If this is the actual player
        if(self.GetPlayerState().GetValue(PlayerState.PID) == Globals.MY_PID):
            self.ShowPlayerModel()
            if(isinstance(self.currentItem, Firearm) and self.currentItem.IsADS()):
                self.currentItem.ToggleADS()
        
    def OnRespawn(self):
        self.collisionNode.unstash()
        self.GetInputBuffer().Clear()
        self.itemNode.show()
        self.camItemNode.show()
        self.GetPlayerState().UpdateValue(PlayerState.PLAYING_STATE, PlayerState.PS_PLAYING)
        
        if(self.GetPlayerState().GetValue(PlayerState.PID) == Globals.MY_PID):
            print 'Respawn event for me'
            self.HidePlayerModel()
            SelectedItemChangeEvent(None, ItemStack(self.currentItem)).Fire()
            
        else:
            self.ShowPlayerModel()
            
    #----------------------
    # Accessor / Mutators
    #----------------------
        
    def GetPos(self):
        return self.pNode.getPos()
    
    def SetPos(self, value):
        self.pNode.setPos(value)
        
    def GetZ(self):
        return self.pNode.getZ()
        
    def LerpTo(self, pos):
        LerpPosInterval(self.pNode, 0.1, pos).start()
        
    #---------------------------------------
    # Playernames on screen
    #---------------------------------------
    
    def ShowNameAboveHead(self):
        self.nameText.Show()
        
    def FadeOutNameAboveHead(self, task = None):
        self.nameText.FadeOut()
        
    #---------------------------------------
    # Picking things with looking direction
    #----------------------------------------
        
    #@pstat
    def PerfromLookingRayCollision(self, isSelf = True):
        self.pickerTraverser.traverse(render)
        
        entries = []
        for i in range(self.pickerCollisionHandler.getNumEntries()):
            entry = self.pickerCollisionHandler.getEntry(i)
            entries.append(entry)
            
        numEntries = len(entries)
        
        if(numEntries > 0):
            entries.sort(lambda x,y: cmp(self.DistanceFromCam(x.getSurfacePoint(render)),
                                         self.DistanceFromCam(y.getSurfacePoint(render))))
            
            self.lookingRayCollisionEntry = None
            playerEntry = None
            blockCollisionEntry = None
            
            for i in xrange(numEntries):
                if(entries[i].getIntoNodePath().getParent() != self.collisionNode):
                    target = entries[i].getIntoNodePath().__str__()
                    if(target.endswith('blockCollision')):
                        blockCollisionEntry = entries[i]
                        self.lookingRayCollisionEntry = blockCollisionEntry
                        break
                    elif(target.endswith('Player')):
                        playerEntry = entries[i]
                        self.lookingRayCollisionEntry = playerEntry
                        break
            
            if(blockCollisionEntry and isinstance(self.currentItem, Builder)):
                point = blockCollisionEntry.getSurfacePoint(render)
                
                if(self.DistanceFromCam(point) <= Globals.MAX_SELECT_DISTANCE):
                    
                    norm = blockCollisionEntry.getSurfaceNormal(render)
                    self.adjacentBlock = point + norm * 0.2
                    point -=  norm * 0.2
                    
                    x = point.getX()
                    y = point.getY()
                    z = point.getZ()
                    
                    if(self.selectionGeom):
                        self.selectionGeom.SetPos(int(x), int(y), int(z))
                        self.selectionGeom.Show()
                        self.selectedBlock = self.selectionGeom.GetPos() 
                    else:
                        self.selectedBlock = VBase3(int(x), int(y), int(z))
                else:
                    self.selectedBlock = None
                    self.adjacentBlock = None
                    if(self.selectionGeom):
                        self.selectionGeom.Hide()                
            else:
                self.selectedBlock = None
                self.adjacentBlock = None
                if(self.selectionGeom):
                    self.selectionGeom.Hide()
            
            if(playerEntry):
                player = playerEntry.getIntoNodePath().getPythonTag(Globals.TAG_PLAYER)
                if(player):
                    # Each frame, if the crosshairs are hovering a player, fire the event
                    # so the HUD can respond.
                    PlayerSelectedEvent(player).Fire()
                    self.selectedPlayer = player
                    
#                    # Before, we were only firing on changes
#                    if(self.selectedPlayer != player):
#                        self.selectedPlayer = player
#                        if(not Settings.IS_SERVER and isSelf):
#                            PlayerSelectedEvent(player).Fire()
                            
            else:
                if(self.selectedPlayer != None):
                    self.selectedPlayer = None
                    if(not Settings.IS_SERVER and isSelf):
                        PlayerSelectedEvent(None).Fire()
                
    def DistanceFromCam(self, otherPoint):
        eye = self.camNode.getPos(render)
        return (otherPoint - eye).length()
    
    def GetSelectedBlock(self):
        return self.selectedBlock
    
    def GetAdjacentBlock(self):
        return self.adjacentBlock
    
    def GetPlayerState(self):
        return self.playerState
    
    def GetInputBuffer(self):
        return self.inputBuffer
    
    def GetPlayerOverheadName(self):
        return self.nameText
    
    def GetCurrentItem(self):
        return self.currentItem
        
    #---------------
    # Cleanup
    #---------------
    
    def Destroy(self):
        for child in self.pNode.getChildren():
            child.removeNode()
        self.pNode.removeNode()
        if(self.playerModel):
            self.playerModel.delete()
示例#24
0
class Usuario(object):
    '''
    Usuario
    '''
    def __init__(self, dadosUsuario, principal=False):
        self.key = dadosUsuario['key']
        self.nick = dadosUsuario['nick']
        self.vida_real = float(dadosUsuario['vida_real'])
        self.vida_total = float(dadosUsuario['vida_total'])
        self.mana_real = float(dadosUsuario['mana_real'])
        self.mana_total = float(dadosUsuario['mana_total'])
        self.forca = float(dadosUsuario['forca'])
        self.velocidade = float(dadosUsuario['velocidade'])
        self.velocidade_atack = float(dadosUsuario['velocidade_atack'])

        self.estaMovendo = False
        self.estaRodando = False

        self.__task_name = "Task Usuario - " + self.key

        self.keyMap = {
            TECLA_esquerda: EVENT_up,
            TECLA_direita: EVENT_up,
            TECLA_frente: EVENT_up,
            TECLA_traz: EVENT_up
        }

        pandaFileModelo = get_path_modelo("ralph")
        pandaFileAnimacaoRun = get_path_animacao("ralph-run")
        pandaFileAnimacaoWalk = get_path_animacao("ralph-walk")

        self.modelo = Actor(pandaFileModelo, {
            "run": pandaFileAnimacaoRun,
            "walk": pandaFileAnimacaoWalk
        })
        self.modelo.reparentTo(render)
        self.modelo.setScale(SCALE_MODELOS)

        self.set_pos((float(dadosUsuario['x']), float(dadosUsuario['y']),
                      float(dadosUsuario['z'])))
        self.set_h(float(dadosUsuario['h']))

        if not principal:
            self.text = Text(parent=self.modelo,
                             pos=(0, 0, 5.5),
                             scale=.5,
                             align='center',
                             cor=COR_VERDE,
                             text=self.nick)

            self.text.billboardEffect()

        self.__setup_collision()

        taskMgr.add(self.__task_movimentacao, self.__task_name, sort=1)

    def get_x(self):
        return self.modelo.getX()

    def get_y(self):
        return self.modelo.getY()

    def get_z(self):
        return self.modelo.getZ()

    def get_h(self):
        return self.modelo.getH()

    def get_pos(self):
        return self.modelo.getPos()

    def set_x(self, x):
        self.modelo.setX(x)

    def set_y(self, y):
        self.modelo.setY(y)

    def set_z(self, z):
        self.modelo.setZ(z)

    def set_h(self, h):
        self.modelo.setH(h)

    def set_pos(self, pos):
        self.modelo.setPos(pos)

    def delete(self):
        taskMgr.remove(self.__task_name)

        self.modelo.delete()

    def __setup_collision(self):
        #Colisao
        self.cTrav = CollisionTraverser('usuarioTraverser')

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 5)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.modelo.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()

        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        #self.ralphGroundColNp.show()
        #self.cTrav.showCollisions(render)
        #Colisao

    def __task_movimentacao(self, task):
        dt = globalClock.getDt()
        startpos = self.modelo.getPos()

        #movimentos usuario modelo
        if self.keyMap[TECLA_esquerda] == EVENT_down and self.keyMap[
                TECLA_direita] == EVENT_up:
            self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt))

            if not self.estaRodando:
                self.estaRodando = True

        elif self.keyMap[TECLA_direita] == EVENT_down and self.keyMap[
                TECLA_esquerda] == EVENT_up:
            self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt) * -1)

            if not self.estaRodando:
                self.estaRodando = True

        elif self.estaRodando:
            self.estaRodando = False

        if self.keyMap[TECLA_frente] == EVENT_down and self.keyMap[
                TECLA_traz] == EVENT_up:
            self.modelo.setY(self.modelo, ((self.velocidade * 2) * dt) * -1)

            if self.estaMovendo is False:
                self.modelo.loop("run")
                self.estaMovendo = True

        elif self.keyMap[TECLA_traz] == EVENT_down and self.keyMap[
                TECLA_frente] == EVENT_up:
            self.modelo.setY(self.modelo, (self.velocidade * dt))

            if self.estaMovendo is False:
                self.modelo.loop("walk")
                self.estaMovendo = True

        elif self.estaMovendo:
            self.modelo.stop()
            self.modelo.pose("walk", 5)
            self.estaMovendo = False
        #movimentos usuario modelo

        if self.estaMovendo:

            self.cTrav.traverse(render)

            if self.ralphGroundHandler.getNumEntries() == 1:
                entry = self.ralphGroundHandler.getEntry(0)
                if entry.getIntoNode().getName() == "terrain":
                    self.modelo.setZ(entry.getSurfacePoint(render).getZ())
            else:
                self.modelo.setPos(startpos)

        return task.cont
class Creep(object):
	def __init__(self, showbase, midPoints, positionInList):
		self.showbase = showbase
		self.startHp = 50
		self.totalHp = int(self.startHp * ( (self.showbase.level/4.0) +
										(self.showbase.level*0.1) 
									  ))
		self.showbase.totalHp = self.totalHp
		#CurrentHp that will be updated and used as value in hpBar
		self.hp = self.totalHp
		self.midPoints = midPoints
		self.end = midPoints[len(self.midPoints)-1][len(self.midPoints[0])-1]
		#Get just X and Y
		self.end = (self.end[0], self.end[1])
		self.position = positionInList
		self.start = midPoints[0][0]
		self.creep = Actor("models/panda-model",
								{"walk": "models/panda-walk4"})
		self.creep.setPos(self.start)
		self.creep.setScale(Point3(0.005,0.005,0.005))
		self.hpBar = DirectWaitBar(text = "", range = 100, value = 100)
		self.hpBar.setScale(Point3(2.5, 4, 4))
		self.hpBar.lookAt(0,0,-1)
		#Starts off running normal speed, not slowed
		self.isSlowed = False
		#For if another slow is overlapping
		self.overlapSlow = False
		#Make sure the value of hpBar shows
		self.hpBar.setDepthTest(False)
		self.hpBar.setDepthWrite(False)
		
	#Spanws the creep and its hpBar
	def spawn(self):
		self.creep.reparentTo(self.showbase.render)
		self.hpBar.reparentTo(self.showbase.render)
	
	#Makes the hpBar follow the creep
	#
	#Tried to, instead, make it reparent to self.creep
	#rather than self.showbase.render
	#So I didn't have to constantly update its position
	#But it didn't display when I tried this
	def showHpBar(self, task):
		x = self.creep.getPos()[0]
		y = self.creep.getPos()[1]
		z = self.creep.getPos()[2]
		self.hpBar.setPos(Point3(
								x,
								y+3,
								z+1))
		#Creep has reached the end
		if ( int(x), int(y) ) == self.end:
			self.remove()
		return Task.cont
	def hit(self, damage):
		self.hp -= damage
		if self.isDead():
			self.kill()
		#Update as a percentage of 100 (initial hpBar range is 100)
		self.hpBar.update(int((self.hp*100.0)/(self.totalHp)))
	def isDead(self):
		if self.hp <= 0: #Dead
			return True
		return False
	#Killed by towers, counts as kill
	def kill(self):
		#Remove the creep & hpBar from the screen
		self.creep.delete()
		self.hpBar.removeNode()
		#Set the value of this creep in the list of all creeps to 0
		self.showbase.creeps[self.position] = 0
		#Every five levels, double the gold
		self.showbase.gold += (1+(self.showbase.level/5)) #Either 1 or 2
		if self.showbase.displayGameInfoNode1 != None:
			self.showbase.displayGameInfoNode1.destroy()
		self.showbase.displayGameInfoNode.destroy()
		self.showbase.displayGameInfo()
	#Reached end of board, does not count as kill
	def remove(self):
		#Remove the creep & hpBar from the screen
		self.creep.delete()
		self.hpBar.removeNode()
		#Set the value of this creep in the list of all creeps to 0
		self.showbase.creeps[self.position] = 0
		self.showbase.lives -= 1
		if self.showbase.displayGameInfoNode1 != None:
			self.showbase.displayGameInfoNode1.destroy()
		self.showbase.displayGameInfoNode.destroy()
		self.showbase.displayGameInfo()
		#No more lives left, game over
		if self.showbase.lives == 0:
			self.showbase.displayGameOver()
			sys.exit()
	def move(self, path):
		self.pathSequence = Sequence()
		for i in xrange(len(path)-1):
			step = self.creep.posInterval(
											.4,
											path[i+1],
											startPos = path[i]
											)
			self.pathSequence.append(step)
		self.pathSequence.start()
	def slow(self):
		self.pathSequence.setPlayRate(0.4)
	def resume(self):
		self.pathSequence.setPlayRate(1)
	def getPosition(self):
		return self.creep.getPos()
	def getTotalHp(self):
		return self.totalHp
示例#26
0
class Usuario(object):
    """
    Usuario
    """

    def __init__(self, dadosUsuario, principal=False):
        self.key = dadosUsuario["key"]
        self.nick = dadosUsuario["nick"]
        self.vida_real = float(dadosUsuario["vida_real"])
        self.vida_total = float(dadosUsuario["vida_total"])
        self.mana_real = float(dadosUsuario["mana_real"])
        self.mana_total = float(dadosUsuario["mana_total"])
        self.forca = float(dadosUsuario["forca"])
        self.velocidade = float(dadosUsuario["velocidade"])
        self.velocidade_atack = float(dadosUsuario["velocidade_atack"])

        self.estaMovendo = False
        self.estaRodando = False

        self.__task_name = "Task Usuario - " + self.key

        self.keyMap = {TECLA_esquerda: EVENT_up, TECLA_direita: EVENT_up, TECLA_frente: EVENT_up, TECLA_traz: EVENT_up}

        pandaFileModelo = get_path_modelo("ralph")
        pandaFileAnimacaoRun = get_path_animacao("ralph-run")
        pandaFileAnimacaoWalk = get_path_animacao("ralph-walk")

        self.modelo = Actor(pandaFileModelo, {"run": pandaFileAnimacaoRun, "walk": pandaFileAnimacaoWalk})
        self.modelo.reparentTo(render)
        self.modelo.setScale(SCALE_MODELOS)

        self.set_pos((float(dadosUsuario["x"]), float(dadosUsuario["y"]), float(dadosUsuario["z"])))
        self.set_h(float(dadosUsuario["h"]))

        if not principal:
            self.text = Text(
                parent=self.modelo, pos=(0, 0, 5.5), scale=0.5, align="center", cor=COR_VERDE, text=self.nick
            )

            self.text.billboardEffect()

        self.__setup_collision()

        taskMgr.add(self.__task_movimentacao, self.__task_name, sort=1)

    def get_x(self):
        return self.modelo.getX()

    def get_y(self):
        return self.modelo.getY()

    def get_z(self):
        return self.modelo.getZ()

    def get_h(self):
        return self.modelo.getH()

    def get_pos(self):
        return self.modelo.getPos()

    def set_x(self, x):
        self.modelo.setX(x)

    def set_y(self, y):
        self.modelo.setY(y)

    def set_z(self, z):
        self.modelo.setZ(z)

    def set_h(self, h):
        self.modelo.setH(h)

    def set_pos(self, pos):
        self.modelo.setPos(pos)

    def delete(self):
        taskMgr.remove(self.__task_name)

        self.modelo.delete()

    def __setup_collision(self):
        # Colisao
        self.cTrav = CollisionTraverser("usuarioTraverser")

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0, 0, 5)
        self.ralphGroundRay.setDirection(0, 0, -1)
        self.ralphGroundCol = CollisionNode("ralphRay")
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.modelo.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()

        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        # self.ralphGroundColNp.show()
        # self.cTrav.showCollisions(render)
        # Colisao

    def __task_movimentacao(self, task):
        dt = globalClock.getDt()
        startpos = self.modelo.getPos()

        # movimentos usuario modelo
        if self.keyMap[TECLA_esquerda] == EVENT_down and self.keyMap[TECLA_direita] == EVENT_up:
            self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt))

            if not self.estaRodando:
                self.estaRodando = True

        elif self.keyMap[TECLA_direita] == EVENT_down and self.keyMap[TECLA_esquerda] == EVENT_up:
            self.modelo.setH(self.modelo, ((self.velocidade * 5) * dt) * -1)

            if not self.estaRodando:
                self.estaRodando = True

        elif self.estaRodando:
            self.estaRodando = False

        if self.keyMap[TECLA_frente] == EVENT_down and self.keyMap[TECLA_traz] == EVENT_up:
            self.modelo.setY(self.modelo, ((self.velocidade * 2) * dt) * -1)

            if self.estaMovendo is False:
                self.modelo.loop("run")
                self.estaMovendo = True

        elif self.keyMap[TECLA_traz] == EVENT_down and self.keyMap[TECLA_frente] == EVENT_up:
            self.modelo.setY(self.modelo, (self.velocidade * dt))

            if self.estaMovendo is False:
                self.modelo.loop("walk")
                self.estaMovendo = True

        elif self.estaMovendo:
            self.modelo.stop()
            self.modelo.pose("walk", 5)
            self.estaMovendo = False
        # movimentos usuario modelo

        if self.estaMovendo:

            self.cTrav.traverse(render)

            if self.ralphGroundHandler.getNumEntries() == 1:
                entry = self.ralphGroundHandler.getEntry(0)
                if entry.getIntoNode().getName() == "terrain":
                    self.modelo.setZ(entry.getSurfacePoint(render).getZ())
            else:
                self.modelo.setPos(startpos)

        return task.cont
示例#27
0
class Personaje:

    # suelo
    SueloNulo = 0
    SueloGenerico = 1
    SueloEscalera = 2
    SueloPendienteSubida = 3
    SueloPendienteBajada = 4

    #    # estados
    EstadoNulo = 0
    EstadoQuieto = 1
    EstadoClaseDerivadaBase = 100

    # parametros de estados
    ParamEstadoNulo = 0

    def __init__(self, clase):
        # variables internas
        self._suelo = self.SueloNulo
        self._partes_actor = list()  # [] | [nombre_parte, ...]
        self._estado_capa = [self.EstadoNulo,
                             self.EstadoNulo]  # [estado,estado]
        self._params_estado = Personaje.ParamEstadoNulo
        self._altura = 0.0
        self._velocidad_lineal = LVector3()
        self._velocidad_angular = LVector3()  # grados
        self._ajuste_altura = 0.0
        # variables externas
        self.altitud_suelo = 0.0
        self.altitud_agua = 0.0
        self.contactos = None  # |list [BulletContact,...]
        self.objetos_estados = dict()  # {Estado:NodePath,...}
        # parametros
        self.directorio_recursos = "personajes"
        self.clase = clase
        self.prefijo_cuerpo_suelo = "cuerpo_suelo_"
        self.prefijo_cuerpo_personaje = "cuerpo_personaje_"
        self.rapidez_caminar = 1.0  # multiplicador
        self.rapidez_correr = 2.0  # multiplicador
        # referencias
        self.sistema = None
        self.input_mapper = None
        self.bullet_world = None
        # componentes
        self.cuerpo = None
        self.actor = None

    def iniciar(self, parent_node_path, bullet_world, partes=list()):
        log.info("iniciar")
        # sistema
        self.sistema = Sistema.obtener_instancia()
        # recursos
        ruta_dir = os.path.join(os.getcwd(), self.directorio_recursos,
                                self.clase)
        if not os.path.exists(ruta_dir):
            raise Exception("no existe el directorio '%s'" % (ruta_dir))
        archivos = [
            archivo for archivo in os.listdir(ruta_dir)
            if archivo[-4:].lower() == ".egg" or archivo[-4:].lower() == ".bam"
        ]
        archivo_actor = ""
        dict_animaciones = dict()
        for archivo in archivos:
            if archivo[:-4] == "actor":
                archivo_actor = archivo
            else:
                dict_animaciones[archivo[:-4]] = Filename.fromOsSpecific(
                    os.path.join(ruta_dir, archivo))
        if archivo_actor == "":
            raise Exception(
                "no se encontró ningún archivo de actor (actor.[egg|bam]) en '%s'"
                % ruta_dir)
        # cuerpo
        self.bullet_world = bullet_world
        rb = self._generar_cuerpo_fisica()
        self.bullet_world.attach(rb)
        self.cuerpo = parent_node_path.attachNewNode(rb)
        self.cuerpo.setCollideMask(BitMask32.bit(2))
        # actor
        self.actor = Actor(
            Filename.fromOsSpecific(os.path.join(ruta_dir, archivo_actor)),
            dict_animaciones)
        self.actor.reparentTo(self.cuerpo)
        self.actor.setZ(-self._ajuste_altura)
        # partes
        for parte in partes:
            self.actor.makeSubpart(parte[0], parte[1], parte[2])
            self._partes_actor.append(parte[0])
        # shader
        GestorShader.aplicar(self.actor, GestorShader.ClasePersonaje, 2)

    def terminar(self):
        log.info("terminar")
        self.sistema = None
        self.actor.delete()
        self.bullet_world.remove(self.cuerpo.node())
        self.actor = None
        self.cuerpo = None
        self.input_mapper = None
        self.bullet_world = None

    def setPos(self, posicion):
        _posicion = Vec3(posicion[0], posicion[1],
                         posicion[2] + self._ajuste_altura)
        self.cuerpo.setPos(_posicion)

    def chequear_estado(self, estado, idx_capa):
        if idx_capa == 1:  # capa 1
            return (self._estado_capa[1] & estado) == estado
        elif idx_capa == 0:  # capa 0
            return estado == self._estado_capa[0]

    def update(self, dt):
        if self._estado_capa[0] != Personaje.EstadoQuieto:
            # altitud suelo
            self.altitud_suelo = self.sistema.obtener_altitud_suelo(
                self.cuerpo.getPos())
            # definir ambiente y suelo
            self._definir_suelo()
            # altura desde el suelo (se encuentra al final para ser evaluada en forma porterior)
            self._altura = self.cuerpo.getZ(
            ) - self.altitud_suelo - self._ajuste_altura  #|0.5
        # definir estados
        for idx_capa in range(len(self._estado_capa)):
            estado_nuevo = self._definir_estado(idx_capa)
            if self._estado_capa[idx_capa] != estado_nuevo:
                # procesar cambio de estado
                self._cambio_estado(idx_capa, self._estado_capa[idx_capa],
                                    estado_nuevo)
                self._estado_capa[idx_capa] = estado_nuevo
        # verificar cambio de parametros
        param_estado_nuevo = self.input_mapper.parametros
        if self._params_estado != param_estado_nuevo:
            # procesar cambio en parametros
            self._cambio_params(self._params_estado, param_estado_nuevo)
            self._params_estado = param_estado_nuevo
        # procesar estados
        self._procesar_estados(dt)
        # contactos
        self._procesar_contactos()

    def obtener_info(self):
        info = "Personaje:BulletRigidBodyNode vl=%s va=%s\n" % (
            str(self.cuerpo.node().getLinearVelocity()),
            str(self.cuerpo.node().getAngularVelocity()))
        info += "velocidad_lineal=%s velocidad_angular=%s\n" % (str(
            self._velocidad_lineal), str(self._velocidad_angular))
        info += "posicion=%s altitud_suelo=%s altura=%s\n" % (str(
            self.cuerpo.getPos()), str(self.altitud_suelo), str(self._altura))
        info += "ambiente=? suelo=%s\n" % (str(self._suelo))
        info += "estado=%s params=%s\n" % (str(
            self._estado_capa), str(self._params_estado))
        if self.contactos:
            info += "contactos=%s\n" % (str(
                [c.getNode1().getName() for c in self.contactos]))
        if len(self.objetos_estados) > 0:
            info += "objetos_estados=%s\n" % ("; ".join([
                "%i %s" % (e, np.getName())
                for e, np in self.objetos_estados.items()
            ]))
        return info

    def _definir_suelo(self):
        if self._suelo != Personaje.SueloNulo and self._altura > 0.5:
            self._suelo = Personaje.SueloNulo
        elif self._suelo == Personaje.SueloNulo and self._altura < 0.05:
            self._suelo = Personaje.SueloGenerico

    def _generar_cuerpo_fisica(self):
        log.warning("_generar_cuerpo_fisica no implementado (%s)" % self.clase)
        return None

    def _definir_estado(self, idx_capa):
        log.warning("_definir_estado no implementado (%s)" % self.clase)
        pass

    def _cambio_estado(self, idx_capa, estado_previo, estado_nuevo):
        log.warning("_cambio_estado no implementado (%s)" % self.clase)

    def _cambio_params(self, params_previos, params_nuevos):
        log.warning("_cambio_params no implementado (%s)" % self.clase)
        pass

    def _procesar_estados(self, dt):
        log.warning("_procesar_estados no implementado (%s)" % self.clase)
        pass

    def _procesar_contactos(self):
        log.warning("_procesar_contactos no implementado (%s)" % self.clase)
        pass

    def _contacto_iniciado(self, contacto):
        log.debug("_contacto_iniciado %s %s" %
                  (self.clase, contacto.getNode1().getName()))
        log.warning("_contacto_iniciado no implementado (%s)" % self.clase)
        pass

    def _contacto_finalizado(self, contacto):
        log.debug("_contacto_finalizado %s %s" %
                  (self.clase, contacto.getNode1().getName()))
        log.warning("_contacto_finalizado no implementado (%s)" % self.clase)
        pass

    def _agarrar(self):
        log.warning("_agarrar no implementado (%s)" % self.clase)
        return False

    def _soltar(self):
        log.warning("_soltar no implementado (%s)" % self.clase)
        return False

    def _usar(self, nodo_objeto):
        log.warning("_usar no implementado (%s)" % self.clase)
        return False
示例#28
0
class DistributedPartyFireworksActivity(DistributedPartyActivity,
                                        FireworkShowMixin):
    notify = directNotify.newCategory('DistributedPartyFireworksActivity')

    def __init__(self, cr):
        DistributedPartyFireworksActivity.notify.debug('__init__')
        DistributedPartyActivity.__init__(self,
                                          cr,
                                          ActivityIds.PartyFireworks,
                                          ActivityTypes.HostInitiated,
                                          wantLever=True)
        FireworkShowMixin.__init__(self,
                                   restorePlaygroundMusic=True,
                                   startDelay=FireworksPostLaunchDelay)

    def setEventId(self, eventId):
        DistributedPartyFireworksActivity.notify.debug(
            'setEventId( %s )' % FireworkShows.getString(eventId))
        self.eventId = eventId

    def setShowStyle(self, showStyle):
        DistributedPartyFireworksActivity.notify.debug('setShowStyle( %d )' %
                                                       showStyle)
        self.showStyle = showStyle

    def setSongId(self, songId):
        self.songId = songId

    def load(self):
        DistributedPartyFireworksActivity.notify.debug('load')
        DistributedPartyActivity.load(self)
        self.eventId = PartyGlobals.FireworkShows.Summer
        self.launchPadModel = loader.loadModel(
            'phase_13/models/parties/launchPad')
        self.launchPadModel.setH(90.0)
        self.launchPadModel.setPos(0.0, -18.0, 0.0)
        self.launchPadModel.reparentTo(self.root)
        railingsCollection = self.launchPadModel.findAllMatches(
            '**/launchPad_mesh/*railing*')
        for i in xrange(railingsCollection.getNumPaths()):
            railingsCollection[i].setAttrib(
                AlphaTestAttrib.make(RenderAttrib.MGreater, 0.75))

        leverLocator = self.launchPadModel.find('**/RocketLever_locator')
        self.lever.setPosHpr(Vec3.zero(), Vec3.zero())
        self.lever.reparentTo(leverLocator)
        self.toonPullingLeverInterval = None
        self.sign.reparentTo(
            self.launchPadModel.find('**/launchPad_sign_locator'))
        self.rocketActor = Actor(
            'phase_13/models/parties/rocket_model',
            {'launch': 'phase_13/models/parties/rocket_launch'})
        rocketLocator = self.launchPadModel.find('**/rocket_locator')
        self.rocketActor.reparentTo(rocketLocator)
        self.rocketActor.node().setBound(OmniBoundingVolume())
        self.rocketActor.node().setFinal(True)
        effectsLocator = self.rocketActor.find('**/joint1')
        self.rocketExplosionEffect = RocketExplosion(effectsLocator,
                                                     rocketLocator)
        self.rocketParticleSeq = None
        self.launchSound = base.loader.loadSfx(
            'phase_13/audio/sfx/rocket_launch.ogg')
        self.activityFSM = FireworksActivityFSM(self)
        self.activityFSM.request('Idle')
        return

    def unload(self):
        DistributedPartyFireworksActivity.notify.debug('unload')
        taskMgr.remove(self.taskName('delayedStartShow'))
        if self.rocketParticleSeq:
            self.rocketParticleSeq.pause()
            self.rocketParticleSeq = None
        self.launchPadModel.removeNode()
        del self.launchPadModel
        del self.toonPullingLeverInterval
        self.rocketActor.delete()
        self.rocketExplosionEffect.destroy()
        self.activityFSM.request('Disabled')
        del self.rocketActor
        del self.launchSound
        del self.activityFSM
        del self.eventId
        del self.showStyle
        DistributedPartyActivity.unload(self)
        return

    def _leverPulled(self, collEntry):
        DistributedPartyFireworksActivity.notify.debug('_leverPulled')
        hostPulledLever = DistributedPartyActivity._leverPulled(
            self, collEntry)
        if self.activityFSM.getCurrentOrNextState() == 'Active':
            self.showMessage(TTLocalizer.PartyFireworksAlreadyActive)
        elif self.activityFSM.getCurrentOrNextState() == 'Disabled':
            self.showMessage(TTLocalizer.PartyFireworksAlreadyDone)
        elif self.activityFSM.getCurrentOrNextState() == 'Idle':
            if hostPulledLever:
                base.cr.playGame.getPlace().fsm.request('activity')
                self.toonPullingLeverInterval = self.getToonPullingLeverInterval(
                    base.localAvatar)
                self.toonPullingLeverInterval.append(
                    Func(self.d_toonJoinRequest))
                self.toonPullingLeverInterval.append(
                    Func(base.cr.playGame.getPlace().fsm.request, 'walk'))
                self.toonPullingLeverInterval.start()
            else:
                self.showMessage(TTLocalizer.PartyOnlyHostLeverPull)

    def setState(self, newState, timestamp):
        DistributedPartyFireworksActivity.notify.debug(
            'setState( newState=%s, ... )' % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        if newState == 'Active':
            self.activityFSM.request(newState, timestamp)
        else:
            self.activityFSM.request(newState)

    def startIdle(self):
        DistributedPartyFireworksActivity.notify.debug('startIdle')

    def finishIdle(self):
        DistributedPartyFireworksActivity.notify.debug('finishIdle')

    def startActive(self, showStartTimestamp):
        DistributedPartyFireworksActivity.notify.debug('startActive')
        messenger.send(FireworksStartedEvent)
        timeSinceStart = globalClockDelta.localElapsedTime(showStartTimestamp)
        if timeSinceStart > self.rocketActor.getDuration('launch'):
            self.rocketActor.hide()
            if timeSinceStart < 60:
                self.startShow(self.eventId, self.showStyle, self.songId,
                               showStartTimestamp)
        else:
            self.rocketActor.play('launch')
            self.rocketParticleSeq = Sequence(
                Wait(RocketSoundDelay), Func(base.playSfx, self.launchSound),
                Func(self.rocketExplosionEffect.start),
                Wait(RocketDirectionDelay),
                LerpHprInterval(self.rocketActor, 4.0, Vec3(0, 0, -60)),
                Func(self.rocketExplosionEffect.end),
                Func(self.rocketActor.hide))
            self.rocketParticleSeq.start()
            taskMgr.doMethodLater(FireworksPostLaunchDelay,
                                  self.startShow,
                                  self.taskName('delayedStartShow'),
                                  extraArgs=[
                                      self.eventId, self.showStyle,
                                      self.songId, showStartTimestamp,
                                      self.root
                                  ])

    def finishActive(self):
        self.rocketParticleSeq = None
        DistributedPartyFireworksActivity.notify.debug('finishActive')
        messenger.send(FireworksFinishedEvent)
        taskMgr.remove(self.taskName('delayedStartShow'))
        FireworkShowMixin.disable(self)
        return

    def startDisabled(self):
        DistributedPartyFireworksActivity.notify.debug('startDisabled')
        if not self.rocketActor.isEmpty():
            self.rocketActor.hide()

    def finishDisabled(self):
        DistributedPartyFireworksActivity.notify.debug('finishDisabled')

    def handleToonDisabled(self, toonId):
        self.notify.warning('handleToonDisabled no implementation yet')
示例#29
0
class Digger(enemy.Enemy):

    def __init__(self, mainRef):
        enemy.Enemy.__init__(self, mainRef, enemy.koboldSkirmisher) # Change to correct kobold

        self.holeModel = None

    def initAttributes(self, attributes):
        super(Digger, self).initAttributes(attributes)

        rangeMultiplier = 1.5
        self.combatRange *= rangeMultiplier
        self.perceptionRange *= rangeMultiplier

    def loadEnemyModel(self, modelName):
        modelPrefix = 'models/digger-'
        self.enemyModel = Actor(modelPrefix + 'model', {
                'attack1':modelPrefix+'attack1',
                'attack2':modelPrefix+'attack2',
                'attack3':modelPrefix+'attack3',
                'attack4':modelPrefix+'attack4',
                'special-attack':modelPrefix+'special-attack',

                'pursue':modelPrefix+'pursue',
                'pursue-to-idle':modelPrefix+'pursue-stop',

                'idle-walk':modelPrefix+'idle-walk',
                'idle-walk-to-pursue':modelPrefix+'idle-walk-to-pursue',
                'idle-walk-to-dig':modelPrefix+'idle-walk-to-dig',
                'idle-walk-to-dig-to-sleep':modelPrefix+'idle-walk-to-dig-to-sleep',

                'hit1':modelPrefix+'hit1',
                'hit2':modelPrefix+'hit2',

                'death1':modelPrefix+'death1',
                'death2':modelPrefix+'death2',
                'death3':modelPrefix+'death3'
            })
        self.enemyModel.reparentTo(self.enemyNode)

        self.enemyNode.setPos(Point3.zero())

        self.enemyNode.setDepthOffset(-1)

    def enterIdle(self):
        #print 'enemy enterIdle'
        #idleTime = 60.0 * 3.0

        stopEnemy = self.enemyModel.actorInterval('pursue-to-idle', startFrame=0, endFrame=12)
        idleEnemy = self.enemyModel.actorInterval('idle-walk-to-dig', startFrame=0, endFrame=60)
        digHole = Parallel(Func(self.createHole), self.enemyModel.actorInterval('idle-walk-to-dig-to-sleep', startFrame=0, endFrame=120))
        #hideEnemy = Func(self.enemyNode.hide)
        #suicide = Func(self.suicide)

        self.stopSequence = Sequence(stopEnemy, idleEnemy,  digHole)
        self.stopSequence.start()

        self.isSleeping = True

        #taskMgr.doMethodLater(3, self.showEnemy, 'showEnemyTask')

    def showEnemy(self, task):
        if self.state == 'Idle':
            self.enemyNode.show()
        return task.done

    def enterPursue(self):
        #print('enemy enterPursue')
        loopWalkEnemy = Func(self.enemyModel.loop, 'pursue', fromFrame=0, toFrame=24)

        # Only awake enemy if it comes from idle
        if self.isSleeping:
            self.isSleeping = False

            awakeEnemy = self.enemyModel.actorInterval('idle-walk-to-pursue', startFrame=0, endFrame=24)
            self.awakeSequence = Sequence(awakeEnemy, loopWalkEnemy, Func(self.pursuePlayer))
        else:
            self.awakeSequence = Sequence(loopWalkEnemy, Func(self.pursuePlayer))

        self.awakeSequence.start()

    def enterDeath(self):
        #print('enemy enterDeath')
        self.enemyAIBehaviors.removeAi('all')
        randomDeathAnim = 'death' + str(utils.getDX(3))
        self.enemyModel.play(randomDeathAnim, fromFrame=0, toFrame=12)

    def playAttackAnimation(self):
        randomAttackAnim = 'attack' + str(utils.getD4())
        self.enemyModel.play(randomAttackAnim, fromFrame=0, toFrame=12)

    def playHitAnimation(self):
        randomHitAnim = 'hit' + str(utils.getDX(2))
        self.enemyModel.play(randomHitAnim, fromFrame=0, toFrame=12)

    def createHole(self):
        if self.holeModel == None:
            self.holeModel = Actor('models/hole-model',
                                    {'anim':'models/hole-anim'})
            self.holeModel.reparentTo(self._mainRef.mainNode)

            self.holeModel.setPos(self.enemyNode, 0, -.1, 0)

            self.holeModel.play('anim', fromFrame=0, toFrame=120)

            removeHoleDelay = 12
            taskMgr.doMethodLater(removeHoleDelay, self.removeHole, 'removeHoleTask')

    def removeHole(self, task):
        if self.holeModel != None:
            self.holeModel.cleanup()
            self.holeModel.delete()

            self.holeModel = None

        return task.done
示例#30
0
class Enemy(FSM, Unit):

    # Declare private variables
    _enemyActive = False
    _removeCorpseDelay = 2 # seconds before corpse is cleaned

    def __init__(self, mainRef, attributes):
        print("Enemy instantiated")
        Unit.__init__(self)
        FSM.__init__(self, 'playerFSM')

        self._mainRef = mainRef
        self._playerRef = mainRef.player
        self._AIworldRef = mainRef.AIworld
        self._enemyListRef = mainRef.enemyList
        self._ddaHandlerRef = mainRef.DDAHandler
        self._stateHandlerRef = mainRef.stateHandler
        self._scenarioHandlerRef = mainRef.scenarioHandler

        #self.topEnemyNode = mainRef.mainNode.attachNewNode('topEnemyNode')
        self.initEnemyNode(mainRef.mainNode)

        utils.enemyDictionary[self.enemyNode.getName()] = self

        self.loadEnemyModel(attributes.modelName)
        self.initAttributes(attributes)
        self.initEnemyAi()

        self.initEnemyDDA()

        self.initEnemyCollisionHandlers()
        self.initEnemyCollisionSolids()

        #self.request('Idle')
        self.request('Disabled')

        # Start enemy updater task
        self.enemyUpdaterTask = taskMgr.add(self.enemyUpdater, 'enemyUpdaterTask')

    def initEnemyNode(self, parentNode):
        enemyName = 'enemy' + str(len(self._enemyListRef))
        self.enemyNode = parentNode.attachNewNode(enemyName)
        self._enemyListRef.append(self)

    def loadEnemyModel(self, modelName):
        modelPrefix = 'models/' + modelName
        self.enemyModel = Actor(modelPrefix + '-model', {
                'walk':modelPrefix+'-walk',
                'attack':modelPrefix+'-attack',
                'idle':modelPrefix+'-idle',
                'awake':modelPrefix+'-awake',
                'stop':modelPrefix+'-stop',
                'hit':modelPrefix+'-hit',
                'death1':modelPrefix+'-death1',
                'death2':modelPrefix+'-death2'
            })
        self.enemyModel.reparentTo(self.enemyNode)

        self.enemyNode.setPos(Point3.zero())

        self.enemyNode.setDepthOffset(-1)

    def initAttributes(self, attributes):
        perceptionRangeMultiplier = 1.2
        combatRangeMultiplier = .3
        speedMultiplier = .1

        self.strength = attributes.strength
        self.constitution = attributes.constitution
        self.dexterity = attributes.dexterity

        self.mass = attributes.mass
        self.movementSpeed = speedMultiplier * attributes.movementSpeed
        self.perceptionRange = perceptionRangeMultiplier * attributes.perceptionRange
        self.combatRange = combatRangeMultiplier * attributes.combatRange
        self.attackBonus = attributes.attackBonus
        self.damageBonus = attributes.damageBonus
        self.damageRange = attributes.damageRange
        self.initiativeBonus = attributes.initiativeBonus
        self.fixedHealthPoints = attributes.fixedHealthPoints
        self.armorClass = attributes.armorClass

        if attributes.startLevel > 1:
            for i in range(attributes.startLevel-1):
                self.increaseLevel()

        self.expAward = attributes.expAward

        self.initHealth()

    def initEnemyDDA(self):
        if self._scenarioHandlerRef.getHasDDA():
            maxLevelDifference = self._ddaHandlerRef.maxLevelDifference

            # Level enemy up to player's level minus maxLevelDifference
            levelDifference = self._playerRef.level - self.level
            if levelDifference >= maxLevelDifference:
                for i in range (levelDifference-maxLevelDifference):
                    self.increaseLevel()

    def getAttackBonus(self):
        modifier = self.getStrengthModifier() if self.getStrengthModifier() > self.getDexterityModifier() else self.getDexterityModifier()
        ab = self.attackBonus + (self.level / 2) + modifier# + utils.getD20()

        if self._scenarioHandlerRef.getHasDDA():
            attackBonusModifier = self._ddaHandlerRef.attackBonusModifier
            if attackBonusModifier < 0:
                ab -= attackBonusModifier
                if ab < 1:
                    ab = 1

        return ab + utils.getD20()

    def initEnemyAi(self):
        self.enemyAI = AICharacter('enemy',
                                self.enemyNode,
                                self.mass, # Mass
                                0.1, # Movt force
                                self.movementSpeed) # Max force
        self._AIworldRef.addAiChar(self.enemyAI)

        self.enemyAIBehaviors = self.enemyAI.getAiBehaviors()
        #self.enemyAIBehaviors.obstacleAvoidance(1.0)

    def initEnemyCollisionHandlers(self):
        self.groundHandler = CollisionHandlerQueue()
        self.collPusher = CollisionHandlerPusher()

    def initEnemyCollisionSolids(self):
        # Enemy ground ray
        groundRay = CollisionRay(0, 0, 2, 0, 0, -1)
        groundColl = CollisionNode('enemyGroundRay')
        groundColl.addSolid(groundRay)

        groundColl.setIntoCollideMask(BitMask32.allOff())
        groundColl.setFromCollideMask(BitMask32.bit(1))

        self.groundRayNode = self.enemyNode.attachNewNode(groundColl)
        #self.groundRayNode.show()

        base.cTrav.addCollider(self.groundRayNode, self.groundHandler)

        # Enemy collision sphere
        collSphereNode = CollisionNode('enemyCollSphere')
        collSphere = CollisionSphere(0, 0, 0.1, 0.2)
        collSphereNode.addSolid(collSphere)

        collSphereNode.setIntoCollideMask(BitMask32.allOff())
        collSphereNode.setFromCollideMask(BitMask32.bit(2))
        
        self.sphereNode = self.enemyNode.attachNewNode(collSphereNode)
        #sphereNode.show()

        base.cTrav.addCollider(self.sphereNode, self.collPusher)
        self.collPusher.addCollider(self.sphereNode, self.enemyNode)

        # Enemy picker collision sphere
        pickerSphereCollNode = CollisionNode(self.enemyNode.getName())
        pickerCollSphere = CollisionSphere(0, 0, 0, 0.5)
        pickerSphereCollNode.addSolid(pickerCollSphere)

        pickerSphereCollNode.setFromCollideMask(BitMask32.allOff())
        pickerSphereCollNode.setIntoCollideMask(BitMask32.bit(1))

        self.pickerNode = self.enemyNode.attachNewNode(pickerSphereCollNode)
        #sphereNodePath.show()

        # Enemy attack collision sphere
        attackCollSphereNode = CollisionNode(self.enemyNode.getName()+'atkSph')
        attackCollSphere = CollisionSphere(0, 0, 0.1, 0.15)
        attackCollSphereNode.addSolid(attackCollSphere)

        attackCollSphereNode.setIntoCollideMask(BitMask32.bit(3))
        attackCollSphereNode.setFromCollideMask(BitMask32.allOff())

        attackSphereNode = self.enemyNode.attachNewNode(attackCollSphereNode)
        #attackSphereNode.show()

    def slowMovementByPercentage(self, percentage=30, slowDuration=20):
        #print self.enemyNode.getName(), ' slowed by ', percentage, ' %'
        oldSpeed = self.movementSpeed
        newSpeed = ((100.0 - percentage) / 100.0) * oldSpeed

        if newSpeed < 1.0:
            newSpeed = 1.0

        self.movementSpeed = newSpeed

        taskMgr.doMethodLater(slowDuration, self.removeSlowMovement, 'removeSlowMovementTask', extraArgs=[oldSpeed], appendTask=True)

    def removeSlowMovement(self, oldSpeed, task):
        self.movementSpeed = oldSpeed
        return task.done

    def checkGroundCollisions(self):
        if self.groundHandler.getNumEntries() > 0:
            self.groundHandler.sortEntries()
            entries = []
            for i in range(self.groundHandler.getNumEntries()):
                entry = self.groundHandler.getEntry(i)
                #print('entry:', entry)
                entries.append(entry)

            entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                         x.getSurfacePoint(render).getZ()))

            for i in range(len(entries)):
                if entries[i].getIntoNode().getName()[:6] == 'ground':
                    #print('entryFound:', entries[0])
                    newZ = entries[i].getSurfacePoint(base.render).getZ()
                    self.enemyNode.setZ(newZ)
                    #print('enemyZ:', newZ)
                    break;

    def enemyUpdater(self, task):
        if self._stateHandlerRef.state != self._stateHandlerRef.PLAY or not self._enemyActive:
            self.enemyModel.stop()
            # Do not do anything when paused
            return task.cont

        self.checkGroundCollisions()

        if self.getIsDead():
            self.onDeath()
            return task.done

        if self._playerRef.getIsDead():
            return task.cont

        playerPos = self._playerRef.playerNode.getPos()
        enemyPos = self.enemyNode.getPos()

        # If player is within enemy perception range
        if utils.getIsInRange(playerPos, enemyPos, self.perceptionRange):

            # If enemy is not doing anything
            if self.state == 'Idle':
                # Start pursuing
                if self.state != 'Pursue':
                    self.request('Pursue')

            # If enemy is already pursueing
            elif self.state == 'Pursue':
                # If player is within combat range
                if utils.getIsInRange(playerPos, enemyPos, self.combatRange):
                    #print 'enemy go to combat'
                    # Go to combat
                    if self.state != 'Combat':
                        self.request('Combat')

            # If enemy is already in combat
            elif self.state == 'Combat':
                # If player has moved out of combat range
                if not utils.getIsInRange(playerPos, enemyPos, self.combatRange):
                    # Start pursuing
                    if self.state != 'Pursue':
                        self.request('Pursue')

            # If enemy is disabled
            elif self.state == 'Disabled':
                if self.enemyAI.getMaxForce() != self.movementSpeed:
                    self.enemyAI.setMaxForce(self.movementSpeed)

        # If player is not within perception range
        else:
            if self.state != 'Idle':
                self.request('Idle')

        return task.cont

    def pursuePlayer(self):
        taskMgr.add(self.pursue, 'pursueTask')

    def pursue(self, task):
        if self.state == 'Pursue' and not self.getIsDead():
            pitchRoll = self.enemyNode.getP(), self.enemyNode.getR()
            self.enemyNode.headsUp(self._playerRef.playerNode)
            self.enemyNode.setHpr(self.enemyNode.getH()-180, *pitchRoll)

            speed = -self.movementSpeed * globalClock.getDt()
            self.enemyNode.setFluidPos(self.enemyNode, 0, speed, 0)

            return task.cont
        else:
            task.done

    def enterIdle(self):
        #print 'enemy enterIdle'
        stopEnemy = self.enemyModel.actorInterval('stop', loop=0)
        idleEnemy = self.enemyModel.actorInterval('idle', startFrame=0, endFrame=1, loop=0)

        self.stopSequence = Sequence(stopEnemy, idleEnemy)
        self.stopSequence.start()

        self.isSleeping = True

    def exitIdle(self):
        #print('enemy exitIdle')
        self.stopSequence.finish()

    def enterPursue(self):
        #print('enemy enterPursue')
        loopWalkEnemy = Func(self.enemyModel.loop, 'walk', fromFrame=0, toFrame=12)

        # Only awake enemy if it comes from idle
        if self.isSleeping: 
            self.isSleeping = False

            awakeEnemy = self.enemyModel.actorInterval('awake', loop=0)
            self.awakeSequence = Sequence(awakeEnemy, loopWalkEnemy, Func(self.pursuePlayer))
        else:
            self.awakeSequence = Sequence(loopWalkEnemy, Func(self.pursuePlayer))

        self.awakeSequence.start()

    def exitPursue(self):
        #print('enemy exitPursue')
        self.awakeSequence.finish()

    def enterCombat(self):
        #print('enemy enterCombat')
        self.enemyModel.stop()

        attackDelay = self.getInitiativeRoll()
        self.attackTask = taskMgr.doMethodLater(attackDelay, self.attackPlayer, 'attackPlayerTask')

    def enterDisabled(self):
        #print 'enterDisable'
        pass

    def exitDisabled(self):
        #print 'exitDisable'
        pass

    def exitCombat(self):
        #print('enemy exitCombat')
        taskMgr.remove(self.attackTask)

    def enterDeath(self):
        #print('enemy enterDeath')
        self.enemyAIBehaviors.removeAi('all')
        randomDeathAnim = 'death' + str(utils.getD2())
        self.enemyModel.play(randomDeathAnim)


    def attack(self, other):
        if not self.getIsDead() and not other.getIsDead():
            if self.getAttackBonus() >= other.getArmorClass():
                dmg = self.getDamageBonus()
                #print(self.getName(), ' damaged ', other.getName(), ' for ', dmg, ' damage')
                other.receiveDamage(dmg)

                return 2 # Returns 2 when self damages other

            return 1 # Returns 1 when self attacks other, but misses

        return 0 # Returns 0 when either self or other is dead

    def attackPlayer(self, task):
        if self._stateHandlerRef.state != self._stateHandlerRef.PLAY or not self._enemyActive:
            # Do not do anything when paused
            return task.again

        if self._playerRef.getIsDead():
            print('player is already dead')
            self.request('Idle')
            return task.done

        elif self.getIsDead():
            return task.done

        else:
            #print('Attack player!')
            # Make sure enemy is facing player when attacking
            pitchRoll = self.enemyNode.getP(), self.enemyNode.getR()
            self.enemyNode.headsUp(self._playerRef.playerNode)
            self.enemyNode.setHpr(self.enemyNode.getH()-180, *pitchRoll)

            attacked = self.attack(self._playerRef)
            if attacked != 0:
                self.playAttackAnimation()
                if attacked == 2:
                    self._playerRef.playerModel.play('hit')

            return task.again

    def playAttackAnimation(self):
        self.enemyModel.play('attack', fromFrame=0, toFrame=12)

    def playHitAnimation(self):
        self.enemyModel.play('hit')

    def moveEnemy(self, x, y):
        self.enemyNode.setPos(x, y, .01)

    def handleHealthGlobe(self):
        global dropChanceFactor
        global dropChance
        global maxDropChance

        # if we drop, create health goblet
        chance = dropChanceFactor + dropChance
        if self._scenarioHandlerRef.getHasDDA():
            chance *= self._ddaHandlerRef.healthGobletModifier

        if utils.getD100() <= chance:
            HealthGoblet(self._mainRef, self)
            print 'dropping health goblet'
        # Otherwise, increase dropChance
        else:
            if dropChance+dropChanceFactor <= maxDropChance:
                dropChance += dropChanceFactor

    def suicide(self):
        print('suicide: ', self)
        # Remove AI behavior
        self.enemyAIBehaviors.removeAi('all')

        # Remove enemy picker sphere (handlerQueue)
        self.pickerNode.removeNode()

        taskMgr.add(self.removeCorpse, 'removeCorpseTask')

    def onDeath(self):
        if self.getIsDead():
            # Remove AI behavior
            self.enemyAIBehaviors.removeAi('all')

            # Award the player exp
            self._playerRef.receiveEXP(self.expAward)

            # Remove enemy picker sphere (handlerQueue)
            self.pickerNode.removeNode()

            # Change state
            self.request('Death')

            # Increase DDA death count
            if self._scenarioHandlerRef.getHasDDA():
                self._ddaHandlerRef.enemyDeathCount += 1

            # Handle health globe
            self.handleHealthGlobe()

            # Remove enemy corpse and clean up
            taskMgr.doMethodLater(self._removeCorpseDelay, self.removeCorpse, 'removeCorpseTask')

    def removeCorpse(self, task):
        # Remove enemy collision sphere (pusher)
        self.sphereNode.removeNode()

        # Stop the collision pusher
        self.collPusher = None

        # Remove enemy from enemyList
        self._enemyListRef.remove(self)

        # Cleanup the enemy model
        self.enemyModel.cleanup()
        self.enemyModel.delete()

        # Cleanup FSM
        self.cleanup()

        # Remove the enemy node
        self.enemyNode.removeNode()
        #self.topEnemyNode.removeNode()

        # Remove enemy updater tasks
        taskMgr.remove(self.enemyUpdaterTask)

        # Remove the passive regeneration task (from Unit class)
        self.removePassiveRegeneration()

        # Remove references
        self._mainRef = None
        self._playerRef = None
        self._AIworldRef = None
        self._enemyListRef = None
        self._stateHandlerRef = None

        return task.done
示例#31
0
class Cannon:
    def __init__(self, cycle, mount, audio3D):
        self.cycle = cycle
        self.name = "Virtue X-A9 Equalizer"
        self.audio3D = audio3D

        self.actor = Actor("../Models/CannonActor.egg")
        self.model = loader.loadModel("../Models/Cannon.bam")
        self.actor.reparentTo(mount)
        self.model.reparentTo(self.actor)
        self.flashModel = loader.loadModel("../Models/LaserFlash.bam")
        self.projModel = loader.loadModel("../Models/LaserProj.bam")

        self.refNP = self.cycle.trgtrMount.attachNewNode("CannonRefNP")

        self.muzzle = self.actor.exposeJoint(None, "modelRoot", "Muzzle")

        self.audio3D = audio3D
        self.fireSfx = self.audio3D.loadSfx("../Sound/LaserShot.wav")
        self.audio3D.attachSoundToObject(self.fireSfx, self.muzzle)

        reloadTime = 1.5
        self.damage = 75
        self.energyCost = 5
        self.blastR = 10

        self.flashLerp = LerpScaleInterval(self.flashModel, reloadTime * .1,
                                           Point3(2, 2, 2), Point3(.2, .2, .2))

        self.firePar = Parallel(Func(self.checkForHit), Func(self.setEffects),
                                self.flashLerp)

        self.fireSeq = Sequence(self.firePar, Func(self.clearEffects),
                                Wait(reloadTime * .9))

    def fire(self):
        if (self.fireSeq.isPlaying() == False):
            self.fireSeq.start()
            self.fireSfx.play()
            self.cycle.energy -= self.energyCost
        return

    def setEffects(self):
        self.flashModel.reparentTo(self.muzzle)
        self.projModel.reparentTo(self.muzzle)
        self.projModel.lookAt(self.refNP.getPos(self.muzzle))
        self.projModel.setSy(
            trueDist(Point3(0, 0, 0), self.refNP.getPos(self.muzzle)) * 2)
        return

    def clearEffects(self):
        self.flashModel.detachNode()
        self.projModel.detachNode()
        return

    def checkForHit(self):
        self.cycle.trgtrCTrav.traverse(render)
        if (self.cycle.trgtrCHan.getNumEntries() > 0):
            self.cycle.trgtrCHan.sortEntries()
            entry = self.cycle.trgtrCHan.getEntry(0)
            # If collisions were detected sort them nearest to far and pull out the first one.

            colPoint = entry.getSurfacePoint(render)
            self.refNP.setPos(render, colPoint)
            # Get the collision point and the range to the collision.

            boom = Boom(colPoint, self.blastR, self.damage, self.audio3D)
            # Create an explosion at the collision point.

        else:
            self.refNP.setPos(self.cycle.trgtrCNP, 0, 300, 0)
            boom = Boom(self.refNP.getPos(render), self.blastR, self.damage,
                        self.audio3D)
            # If no collision was detected, create a boom at a distant point.

    def destroy(self):
        self.actor.delete()
        self.model.removeNode()
        self.flashModel.removeNode()
        self.projModel.removeNode()
        self.refNP.removeNode()
        self.cycle = None
        self.flashLerp = None
        self.firePar = None
        self.fireSeq = None
        self.audio3D.detachSound(self.fireSfx)
        return
示例#32
0
class DistributedPartyJukeboxActivityBase(DistributedPartyActivity):
    __module__ = __name__
    notify = directNotify.newCategory('DistributedPartyJukeboxActivityBase')

    def __init__(self, cr, actId, phaseToMusicData):
        DistributedPartyActivity.__init__(self, cr, actId,
                                          ActivityTypes.Continuous)
        self.phaseToMusicData = phaseToMusicData
        self.jukebox = None
        self.gui = None
        self.tunes = []
        self.music = None
        self.currentSongData = None
        self.localQueuedSongInfo = None
        self.localQueuedSongListItem = None
        return

    def generateInit(self):
        self.gui = JukeboxGui(self.phaseToMusicData)

    def load(self):
        DistributedPartyActivity.load(self)
        self.jukebox = Actor(
            'phase_13/models/parties/jukebox_model',
            {'dance': 'phase_13/models/parties/jukebox_dance'})
        self.jukebox.reparentTo(self.root)
        self.collNode = CollisionNode(self.getCollisionName())
        self.collNode.setCollideMask(ToontownGlobals.CameraBitmask
                                     | ToontownGlobals.WallBitmask)
        collTube = CollisionTube(0, 0, 0, 0.0, 0.0, 4.25, 2.25)
        collTube.setTangible(1)
        self.collNode.addSolid(collTube)
        self.collNodePath = self.jukebox.attachNewNode(self.collNode)
        self.sign.setPos(-5.0, 0, 0)
        self.activate()

    def unload(self):
        DistributedPartyActivity.unload(self)
        self.gui.unload()
        if self.music is not None:
            self.music.stop()
        self.jukebox.stop()
        self.jukebox.delete()
        self.jukebox = None
        self.ignoreAll()
        return

    def getCollisionName(self):
        return self.uniqueName('jukeboxCollision')

    def activate(self):
        self.accept('enter' + self.getCollisionName(),
                    self.__handleEnterCollision)

    def __handleEnterCollision(self, collisionEntry):
        if base.cr.playGame.getPlace().fsm.getCurrentState().getName(
        ) == 'walk':
            base.cr.playGame.getPlace().fsm.request('activity')
            self.d_toonJoinRequest()

    def joinRequestDenied(self, reason):
        DistributedPartyActivity.joinRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyJukeboxOccupied)

    def handleToonJoined(self, toonId):
        toon = base.cr.doId2do.get(toonId)
        if toon:
            self.jukebox.lookAt(base.cr.doId2do[toonId])
            self.jukebox.setHpr(self.jukebox.getH() + 180.0, 0, 0)
        if toonId == base.localAvatar.doId:
            self.__localUseJukebox()

    def handleToonExited(self, toonId):
        if toonId == base.localAvatar.doId and self.gui.isLoaded():
            self.__deactivateGui()

    def handleToonDisabled(self, toonId):
        self.notify.warning('handleToonDisabled no implementation yet')

    def __localUseJukebox(self):
        base.localAvatar.disableAvatarControls()
        base.localAvatar.stopPosHprBroadcast()
        self.__activateGui()
        self.accept(JukeboxGui.CLOSE_EVENT, self.__handleGuiClose)
        taskMgr.doMethodLater(0.5,
                              self.__localToonWillExitTask,
                              self.uniqueName('toonWillExitJukeboxOnTimeout'),
                              extraArgs=None)
        self.accept(JukeboxGui.ADD_SONG_CLICK_EVENT, self.__handleQueueSong)
        if self.isUserHost():
            self.accept(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT,
                        self.__handleMoveSongToTop)
        return

    def __localToonWillExitTask(self, task):
        self.localToonExiting()
        return Task.done

    def __activateGui(self):
        self.gui.enable(timer=JUKEBOX_TIMEOUT)
        self.gui.disableAddSongButton()
        if self.currentSongData is not None:
            self.gui.setSongCurrentlyPlaying(self.currentSongData[0],
                                             self.currentSongData[1])
        self.d_queuedSongsRequest()
        return

    def __deactivateGui(self):
        self.ignore(JukeboxGui.CLOSE_EVENT)
        self.ignore(JukeboxGui.SONG_SELECT_EVENT)
        self.ignore(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT)
        base.cr.playGame.getPlace().setState('walk')
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.enableAvatarControls()
        self.gui.unload()
        self.__localClearQueuedSong()

    def isUserHost(self):
        return self.party.partyInfo.hostId == base.localAvatar.doId

    def d_queuedSongsRequest(self):
        self.sendUpdate('queuedSongsRequest')

    def queuedSongsResponse(self, songInfoList, index):
        if self.gui.isLoaded():
            for i in range(len(songInfoList)):
                songInfo = songInfoList[i]
                self.__addSongToQueue(songInfo,
                                      isLocalQueue=index >= 0 and i == index)

            self.gui.enableAddSongButton()

    def __handleGuiClose(self):
        self.__deactivateGui()
        self.d_toonExitDemand()

    def __handleQueueSong(self, name, values):
        self.d_setNextSong(values[0], values[1])

    def d_setNextSong(self, phase, filename):
        self.sendUpdate('setNextSong', [(phase, filename)])

    def setSongInQueue(self, songInfo):
        if self.gui.isLoaded():
            phase = sanitizePhase(songInfo[0])
            filename = songInfo[1]
            data = self.getMusicData(phase, filename)
            if data:
                if self.localQueuedSongListItem is not None:
                    self.localQueuedSongListItem['text'] = data[0]
                else:
                    self.__addSongToQueue(songInfo, isLocalQueue=True)
        return

    def __addSongToQueue(self, songInfo, isLocalQueue=False):
        if isLocalQueue:
            isHost = self.isUserHost()
            data = self.getMusicData(sanitizePhase(songInfo[0]), songInfo[1])
            if data:
                listItem = self.gui.addSongToQueue(data[0],
                                                   highlight=isLocalQueue,
                                                   moveToTopButton=isHost)
                self.localQueuedSongInfo = isLocalQueue and songInfo
                self.localQueuedSongListItem = listItem

    def __localClearQueuedSong(self):
        self.localQueuedSongInfo = None
        self.localQueuedSongListItem = None
        return

    def __play(self, phase, filename, length):
        self.music = base.loadMusic((MUSIC_PATH + '%s') % (phase, filename))
        if self.music:
            if self.__checkPartyValidity() and hasattr(
                    base.cr.playGame.getPlace().loader,
                    'music') and base.cr.playGame.getPlace().loader.music:
                base.cr.playGame.getPlace().loader.music.stop()
            base.resetMusic.play()
            self.music.setTime(0.0)
            self.music.setLoopCount(getMusicRepeatTimes(length))
            self.music.play()
            jukeboxAnimControl = self.jukebox.getAnimControl('dance')
            if not jukeboxAnimControl.isPlaying():
                self.jukebox.loop('dance')
            self.currentSongData = (phase, filename)

    def __stop(self):
        self.jukebox.stop()
        self.currentSongData = None
        if self.music:
            self.music.stop()
        if self.gui.isLoaded():
            self.gui.clearSongCurrentlyPlaying()
        return

    def setSongPlaying(self, songInfo, toonId):
        phase = sanitizePhase(songInfo[0])
        filename = songInfo[1]
        if not filename:
            self.__stop()
            return
        data = self.getMusicData(phase, filename)
        if data:
            self.__play(phase, filename, data[1])
            self.setSignNote(data[0])
            if self.gui.isLoaded():
                item = self.gui.popSongFromQueue()
                self.gui.setSongCurrentlyPlaying(phase, filename)
                if item == self.localQueuedSongListItem:
                    self.__localClearQueuedSong()
        if toonId == localAvatar.doId:
            localAvatar.setSystemMessage(0, TTLocalizer.PartyJukeboxNowPlaying)

    def __handleMoveSongToTop(self):
        if self.isUserHost() and self.localQueuedSongListItem is not None:
            self.d_moveHostSongToTopRequest()
        return

    def d_moveHostSongToTopRequest(self):
        self.notify.debug('d_moveHostSongToTopRequest')
        self.sendUpdate('moveHostSongToTopRequest')

    def moveHostSongToTop(self):
        self.notify.debug('moveHostSongToTop')
        if self.gui.isLoaded():
            self.gui.pushQueuedItemToTop(self.localQueuedSongListItem)

    def getMusicData(self, phase, filename):
        data = []
        phase = sanitizePhase(phase)
        phase = self.phaseToMusicData.get(phase)
        if phase:
            data = phase.get(filename, [])
        return data

    def __checkPartyValidity(self):
        if hasattr(base.cr.playGame,
                   'getPlace') and base.cr.playGame.getPlace() and hasattr(
                       base.cr.playGame.getPlace(),
                       'loader') and base.cr.playGame.getPlace().loader:
            return True
        else:
            return False
示例#33
0
class Cog():
    def __init__(self):
        #Define variables to keep track of the current head, body, and department
        self.currentBody = 0
        self.currentHead = 0
        self.currentDept = 0

        #Define a boolean to determine if the cog is in view
        self.isInView = False

        #Establish current file path location
        self.currentDirectory = os.path.abspath(sys.path[0])
        self.pandaDirectory = Filename.fromOsSpecific(
            self.currentDirectory).getFullpath()

        #Create the cog head and body (mainly to allow it to be
        #destroyed later in replacement of the proper body)
        self.cog = Actor(
            self.pandaDirectory +
            '/resources/cogs/models/tt_a_ene_cga_zero.bam', {
                'neutral':
                (self.pandaDirectory +
                 '/resources/cogs/animations/tt_a_ene_cga_neutral.bam'),
                'walk': (self.pandaDirectory +
                         '/resources/cogs/animations/tt_a_ene_cga_walk.bam')
            })
        self.head = loader.loadModel(self.pandaDirectory +
                                     '/resources/cogs/models/suitA-heads.bam')

        #Determine the body type and set the head
        self.determineBody()

    def determineBody(self):
        #Destroy the current body to unrender it
        self.cog.delete()
        self.cog.removeNode()

        #Determine the new cog body type
        if self.currentBody == 0:
            self.cog = Actor(
                self.pandaDirectory +
                '/resources/cogs/models/tt_a_ene_cga_zero.bam', {
                    'neutral':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cga_neutral.bam'),
                    'walk':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cga_walk.bam'),
                    'victory':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cga_victory.bam')
                })
        elif self.currentBody == 1:
            self.cog = Actor(
                self.pandaDirectory +
                '/resources/cogs/models/tt_a_ene_cgb_zero.bam', {
                    'neutral':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cgb_neutral.bam'),
                    'walk':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cgb_walk.bam'),
                    'victory':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cgb_victory.bam')
                })
        elif self.currentBody == 2:
            self.cog = Actor(
                self.pandaDirectory +
                '/resources/cogs/models/tt_a_ene_cgc_zero.bam', {
                    'neutral':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cgc_neutral.bam'),
                    'walk':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cgc_walk.bam'),
                    'victory':
                    (self.pandaDirectory +
                     '/resources/cogs/animations/tt_a_ene_cgc_victory.bam')
                })
        else:
            raise Exception(
                'UH OH! currentBody is not between 0 and 2! The value of currentBody is {}'
                .format(self.currentBody))

        self.cog.reparentTo(render)

        if self.isInView:
            self.cog.loop('neutral')
            self.cog.setPos(6, 2, 0)
            self.cog.setHpr(180, 0, 0)
        else:
            self.resetCogPos()

        #Define the lerp for the cog's movement and animations
        self.walkIn = self.cog.posInterval(2, pos=(6, 2, 0))
        self.walkOut = self.cog.posInterval(2, pos=(15, 2, 0))
        self.turnToCam = self.cog.hprInterval(1, hpr=(180, 0, 0))
        self.turnAway = self.cog.hprInterval(1, hpr=(270, 0, 0))

        #Define the sequences
        #Note: If you want to loop an animation after a sequence plays,
        #you have to append the Func(self.actor.loop, 'animName') to the end of the function.
        self.enterView = Sequence(self.walkIn, self.turnToCam,
                                  Func(self.cog.loop, 'neutral'))
        self.exitView = Sequence(Func(self.cog.loop, 'walk'), self.turnAway,
                                 self.walkOut)

        #Call the other methods to reattach and reapply the head and department textures
        self.determineHead()
        self.determineDept()

    def determineHead(self):
        #Destroy the current head to unrender it
        self.head.removeNode()

        #Set up a boolean to make sure the cog is or isn't a flunky
        hasGlasses = False

        #Determine the cog head type
        if self.currentHead <= 12:
            self.headList = loader.loadModel(
                self.pandaDirectory + '/resources/cogs/models/suitA-heads.bam')

            if self.currentHead == 0:
                self.head = self.headList.find('**/backstabber')
            elif self.currentHead == 1:
                self.head = self.headList.find('**/bigcheese')
            elif self.currentHead == 2:
                self.head = self.headList.find('**/bigwig')
            elif self.currentHead == 3:
                self.head = self.headList.find('**/headhunter')
            elif self.currentHead == 4:
                self.head = self.headList.find('**/legaleagle')
            elif self.currentHead == 5:
                self.head = self.headList.find('**/numbercruncher')
            elif self.currentHead == 6:
                #name dropper
                self.head = self.headList.find('**/numbercruncher')
                self.head.setTexture(loader.loadTexture(self.pandaDirectory + \
                     '/resources/cogs/textures/name-dropper.jpg'), 1)
            elif self.currentHead == 7:
                self.head = self.headList.find('**/pennypincher')
            elif self.currentHead == 8:
                self.head = self.headList.find('**/yesman')
            elif self.currentHead == 9:
                #robber baron
                self.head = self.headList.find('**/yesman')
                self.head.setTexture(loader.loadTexture(self.pandaDirectory + \
                     '/resources/cogs/textures/robber-baron.jpg'), 1)
            elif self.currentHead == 10:
                self.head = self.headList.find('**/twoface')
            elif self.currentHead == 11:
                #mingler
                self.head = self.headList.find('**/twoface')
                self.head.setTexture(loader.loadTexture(self.pandaDirectory + \
                     '/resources/cogs/textures/mingler.jpg'), 1)
            else:
                #double talker
                self.head = self.headList.find('**/twoface')
                self.head.setTexture(loader.loadTexture(self.pandaDirectory + \
                     '/resources/cogs/textures/double-talker.jpg'), 1)

        elif self.currentHead <= 20:
            self.headList = loader.loadModel(
                self.pandaDirectory + '/resources/cogs/models/suitB-heads.bam')

            if self.currentHead == 13:
                self.head = self.headList.find('**/ambulancechaser')
            elif self.currentHead == 14:
                self.head = self.headList.find('**/beancounter')
            elif self.currentHead == 15:
                self.head = self.headList.find('**/loanshark')
            elif self.currentHead == 16:
                self.head = self.headList.find('**/movershaker')
            elif self.currentHead == 17:
                #bloodsucker
                self.head = self.headList.find('**/movershaker')
                self.head.setTexture(loader.loadTexture(self.pandaDirectory + \
                     '/resources/cogs/textures/blood-sucker.jpg'), 1)
            elif self.currentHead == 18:
                self.head = self.headList.find('**/pencilpusher')
            elif self.currentHead == 19:
                self.head = self.headList.find('**/telemarketer')
            else:
                #spin doctor
                self.head = self.headList.find('**/telemarketer')
                self.head.setTexture(loader.loadTexture(self.pandaDirectory + \
                     '/resources/cogs/textures/spin-doctor.jpg'), 1)

        elif self.currentHead <= 29:
            self.headList = loader.loadModel(
                self.pandaDirectory + '/resources/cogs/models/suitC-heads.bam')

            if self.currentHead == 21:
                #actually a short change
                self.head = self.headList.find('**/coldcaller')
            elif self.currentHead == 22:
                #cold caller needs to be recolored
                self.head = self.headList.find('**/coldcaller')
                self.head.setColor(0, 0, 255, 1)
            elif self.currentHead == 23:
                self.head = self.headList.find('**/flunky')
                hasGlasses = True
            elif self.currentHead == 24:
                #corporate raider
                self.head = self.headList.find('**/flunky')
                self.head.setTexture(loader.loadTexture(self.pandaDirectory + \
                     '/resources/cogs/textures/corporate-raider.jpg'), 1)
            elif self.currentHead == 25:
                self.head = self.headList.find('**/gladhander')
            elif self.currentHead == 26:
                self.head = self.headList.find('**/micromanager')
            elif self.currentHead == 27:
                self.head = self.headList.find('**/moneybags')
            elif self.currentHead == 28:
                self.head = self.headList.find('**/tightwad')
            else:
                #bottom feeder
                self.head = self.headList.find('**/tightwad')
                self.head.setTexture(loader.loadTexture(self.pandaDirectory + \
                     '/resources/cogs/textures/bottom-feeder.jpg'), 1)
        else:
            raise Exception(
                'UH OH! currentHead is not between 0 and 31! The value of currentBody is {}'
                .format(self.currentHead))

        #Attach the head to the model
        self.head.reparentTo(self.cog.find('**/def_head'))

        if hasGlasses:
            self.glasses = self.headList.find('**/glasses')
            self.glasses.reparentTo(self.head)

    def determineDept(self):
        #Determine the cog department and set the textures of the suit
        if self.currentDept == 0:
            self.cog.findAllMatches('**/torso').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/s_blazer.jpg'), 1)

            self.cog.findAllMatches('**/arms').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/s_sleeve.jpg'), 1)

            self.cog.findAllMatches('**/legs').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/s_leg.jpg'), 1)

        elif self.currentDept == 1:
            self.cog.findAllMatches('**/torso').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/m_blazer.jpg'), 1)

            self.cog.findAllMatches('**/arms').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/m_sleeve.jpg'), 1)

            self.cog.findAllMatches('**/legs').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/m_leg.jpg'), 1)

        elif self.currentDept == 2:
            self.cog.findAllMatches('**/torso').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/l_blazer.jpg'), 1)

            self.cog.findAllMatches('**/arms').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/l_sleeve.jpg'), 1)

            self.cog.findAllMatches('**/legs').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/l_leg.jpg'), 1)

        elif self.currentDept == 3:
            self.cog.findAllMatches('**/torso').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/c_blazer.jpg'), 1)

            self.cog.findAllMatches('**/arms').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/c_sleeve.jpg'), 1)

            self.cog.findAllMatches('**/legs').setTexture(
                loader.loadTexture(self.pandaDirectory +
                                   '/resources/cogs/textures/c_leg.jpg'), 1)

        elif self.currentDept == 4:
            self.cog.findAllMatches('**/torso').setTexture(
                loader.loadTexture(
                    self.pandaDirectory +
                    '/resources/cogs/textures/waiter_m_blazer.jpg'), 1)

            self.cog.findAllMatches('**/arms').setTexture(
                loader.loadTexture(
                    self.pandaDirectory +
                    '/resources/cogs/textures/waiter_m_sleeve.jpg'), 1)

            self.cog.findAllMatches('**/legs').setTexture(
                loader.loadTexture(
                    self.pandaDirectory +
                    '/resources/cogs/textures/waiter_m_leg.jpg'), 1)

        else:
            raise Exception(
                'UH OH! currentDept is not between 0 and 4! The value of currentDept is {}'
                .format(self.currentDept))

    def nextHead(self):
        #Keep the head variable within the range and switch to the next head
        if self.currentHead >= 29:
            self.currentHead = 0
        else:
            self.currentHead += 1

        self.determineHead()

    def previousHead(self):
        #Keep the head variable within the range and switch to the previous head
        if self.currentHead <= 0:
            self.currentHead = 29
        else:
            self.currentHead -= 1

        self.determineHead()

    def nextBody(self):
        #Keep the head variable within the range and switch to the next body
        if self.currentBody >= 2:
            self.currentBody = 0
        else:
            self.currentBody += 1

        self.determineBody()

    def previousBody(self):
        #Keep the head variable within the range and switch to the previous body
        if self.currentBody <= 0:
            self.currentBody = 2
        else:
            self.currentBody -= 1

        self.determineBody()

    def nextDept(self):
        #Keep the head variable within the range and switch to the next department
        if self.currentDept >= 4:
            self.currentDept = 0
        else:
            self.currentDept += 1

        self.determineDept()

    def previousDept(self):
        #Keep the head variable within the range and switch to the previous department
        if self.currentDept <= 0:
            self.currentDept = 4
        else:
            self.currentDept -= 1

        self.determineDept()

    def resetCogPos(self):
        #Sets the cog's position to its starting location outside the scene
        self.cog.loop('walk')
        self.cog.setHpr(90, 0, 0)
        self.cog.setPos(15, 2, 0)

    def enterScene(self):
        #Establish the sequence for the cog to walk in the scene
        self.resetCogPos()
        self.enterView.start()

        self.isInView = True

    def exitScene(self):
        #Establish the sequence for the cog to walk out of the scene
        self.exitView.start()

        self.isInView = False

    def playNeutral(self):
        #Makes the neutral animation available to the GUI class
        self.cog.loop('neutral')

    def playVictory(self):
        #Makes the victory animation available to the GUI class
        self.cog.loop('victory')

    def getAnimPlaying(self):
        #returns the animation playing for the GUI class
        return self.cog.getCurrentAnim()
示例#34
0
class DistributedSafezoneJukebox(DistributedObject):
    notify = directNotify.newCategory('DistributedSafezoneJukebox')

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.activityName = TTLocalizer.SafezoneJukeboxTitle
        self.phaseToMusicData = PhaseToMusicData60
        self.jukebox = None
        self.gui = None
        self.tunes = []
        self.music = None
        self.messageGui = None
        self.currentSongData = None
        self.localQueuedSongInfo = None
        self.localQueuedSongListItem = None
        self._localToonRequestStatus = None
        self.toonIds = []
        self._toonId2ror = {}
        self.root = NodePath('root')
        return

    def announceGenerate(self):
        DistributedObject.announceGenerate(self)
        self.load()

    def disable(self):
        self.notify.debug('BASE: disable')
        DistributedObject.disable(self)
        rorToonIds = self._toonId2ror.keys()
        for toonId in rorToonIds:
            self.cr.relatedObjectMgr.abortRequest(self._toonId2ror[toonId])
            del self._toonId2ror[toonId]

        self.ignore(self.messageDoneEvent)
        if self.messageGui is not None and not self.messageGui.isEmpty():
            self.messageGui.cleanup()
            self.messageGui = None
        return

    def delete(self):
        self.notify.debug('BASE: delete')
        self.unload()
        self.ignoreAll()
        DistributedObject.delete(self)

    def generateInit(self):
        self.gui = JukeboxGui(self.phaseToMusicData)

    def load(self):
        self.jukebox = Actor(
            'phase_13/models/parties/jukebox_model',
            {'dance': 'phase_13/models/parties/jukebox_dance'})
        self.jukebox.reparentTo(self.root)
        self.collNode = CollisionNode(self.getCollisionName())
        self.collNode.setCollideMask(ToontownGlobals.CameraBitmask
                                     | ToontownGlobals.WallBitmask)
        collTube = CollisionTube(0, 0, 0, 0.0, 0.0, 4.25, 2.25)
        collTube.setTangible(1)
        self.collNode.addSolid(collTube)
        self.collNodePath = self.jukebox.attachNewNode(self.collNode)
        self.loadSign()
        self.sign.setPos(-5.0, 0, 0)
        self.messageDoneEvent = self.uniqueName('messageDoneEvent')
        self.root.reparentTo(render)
        self.activate()

    def loadSign(self):
        self.sign = self.root.attachNewNode('%sSign' % self.activityName)
        self.defaultSignModel = loader.loadModel(
            'phase_13/models/parties/eventSign')
        self.signModel = self.defaultSignModel.copyTo(self.sign)
        self.signFlat = self.signModel.find('**/sign_flat')
        self.signFlatWithNote = self.signModel.find('**/sign_withNote')
        self.signTextLocator = self.signModel.find('**/signText_locator')
        self.activityIconsModel = loader.loadModel(
            'phase_4/models/parties/eventSignIcons')
        textureNodePath = self.activityIconsModel.find('**/PartyJukebox40Icon')
        textureNodePath.setPos(0.0, -0.02, 2.2)
        textureNodePath.setScale(2.35)
        textureNodePath.copyTo(self.signFlat)
        textureNodePath.copyTo(self.signFlatWithNote)
        text = TextNode('noteText')
        text.setTextColor(0.2, 0.1, 0.7, 1.0)
        text.setAlign(TextNode.ACenter)
        text.setFont(OTPGlobals.getInterfaceFont())
        text.setWordwrap(10.0)
        text.setText('')
        self.noteText = self.signFlatWithNote.attachNewNode(text)
        self.noteText.setPosHpr(self.signTextLocator, 0.0, 0.0, 0.2, 0.0, 0.0,
                                0.0)
        self.noteText.setScale(0.2)
        self.signFlatWithNote.stash()
        self.signTextLocator.stash()

    def unload(self):
        self.gui.unload()
        if self.music is not None:
            self.music.stop()
        self.jukebox.stop()
        self.jukebox.delete()
        self.jukebox = None
        self.signModel.removeNode()
        del self.signModel
        self.sign.removeNode()
        del self.sign
        self.ignoreAll()
        self.root.removeNode()
        del self.root
        del self.activityName
        del self.messageGui
        if hasattr(self, 'toonIds'):
            del self.toonIds
        self.ignoreAll()
        return

    def getCollisionName(self):
        return self.uniqueName('jukeboxCollision')

    def activate(self):
        self.accept('enter' + self.getCollisionName(),
                    self.__handleEnterCollision)

    def __handleEnterCollision(self, collisionEntry):
        if base.cr.playGame.getPlace().fsm.getCurrentState().getName(
        ) == 'walk':
            base.cr.playGame.getPlace().fsm.request('activity')
            self.d_toonJoinRequest()

    def localToonExiting(self):
        self._localToonRequestStatus = ActivityRequestStatus.Exiting

    def localToonJoining(self):
        self._localToonRequestStatus = ActivityRequestStatus.Joining

    def d_toonJoinRequest(self):
        if self._localToonRequestStatus is None:
            self.localToonJoining()
            self.sendUpdate('toonJoinRequest')
        return

    def d_toonExitRequest(self):
        if self._localToonRequestStatus is None:
            self.localToonExiting()
            self.sendUpdate('toonExitRequest')
        return

    def d_toonExitDemand(self):
        self.localToonExiting()
        self.sendUpdate('toonExitDemand')

    def joinRequestDenied(self, reason):
        self._localToonRequestStatus = None
        self.showMessage(TTLocalizer.PartyJukeboxOccupied)
        return

    def handleToonJoined(self, toonId):
        toon = base.cr.doId2do.get(toonId)
        if toon:
            self.jukebox.lookAt(base.cr.doId2do[toonId])
            self.jukebox.setHpr(self.jukebox.getH() + 180.0, 0, 0)
        if toonId == base.localAvatar.doId:
            self.__localUseJukebox()

    def handleToonExited(self, toonId):
        if toonId == base.localAvatar.doId and self.gui.isLoaded():
            self.__deactivateGui()

    def handleToonDisabled(self, toonId):
        self.notify.warning('handleToonDisabled no implementation yet')

    def setToonsPlaying(self, toonIds):
        exitedToons, joinedToons = self.getToonsPlayingChanges(
            self.toonIds, toonIds)
        self.setToonIds(toonIds)
        self._processExitedToons(exitedToons)
        self._processJoinedToons(joinedToons)

    def _processExitedToons(self, exitedToons):
        for toonId in exitedToons:
            if toonId != base.localAvatar.doId or toonId == base.localAvatar.doId and self.isLocalToonRequestStatus(
                    ActivityRequestStatus.Exiting):
                toon = self.getAvatar(toonId)
                if toon is not None:
                    self.ignore(toon.uniqueName('disable'))
                self.handleToonExited(toonId)
                if toonId == base.localAvatar.doId:
                    self._localToonRequestStatus = None
                if toonId in self._toonId2ror:
                    self.cr.relatedObjectMgr.abortRequest(
                        self._toonId2ror[toonId])
                    del self._toonId2ror[toonId]

        return

    def _processJoinedToons(self, joinedToons):
        for toonId in joinedToons:
            if toonId != base.localAvatar.doId or toonId == base.localAvatar.doId and self.isLocalToonRequestStatus(
                    ActivityRequestStatus.Joining):
                if toonId not in self._toonId2ror:
                    request = self.cr.relatedObjectMgr.requestObjects(
                        [toonId], allCallback=self._handlePlayerPresent)
                    if toonId in self._toonId2ror:
                        del self._toonId2ror[toonId]
                    else:
                        self._toonId2ror[toonId] = request

    def _handlePlayerPresent(self, toons):
        toon = toons[0]
        toonId = toon.doId
        if toonId in self._toonId2ror:
            del self._toonId2ror[toonId]
        else:
            self._toonId2ror[toonId] = None
        self._enableHandleToonDisabled(toonId)
        self.handleToonJoined(toonId)
        if toonId == base.localAvatar.doId:
            self._localToonRequestStatus = None
        return

    def _enableHandleToonDisabled(self, toonId):
        toon = self.getAvatar(toonId)
        if toon is not None:
            self.acceptOnce(toon.uniqueName('disable'),
                            self.handleToonDisabled, [toonId])
        else:
            self.notify.warning(
                'BASE: unable to get handle to toon with toonId:%d. Hook for handleToonDisabled not set.'
                % toonId)
        return

    def isLocalToonRequestStatus(self, requestStatus):
        return self._localToonRequestStatus == requestStatus

    def setToonIds(self, toonIds):
        self.toonIds = toonIds

    def getToonsPlayingChanges(self, oldToonIds, newToonIds):
        oldToons = set(oldToonIds)
        newToons = set(newToonIds)
        exitedToons = oldToons.difference(newToons)
        joinedToons = newToons.difference(oldToons)
        return (list(exitedToons), list(joinedToons))

    def getAvatar(self, toonId):
        if toonId in self.cr.doId2do:
            return self.cr.doId2do[toonId]
        else:
            self.notify.warning(
                'BASE: getAvatar: No avatar in doId2do with id: ' +
                str(toonId))
            return
            return

    def __localUseJukebox(self):
        base.localAvatar.disableAvatarControls()
        base.localAvatar.stopPosHprBroadcast()
        self.__activateGui()
        self.accept(JukeboxGui.CLOSE_EVENT, self.__handleGuiClose)
        taskMgr.doMethodLater(0.5,
                              self.__localToonWillExitTask,
                              self.uniqueName('toonWillExitJukeboxOnTimeout'),
                              extraArgs=None)
        self.accept(JukeboxGui.ADD_SONG_CLICK_EVENT, self.__handleQueueSong)
        if self.isUserHost():
            self.accept(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT,
                        self.__handleMoveSongToTop)
        return

    def __localToonWillExitTask(self, task):
        self.localToonExiting()
        return Task.done

    def __activateGui(self):
        self.gui.enable(timer=JUKEBOX_TIMEOUT)
        self.gui.disableAddSongButton()
        if self.currentSongData is not None:
            self.gui.setSongCurrentlyPlaying(self.currentSongData[0],
                                             self.currentSongData[1])
        self.d_queuedSongsRequest()
        return

    def __deactivateGui(self):
        self.ignore(JukeboxGui.CLOSE_EVENT)
        self.ignore(JukeboxGui.SONG_SELECT_EVENT)
        self.ignore(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT)
        base.cr.playGame.getPlace().setState('walk')
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.enableAvatarControls()
        self.gui.unload()
        self.__localClearQueuedSong()

    def isUserHost(self):
        return base.localAvatar.getAccessLevel() >= 200

    def d_queuedSongsRequest(self):
        self.sendUpdate('queuedSongsRequest')

    def queuedSongsResponse(self, songInfoList, index):
        if self.gui.isLoaded():
            for i in xrange(len(songInfoList)):
                songInfo = songInfoList[i]
                self.__addSongToQueue(songInfo,
                                      isLocalQueue=index >= 0 and i == index)

            self.gui.enableAddSongButton()

    def __handleGuiClose(self):
        self.__deactivateGui()
        self.d_toonExitDemand()

    def __handleQueueSong(self, name, values):
        self.d_setNextSong(values[0], values[1])

    def d_setNextSong(self, phase, filename):
        self.sendUpdate('setNextSong', [(phase, filename)])

    def setSongInQueue(self, songInfo):
        if self.gui.isLoaded():
            phase = sanitizePhase(songInfo[0])
            filename = songInfo[1]
            data = self.getMusicData(phase, filename)
            if data:
                if self.localQueuedSongListItem is not None:
                    self.localQueuedSongListItem['text'] = data[0]
                else:
                    self.__addSongToQueue(songInfo, isLocalQueue=True)
        return

    def __addSongToQueue(self, songInfo, isLocalQueue=False):
        isHost = isLocalQueue and self.isUserHost()
        data = self.getMusicData(sanitizePhase(songInfo[0]), songInfo[1])
        if data:
            listItem = self.gui.addSongToQueue(data[0],
                                               highlight=isLocalQueue,
                                               moveToTopButton=isHost)
            if isLocalQueue:
                self.localQueuedSongInfo = songInfo
                self.localQueuedSongListItem = listItem

    def __localClearQueuedSong(self):
        self.localQueuedSongInfo = None
        self.localQueuedSongListItem = None
        return

    def __play(self, phase, filename, length):
        self.music = base.loader.loadMusic(
            (MUSIC_PATH + '%s') % (phase, filename))
        if self.music:
            if self.__checkPartyValidity() and hasattr(
                    base.cr.playGame.getPlace().loader,
                    'music') and base.cr.playGame.getPlace().loader.music:
                base.cr.playGame.getPlace().loader.music.stop()
            self.music.setTime(0.0)
            self.music.setLoopCount(int(getMusicRepeatTimes(length)))
            self.music.play()
            jukeboxAnimControl = self.jukebox.getAnimControl('dance')
            if not jukeboxAnimControl.isPlaying():
                self.jukebox.loop('dance', fromFrame=0, toFrame=48)
            self.currentSongData = (phase, filename)

    def __stop(self):
        self.jukebox.stop()
        self.currentSongData = None
        if self.music:
            self.music.stop()
        if self.gui.isLoaded():
            self.gui.clearSongCurrentlyPlaying()
        return

    def setSongPlaying(self, songInfo, toonId):
        phase = sanitizePhase(songInfo[0])
        filename = songInfo[1]
        if not filename:
            self.__stop()
            return
        data = self.getMusicData(phase, filename)
        if data:
            self.__play(phase, filename, data[1])
            self.setSignNote(data[0])
            if self.gui.isLoaded():
                item = self.gui.popSongFromQueue()
                self.gui.setSongCurrentlyPlaying(phase, filename)
                if item == self.localQueuedSongListItem:
                    self.__localClearQueuedSong()
        if toonId == localAvatar.doId:
            localAvatar.setSystemMessage(0, TTLocalizer.PartyJukeboxNowPlaying)

    def setSignNote(self, note):
        self.noteText.node().setText(note)
        if len(note.strip()) > 0:
            self.signFlat.stash()
            self.signFlatWithNote.unstash()
            self.signTextLocator.unstash()
        else:
            self.signFlat.unstash()
            self.signFlatWithNote.stash()
            self.signTextLocator.stash()

    def __handleMoveSongToTop(self):
        if self.isUserHost() and self.localQueuedSongListItem is not None:
            self.d_moveHostSongToTopRequest()
        return

    def d_moveHostSongToTopRequest(self):
        self.notify.debug('d_moveHostSongToTopRequest')
        self.sendUpdate('moveHostSongToTopRequest')

    def moveHostSongToTop(self):
        self.notify.debug('moveHostSongToTop')
        if self.gui.isLoaded():
            self.gui.pushQueuedItemToTop(self.localQueuedSongListItem)

    def getMusicData(self, phase, filename):
        data = []
        phase = sanitizePhase(phase)
        phase = self.phaseToMusicData.get(phase)
        if phase:
            data = phase.get(filename, [])
        return data

    def __checkPartyValidity(self):
        if hasattr(base.cr.playGame,
                   'getPlace') and base.cr.playGame.getPlace() and hasattr(
                       base.cr.playGame.getPlace(),
                       'loader') and base.cr.playGame.getPlace().loader:
            return True
        else:
            return False

    def showMessage(self, message, endState='walk'):
        base.cr.playGame.getPlace().fsm.request('activity')
        self.acceptOnce(self.messageDoneEvent, self.__handleMessageDone)
        self.messageGui = TTDialog.TTGlobalDialog(
            doneEvent=self.messageDoneEvent,
            message=message,
            style=TTDialog.Acknowledge)
        self.messageGui.endState = endState

    def __handleMessageDone(self):
        self.ignore(self.messageDoneEvent)
        if hasattr(base.cr.playGame.getPlace(), 'fsm'):
            if self.messageGui and hasattr(self.messageGui, 'endState'):
                self.notify.info('__handleMessageDone (endState=%s)' %
                                 self.messageGui.endState)
                base.cr.playGame.getPlace().fsm.request(
                    self.messageGui.endState)
            else:
                self.notify.warning(
                    "messageGui has no endState, defaulting to 'walk'")
                base.cr.playGame.getPlace().fsm.request('walk')
        if self.messageGui is not None and not self.messageGui.isEmpty():
            self.messageGui.cleanup()
            self.messageGui = None
        return
示例#35
0
class Cycle(DirectObject):
	def __init__(self, inputManager, track, audio3D, startPos, 
		name, ai = None):
		self.inputManager = inputManager
		# Stores a reference to the InputManager to access user input.
		
		self.setupVarsNPs(audio3D, startPos, name)
		self.setupCollisions()
		# Sets up initial variables, NodePaths, and collision objects.
		
		self.track = track
		# Stores a reference to the track.
		
		self.lanes = self.track.trackLanes.lanes
		# gets a reference to the lanes on the track, to shorten the variable name.
		
		startingLane = self.track.trackLanes.getNearestMarker(self).lane
		# Gets the lane for the closest marker to the cycle.
		
		self.uc1 = self.lanes[startingLane][0]
		self.uc2 = self.lanes[startingLane][1]
		self.uc3 = self.lanes[startingLane][2]
		# Sets up 3 variables to store references to the 3 up-coming markers on the
		# track, ahead of the cycle. These are used by the AI to steer, and by player
		# cycles to measure progress along the track.
		
		if(ai == True):
			self.ai = CycleAI(self)
		# if the ai input is passed anything, it won't default to None, and the cycle will create
		# an AI to control itself.
		elif(ai == None):
			self.ai = None
			taskMgr.add(self.cycleControl, "Cycle Control", sort = int(self.root.getY() + 100))
		# If the cycle isn't using an AI, activate player control. The cycle is also given a unique
		# sort value based on it's distance from the finish line. The unique sort value fixes a bug
		# in the AI aim code that can cause jittering in the aim when the tasks that control the 
		# cycles don't execute in the same order every frame.
		# With this set up, if AI == False, the cycle will be completely uncontrolled.
		
		self.setupLight()
		# Calls the method that creates a light to represent the glow of the cycle's discs and engine.
		
	def setupVarsNPs(self, audio3D, startPos, name):
		self.name = name
		# Stores a unique name for this cycle.
		
		self.audio3D = audio3D
		# Stores a reference to the audio3DManager the cycle will use.
		
		self.root = render.attachNewNode("Root")
		# Creates and stores the NodePath that will be used as the root of the cycle
		# for the purpose of movement.
		
		self.cycle = self.root.attachNewNode("Cycle")
		# Creates a dummy node to go between self.root and the actualy cycle model.
		
		if(startPos == 1):
			self.root.setPos(5,0,0)
			self.model = loader.loadModel("../Models/RedCycle.bam")
			self.turret = loader.loadModel("../Models/RedTurr.bam")
		elif(startPos == 2):
			self.root.setPos(-5,-5,0)
			self.model = loader.loadModel("../Models/BlueCycle.bam")
			self.turret = loader.loadModel("../Models/BlueTurr.bam")
		elif(startPos == 3):
			self.root.setPos(5,-10,0)
			self.model = loader.loadModel("../Models/GreenCycle.bam")
			self.turret = loader.loadModel("../Models/GreenTurr.bam")
		elif(startPos == 4):
			self.root.setPos(-5,-15,0)
			self.model = loader.loadModel("../Models/YellowCycle.bam")
			self.turret = loader.loadModel("../Models/YellowTurr.bam")
		# Sets the root to a new position according to what place it is given.
		# Also loads the model and turret of the appropriate color.
		
		self.mounts = Actor("../Models/Mounts.egg")
		# Loads an actor with 3 mounting joints for the moving parts of the cycle.
		
		self.model.reparentTo(self.cycle)
		self.mounts.reparentTo(self.model)
		# Attaches the model to the go-between node and attaches the mounts to
		# the model.
		
		turretMount = self.mounts.exposeJoint(None, 
			"modelRoot", "Turret")
		fdMount = self.mounts.exposeJoint(None, 
			"modelRoot", "FrontDisc")
		rdMount = self.mounts.exposeJoint(None, 
			"modelRoot", "RearDisc")
		# exposes the mount joints so pieces can be attached to them.
		
		self.fd = loader.loadModel("../Models/Disc.bam")
		self.rd = loader.loadModel("../Models/Disc.bam")
		# loads the models for the discs.
		
		self.turretActor = Actor("../Models/TurretActor.egg")
		self.turretActor.reparentTo(turretMount)
		self.turret.reparentTo(self.turretActor)
		self.trgtrMount = self.turretActor.exposeJoint(None,
			"modelRoot", "TargeterMount")
		self.fd.reparentTo(fdMount)
		self.rd.reparentTo(rdMount)
		# Attaches the turret and discs to their mounts.
		
		self.LMGMount = self.turretActor.exposeJoint(None,
			"modelRoot", "LMGMount")
		self.RMGMount = self.turretActor.exposeJoint(None,
			"modelRoot", "RMGMount")
		self.LMG = MachineGun(self, self.LMGMount, self.audio3D)
		self.RMG = MachineGun(self, self.RMGMount, self.audio3D)
		self.CannonMount = self.turretActor.exposeJoint(None,
			"modelRoot", "CannonMount")
		self.cannon = Cannon(self, self.CannonMount, self.audio3D)
		
		self.engineSfx = self.audio3D.loadSfx("../Sound/Engine.wav")
		self.audio3D.attachSoundToObject(self.engineSfx, self.root)
		self.engineSfx.setPlayRate(.5)
		self.engineSfx.setLoop(True)
		self.engineSfx.setVolume(2)
		self.engineSfx.play()
		# loads a sound effect for the engine and sets the starting play rate.

		self.dirNP = self.root.attachNewNode("DirNP")
		self.refNP = self.root.attachNewNode("RefNP")
		# Creates and stores two more NodePaths, one to track the direction the cycle
		# is moving in and another to use as a reference during various calculations
		# the cycle performs.
		
		self.dirVec = Vec3(0,0,0)
		self.cycleVec = Vec3(0,0,0)
		self.refVec = Vec3(0,0,0)
		# Creates and stores 3 vector objects to be used in simulating drift when the
		# cycle turns.
		
		self.speed = 0
		self.throttle = 0
		self.maxSpeed = 200
		self.maxShield = 500
		self.shield = self.maxShield
		self.accel = 25
		self.handling = 25
		self.maxEnergy = 100
		self.energy = self.maxEnergy
		self.stability = 25
		self.shieldRchrg = 10
		self.energyRchrg = 5
		self.shutDown = False
		# Sets basic variables for the cycle's racing attributes.
		
		self.turning = None
		self.lean = 0
		# Creates two variables to control the cycle's lean
		
		self.markerCount = 0
		self.currentLap = 0
		# Creates two variables that will be used to track the progress
		# of the cycle on the track.
		
		self.freeFall = False
		self.fallSpeed = 0
		# Creates two variables to assist with managing the cycle's falls from
		# hills and ramps. 
		self.trackNP = render.attachNewNode(self.name + "_TrackNode")
		# Creates a NodePath to use when setting the cycle's height above the track.
		# refNP won't serve for this purpose, because it exists in root's coordinate space.
		# We need a NodePath in render's coordinate space for this purpose.
		
		self.active = False
		# creates a variable that determines if the cycle can be controlled or not.
		
		return
# setupVarsNPs: Initializes most of the non-collision variables and NodePaths needed by the cycle.
		
	def setupCollisions(self):
		self.shieldCN = CollisionNode(self.name + "_ShieldCN")
		# Creates a CollisionNode to store the 3 CollisionSpheres that represent the
		# invisible energy shield surrounding the cycle.
		
		self.shieldCN.setPythonTag("owner", self)
		# Connects a reference to the instance of this class to the shield CollisionNode.
		# This will make it much easier to identify this cycle when its shield is struck.
		
		CS1 = CollisionSphere(0, -.025, .75, .785)
		CS2 = CollisionSphere(0, -1.075, .85, .835)
		CS3 = CollisionSphere(0, 1.125, .6, .61)
		self.shieldCN.addSolid(CS1)
		self.shieldCN.addSolid(CS2)
		self.shieldCN.addSolid(CS3)
		# Creates the 3 CollisionSpheres that make up the shield and adds them into
		# the CollisionNode.
		
		self.shieldCN.setIntoCollideMask(BitMask32.range(2,3))
		self.shieldCN.setFromCollideMask(BitMask32.bit(2))
		# Sets the BitMasks on the CollisionNode. The From mask has bit 2 turned on, so
		# the shield can bump into things on bit 2. The Into mask has bits 2, 3, and 4 turned
		# on so the shield can be struck by things on bit 2 (other cycles), 3 (guns), and 4 (explosions)
		
		self.shieldCNP = self.model.attachNewNode(self.shieldCN)
		# Connects the shield and its 3 spheres to the cycle model and gets a NodePath to
		# the shield.
		
		self.bumpCTrav = CollisionTraverser()
		self.bumpHan = CollisionHandlerPusher()
		# Creates a CollisionTraverser and a Pusher-type handler to detect and manage
		# collisions caused by the cycle's shield.
		
		self.bumpHan.addCollider(self.shieldCNP, self.root)
		# Tells the pusher handler to push back on self.root when self.shieldCNP is
		# involved in a collision.
		
		self.bumpHan.addAgainPattern("%fn-again")
		# Tells the pusher handler to create an event using the From CollisionNode's
		# name when it handles recurring collisions.
		
		self.bumpCTrav.addCollider(self.shieldCNP, self.bumpHan)
		# Registers the shield and the handler with the traverser.
		
		self.accept(self.name + "_ShieldCN-again", self.bump)
		# Registers the event that the pusher handler will generate and connects it to
		# the bump method.
		
		self.gRayCN = CollisionNode(self.name + "_GRayCN")
		# Creates a second CollisionNode to store the rays that will be used for collision
		# with the ground.
		
		self.fRay = CollisionRay(0, .5, 10, 0, 0, -1)
		self.bRay = CollisionRay(0, -.5, 10, 0, 0, -1)
		# Creates two rays 10 meters up and points them downward. This time we keep a 
		# reference to the rays because we will need them when organizing their collision data.
		
		self.gRayCN.addSolid(self.fRay)
		self.gRayCN.addSolid(self.bRay)
		# Adds the rays to the CollisionNode.
		
		self.gRayCN.setFromCollideMask(BitMask32.bit(1))
		self.gRayCN.setIntoCollideMask(BitMask32.allOff())
		# Sets the BitMasks for gRayCN. The From mask has bit 1 on so it can cause collisions
		# with the ground. The Into mask is turned off completely, because rays should never
		# be collided into.
		
		self.gRayCNP = self.cycle.attachNewNode(self.gRayCN)
		# Attaches the gRayCN to the cycle and gets a NodePath to it.
		
		self.gCTrav = CollisionTraverser()
		self.gHan = CollisionHandlerQueue()
		self.gCTrav.addCollider(self.gRayCNP, self.gHan)
		# Creates a traverser and a Queue-type handler to detect and manage the rays' collisions.
		# Then registers gRayCNP and the handler with the traverser.
		
		self.trgtrCN = CollisionNode(self.name + "_TargeterCN")
		self.trgtrRay = CollisionRay(0,0,0,0,1,0)
		self.trgtrCN.addSolid(self.trgtrRay)
		self.trgtrCN.setFromCollideMask(BitMask32.bit(3))
		self.trgtrCN.setIntoCollideMask(BitMask32.allOff())
		self.trgtrCNP = self.trgtrMount.attachNewNode(self.trgtrCN)
		# creates 1 collision ray to represent the line of fire of the cycle for the purpose shooting.
		# The ray is added to a collision node which is parented to the targeter mount of the turret.
		
		self.trgtrCTrav = CollisionTraverser()
		self.trgtrCHan = CollisionHandlerQueue()
		self.trgtrCTrav.addCollider(self.trgtrCNP, self.trgtrCHan)
		# creates a traverser and Queue-type handler to detect and manage the collisions of the
		# targeter ray, and registers the ray and handler with the traverser.
		
		return
# setupCollisions: Preps CollisionNodes, collision solids, traversers, and handlers to get them
# ready for use.

	def setupLight(self):
		self.glow = self.cycle.attachNewNode(
			PointLight(self.name + "Glow"))
		self.glow.node().setColor(Vec4(.2,.6,1,1))
		# Creates a point light on the cycle and sets it's color to a blue-white. 
		
		self.glow.node().setAttenuation(Vec3(0,0,.75))
		# Sets the attenuation on the point light. This controls the fall-off.
		
		self.cycle.setLight(self.glow)
		self.track.track.setLight(self.glow)
		# Sets the light to illuminate the cycle and the track.
		return
# setupLight: Creates a point light to represent the glow of the cycle and sets its attributes. Then
# sets the light to illuminate the scene.
		
	def cycleControl(self, task):
		if(self.cycle == None):
			return task.done
			# Ends the task if the cycle model is removed.
			
		dt = globalClock.getDt()
		if( dt > .20):
			return task.cont
		# Gets the amount of time that has passed since the last frame from the global clock.
		# If the value is too large, there has been a hiccup and the frame will be skipped.
		
		if(self.active == True and self.shutDown == False):
		# limits player control to only occur when self.active is true and
		# self.shutDown is false.
		
			if(self.inputManager.keyMap["up"] == True):
				self.adjustThrottle("up", dt)
			elif(self.inputManager.keyMap["down"] == True):
				self.adjustThrottle("down", dt)
			# Checks the InputManager for throttle control initiated by the user and performs
			# the adjustments.
		
			if(self.inputManager.keyMap["right"] == True):
				self.turn("r", dt)
				self.turning = "r"
			elif(self.inputManager.keyMap["left"] == True):
				self.turn("l", dt)
				self.turning = "l"
			else:
				self.turning = None
			# Checks the InputManager for turning initiated by the user and performs it.
			# Also updates the self.turning variable to reflect it.
			
			if(self.inputManager.keyMap["mouse1"] == True):
				self.LMG.fire()
				self.RMG.fire()
			# If the left mouse button is pressed, fire the machine guns.
			
			if(self.inputManager.keyMap["mouse3"] == True):
				self.cannon.fire()
			# If the right mouse button is pressed, fire the cannon.
		
		aimPoint = self.inputManager.getMouseAim()
		if(aimPoint != None):
			self.turretActor.lookAt(render, aimPoint)
		
		self.speedCheck(dt)
		self.simDrift(dt)
		self.groundCheck(dt)
		self.move(dt)
		self.checkMarkers()
		self.recharge(dt)
		# Calls the methods that control cycle behavior frame-by-frame.
		
		self.bumpCTrav.traverse(render)
		# Checks for collisions caused by the cycle's shield.
		
		return task.cont
# cycleControl: Manages the cycle's behavior when under player control.

	def cameraZoom(self, dir, dt):
		if(dir == "in"): base.camera.setY(base.camera, 10 * dt)
		else: base.camera.setY(base.camera, -10 * dt)
		return
# cameraZoom: Moves the camera toward or away from the cycle at a rate of 10
# meters per second.

	def turn(self, dir, dt):
		turnRate = self.handling * (2 - 
			(self.speed / self.maxSpeed))
		# Determines the current turn rate of the cycle according to its speed.
		
		if(dir == "r"): 
			turnRate = -turnRate
			self.turning = "r"
		# If this is a right turn, then turnRate should be negative.
		
		self.cycle.setH(self.cycle, turnRate * dt)
		# Rotates the cycle according to the turnRate and time.
		
		return
# turn: Rotates the cycle based on its speed to execute turns.

	def adjustThrottle(self, dir, dt):
		if(dir == "up"):
			self.throttle += .25 * dt
			# Increases the throttle setting at a rate of 25% per second.
			if(self.throttle > 1 ): self.throttle = 1
			# Limits the throttle to a maximum of 100%
		else:
			self.throttle -= .25 * dt
			# Decreases the throttle setting at a rate of 25% per second.
			if(self.throttle < -1 ): self.throttle = -1
			# Limits the throttle to a minimum of 100%
		return
# adjustThrottle: Increases or decreases the throttle.

	def speedCheck(self, dt):
		if(self.freeFall == False):
		# The cycle can't accelerate or deccelerate under it's own power if
		# it's in freefall, so we check to make sure it isn't.
		
			tSetting = (self.maxSpeed * self.throttle)
			# Gets the KpH value that corresponds to the current throttle setting.
			
			if(self.speed < tSetting):
			# Checks if the speed is too low.
				if((self.speed + (self.accel * dt)) > tSetting):
				# If so, check if accelerating at the normal rate would raise speed too high.
					self.speed = tSetting
					# If so, just set the speed to the throttle setting.
				else:
					self.speed += (self.accel * dt)
				# If accelerating won't raise the speed too high, go ahead and accelerate.
				
			elif(self.speed > tSetting):
			# Checks if the speed is too high.
				if((self.speed - (self.accel * dt)) < tSetting):
				# If so, check if decelerating at the normal rate would lower speed too much.
					self.speed = tSetting
					# If so, just set the speed to the throttle setting.
				else:
					self.speed -= (self.accel * dt)
				# If decelerating won't loser the speed too much, go ahead and decelerate.
		else:
			self.speed -= (self.speed * .125) * dt
		# If the cycle is in freefall, lower it's speed by 12.5% per second to simulate loss
		# of momentum to friction.
		
		speedRatio = self.speed / self.maxSpeed
		self.engineSfx.setPlayRate(.5 + speedRatio)
		# Adjusts the playrate of the engine sound based on speed.
		return
# speedCheck: Controls the speed at which the cycle is moving by adjusting it according to the
# throttle, or degrading it over time when in freefall.

	def simDrift(self, dt):
		self.refNP.setPos(self.dirNP, 0, 1, 0)
		self.dirVec.set(self.refNP.getX(), self.refNP.getY(), 0)
		# Uses refNP to get a vector that describes the facing of dirNP. The height value is
		# discarded as it is unnecessary.
		
		self.refNP.setPos(self.cycle, 0, 1, 0)
		self.cycleVec.set(self.refNP.getX(), self.refNP.getY(), 0)
		# Uses refNP to get a vector that describes the facing of the cycle. The height value is
		# discarded as it is unnecessary.
		
		self.refVec.set(0,0,1)
		# Sets refVec to point straight up. This vector will be the axis used to determine the
		# difference in the angle between dirNP and the cycle.
		
		vecDiff = self.dirVec.signedAngleDeg(self.cycleVec, 
			self.refVec)
		# Gets a signed angle that describes the difference between the facing of dirNP and
		# the cycle.
		
		if(vecDiff < .1 and vecDiff > -.1):
			self.dirNP.setHpr(self.cycle.getH(), 0, 0)
		# if the difference between the two facings is insignificant, set dirNP to face the
		# same direction as the cycle.
		
		else: self.dirNP.setHpr(self.dirNP, vecDiff * dt * 2.5, 0, 0)
		# If the difference is significant, tell dirNP to slowly rotate to try and catch up
		# to the cycle's facing.
		
		self.dirNP.setP(self.cycle.getP())
		self.dirNP.setR(0)
		# Constrains dirNP pitch and roll to the cycle and 0, respectively.
		
		return
# simDrift: This function simulates the cycle drifting when it turns by causing the dirNP, which 
# faces the direction the cycle is moving in, to slowly catch up to the actual facing of the cycle
# over time.

	def groundCheck(self, dt):
		self.gCTrav.traverse(render)
		# Checks for collisions between the ground and the CollisionRays attached to the cycle.
		
		points = [None, None]
		# Preps a list to hold the data from the collisions.
		
		if(self.gHan.getNumEntries() > 1):
		# Verifies that at least 2 collisions occured. If not, there's no point in checking
		# the collisions because we can't get data from both rays.
		
			self.gHan.sortEntries()
			# Arranges the collision entries in the cues from nearest to furthest.
			
			for E in range(self.gHan.getNumEntries()):
			# Iterates through all the entries in the CollisionHandlerQueue
			
				entry = self.gHan.getEntry(E)
				# Stores the current entry in a temporary variable.
				
				if(entry.getFrom() == self.fRay and points[0] == None): 
				# Checks if this entry is a collision caused by the front ray, and 
				# verifies that we don't have front ray data for this frame yet.
					points[0] = entry.getSurfacePoint(render)
					# Stores the actual point of collision, in the coordinate system of render,
					# in the first slot of the points list.
				elif(entry.getFrom() == self.bRay and points[1] == None):
				# Checks if this entry is a collision caused by the back ray, and 
				# verifies that we don't have back ray data for this frame yet.
					points[1] = entry.getSurfacePoint(render)
					# Stores the actual point of collision, in the coordinate system of render,
					# in the second slot of the points list.			
			
		if(points[0] == None or points[1] == None):
			self.teleport()
			return
		# If either ray didn't collide with the track, the cycle is going out of bounds
		# and needs to be teleported back onto the track.
		
		else:
		# If both rays gave us collision data, we can proceed.	
			
			''' The following segment of code controls the pitch of the cycle '''
			if(self.freeFall == False):
			# Checks if the cycle is in freefall. If it's not, we'll need to make the cycle's
			# pitch match the angle of the track.
				
				self.refNP.setPos(points[1])
				# Sets refNP to the spot on the track where the back ray collided.
				self.refNP.lookAt(points[0])
				# Tells refNP to point at the spot on the track where the front ray collided.
				
				pDiff = self.refNP.getP()- self.cycle.getP()
				# Finds the difference in pitch between refNP and the cycle, which is equivalent
				# to the difference between the cycle's pitch and the angle of the track.
				
				if(pDiff < .1 and pDiff > -.1):
					self.cycle.setP(self.refNP.getP())
				# If the pitch difference is insignificant, set the cycle to match the pitch of
				# refNP.
				
				else:
					self.cycle.setP(self.cycle, pDiff * dt * 5)
				# If the difference is significant, smoothly adjust the cycle's pitch toward the
				# pitch of refNP.
				
			
			elif((self.cycle.getP() - (dt * 10)) > -15): 
				self.cycle.setP(self.cycle, -(dt * 10))
			# If the cycle is in freefall and slowly dropping the pitch won't lower it past -15,
			# go ahead and slowly lower it.
			else: 
				self.cycle.setP(-15)
			# If we're in freefall and the cycle's pitch is to low to drop it any further, lock it
			# to exactly -15.
			''' End pitch control '''
			
			''' The following section of code will control the height of the cycle above the track. '''			
			if(self.speed >= 0): 
				self.trackNP.setPos(points[0].getX(), 
					points[0].getY(), points[0].getZ())
			else: 
				self.trackNP.setPos(points[1].getX(), 
					points[1].getY(), points[1].getZ())
			# Set trackNP at the collision point on the leading end of the cycle.
			
			height = self.root.getZ(self.trackNP)
			# Get the height of root as seen from the trackNP.
			
			if(height > 2 and self.freeFall == False): 
				self.freeFall = True
				self.fallSpeed = 0
			# If the height is greater than 2 and we aren't in freefall,
			# enter a freefall state and prep freefall variables.
			
			if(self.freeFall == True):
				self.fallSpeed += (self.track.gravity * 9.8) * dt
				newHeight = height - (self.fallSpeed * dt)
			# In a freefall state, begin accelerating the fall speed and 
			# calculate a new height based on that fall speed.
			
			else:
				hDiff = 1 - height
			# If not in a freefall state, calculate the difference in the actual height and the
			# desired height.
			
				if(hDiff > .01 or hDiff < -.01): 
					newHeight = height + (hDiff * dt * 5)
				# If the difference is significant, calculate a new height that drifts toward
				# the desired height.
				else: 
					newHeight = 1
				# If you're close to the desired height, just set it as the calculated new height.

			if(newHeight >= 0): 
				self.root.setZ(self.trackNP, newHeight)
			# If the new height is greater than or equal to zero, set it as root's height.
			
			else: 
				self.root.setZ(self.trackNP, 0)
				self.freeFall = False
			# Otherwise, set the root node to a height of 0, and turn off the freefall state.
			''' end of height control code '''
			
			self.cycle.setR(0)
			# Constrain the cycle's roll to 0.
	
		return
# groundCheck: Controls the cycle's pitch and it's height above the track.

	def move(self, dt):
		mps = self.speed * 1000 / 3600 
		# Convert kph to meters per second
		
		self.refNP.setPos(self.dirNP, 0, 1, 0)
		self.dirVec.set(self.refNP.getX(), self.refNP.getY(), 
			self.refNP.getZ())
		# Uses refNP to get a vector describing the direction dirNP is facing.
		
		self.root.setPos(self.root, 
			self.dirVec.getX() * dt * mps, 
			self.dirVec.getY() * dt * mps, 
			self.dirVec.getZ() * dt * mps)
		# Moves root forward according to the direction vector, speed, and time.
		
		currentLean = self.model.getR()
		# Get the current amount of lean.
		
		if(self.turning == "r"):
			self.lean += 2.5
			if(self.lean > 25): self.lean = 25
			self.model.setR(self.model, 
				(self.lean - currentLean) * dt * 5)
		# If the cycle is turning right, increase lean up to 25 and model the frame to lean the cycle.
		
		elif(self.turning == "l"):
			self.lean -= 2.5
			if(self.lean < -25): self.lean = -25
			self.model.setR(self.model, 
				(self.lean - currentLean) * dt * 5)
		# If the cycle is turning left, decrease lean down to -25 and roll the model to lean the cycle.
		
		else: 
			self.lean = 0
			self.model.setR(self.model, 
				(self.lean - currentLean) * dt * 5)
		# If the cycle isn't turning, set lean to 0 and roll the model back toward upright.
		
		self.fd.setH(self.fd, 5  + (20 * self.throttle))
		self.rd.setH(self.rd, -5 + (-20 * self.throttle))
		
		return
# move: Controls the forward or backward movement of the cycle.
			
	def checkMarkers(self):
		if(self.uc1.checkInFront(self) == True):
		# Checks if the cycle has passed in front of uc1.
		
			self.uc1 = self.uc2
			self.uc2 = self.uc3
			self.uc3 = self.uc2.nextMarker
			# If so, get the next set of markers on the track.
			
			self.markerCount += 1
			# Update the cycle's marker count by one.
			
			if(self.uc1 == self.lanes[0][1] or self.uc1 == self.lanes[1][1]):
				self.currentLap += 1
			# If the cycle just passed the first marker, which is at the finish line, increment the lap count.
			
		return
# checkMarkers: Checks if the nearest marker has been passed, and if so, 
# updates all the markers, marker count, and lap count if needed.

	def recharge(self, dt):
		if(self.energy < self.maxEnergy and self.shutDown == False):
		# Checks if the cycle should recharge energy.
		
			newEnergy = self.energy + (self.energyRchrg * dt)
			# determines what the new energy level will be.
			
			if(newEnergy > self.maxEnergy):
				self.energy = self.maxEnergy
			else:
				self.energy = newEnergy
			# if the new energy level exceeds to maximum, set
			# energy to max. Otherwise set energy to new level.
		
		if(self.shield <= 0 and self.shutDown == False):
			self.shutDown = True
			self.throttle = 0
			self.shield = 0
		# Checks if the cycle should enter emergency shut down and sets all
		# the appropriate values if so.
		
		if(self.shutDown == True):
			newShield = self.shield + (self.shieldRchrg * dt) * 10
		# finds the new shield level if the cycle is in emergency shut down.
			if(newShield >= self.maxShield):
				self.shutDown = False
			# Ends the emergency shut down when the shield is recharged.
		
		elif(self.shield < self.maxShield):
			newShield = self.shield + (self.shieldRchrg * dt)
		# finds the new shield level if the cycle is not in emergency shut
		# down, and needs to recharge its shield.
		
		else:
			return
		# If the cycle doesn't need to recharge its shield, we're done and
		# we can exit the method.
			
		if(newShield <= self.maxShield):
			self.shield = newShield
		else:
			self.shield = self.maxShield
		# if the new energy level exceeds to maximum, set
		# energy to max. Otherwise set energy to new level.
		
		return
# recharge: Evaluates the shield and energy levels of the cycle and recharges
# them if necessary. Also determines if the cycle needs to enter or exit 
# emergency shut down.
				
	def teleport(self):
		marker = self.track.trackLanes.getNearestMarker(self)
		markerPos = marker.getPos()
		self.root.setPos(markerPos.getX(), 
			markerPos.getY(), self.root.getZ())
		# Put the cycle back on the track.
		
		self.gCTrav.traverse(render)
		# Checks for collisions between the ground and the CollisionRays attached to the cycle.
		
		points = [None, None]
		# Preps a list to hold the data from the collisions.
		
		if(self.gHan.getNumEntries() > 1):
		# Verifies that at least 2 collisions occured. If not, there's no point in checking
		# the collisions because we can't get data from both rays.
		
			self.gHan.sortEntries()
			# Arranges the collision entries in the cues from nearest to furthest.
			
			for E in range(self.gHan.getNumEntries()):
			# Iterates through all the entries in the CollisionHandlerQueue
			
				entry = self.gHan.getEntry(E)
				# Stores the current entry in a temporary variable.
				
				if(entry.getFrom() == self.fRay and points[0] == None): 
				# Checks if this entry is a collision caused by the front ray, and 
				# verifies that we don't have front ray data for this frame yet.
					points[0] = entry.getSurfacePoint(render)
					# Stores the actual point of collision, in the coordinate system of render,
					# in the first slot of the points list.
				elif(entry.getFrom() == self.bRay and points[1] == None):
				# Checks if this entry is a collision caused by the back ray, and 
				# verifies that we don't have back ray data for this frame yet.
					points[1] = entry.getSurfacePoint(render)
					# Stores the actual point of collision, in the coordinate system of render,
					# in the second slot of the points list.
		
			if(self.speed >= 0): 
				self.trackNP.setPos(points[0].getX(), 
					points[0].getY(), points[0].getZ())
			else: 
				self.trackNP.setPos(points[1].getX(), 
					points[1].getY(), points[1].getZ())
			# Set the track node at the collision point on the leading end of the cycle.
			
			self.root.setZ(self.trackNP, 1)
			# Set the root to a height of 1 above trackNP.
			
		self.dirNP.setHpr(marker.getHpr())
		self.cycle.setHpr(marker.getHpr())
		# Reorients dirNP and the cycle to the same facing as the marker we teleported to.
		
		self.speed /= 2
		# Cuts the speed by half as a penalty for going off the track.
		
		return
# teleport: Moves the cycle back onto the track, fixes its height, and fixes its orientation.

	def bump(self, entry):
		#print(entry.getFromNodePath().getPythonTag("owner").name)
		#print("has bumped into:")
		#print(entry.getIntoNodePath().getPythonTag("owner").name)
		#print("")
		return
# bump: Prints a message to the command prompt when the cycle bumps into another cycle.
	
	def hit(self, damage):
		self.shield -= damage
		# reduces the shield strength according to the damage.
		
		instability = (damage / 2) - self.stability
		# calculates the instability caused by the damage.
		
		if(instability > 0):
			self.speed -= instability
		# if the instability is positive, reduce the cycle speed by
		# the instability.
		
		return
# hit: Handles tracking damage for the cycle.

	def getPos(self, ref = None):
		if(ref == None): return(self.root.getPos())
		else: return(self.root.getPos(ref))
# getPos: returns the position of root in the coordinate system of the given NodePath, if one is given.

	def destroy(self):
		self.root.removeNode()
		self.cycle.removeNode()
		self.mounts.delete()
		self.turretActor.delete()
		self.model.removeNode()
		self.turret.removeNode()
		self.fd.removeNode()
		self.rd.removeNode()
		self.dirNP.removeNode()
		self.refNP.removeNode()
		self.trackNP.removeNode()
		self.shieldCNP.removeNode()
		self.gRayCNP.removeNode()
		self.trgtrCNP.removeNode()
		self.glow.removeNode()
		# removes all of the cycle's NodePaths from the scene.
		
		self.LMG.destroy()
		self.LMG = None
		self.RMG.destroy()
		self.RMG = None
		self.cannon.destroy()
		self.cannon = None
		# Removes the cycle's weapons.
		
		self.audio3D.detachSound(self.engineSfx)
		
		self.cycle = None
		# sets self.cycle to None to end player cycle control and notify
		# any AI that the cycle is being removed.
		
		if(self.ai != None):
			self.ai = None
		# removes the cycles reference to the AI, if it has one.
		
		return
# destroy: Cleans up all of the cycles components so they can be removed
# from memory.
		
class Monster():
    def __init__(self, id, parent, type, pos):
        self.id = id
        self.parent = parent
        self.hp = 100
        self.speed = 1
        self.can_move = True
        
        if type == 'baby':
            self.node = Actor('models/baby', {'walk':'models/baby-walk', 
                                              'stand':'models/baby-stand',
                                              'idle':'models/baby-idle',
                                              'jump':'models/baby-jump',
                                              'bite1':'models/baby-bite1',
                                              'bite2':'models/baby-bite2',
                                              'head_attack':'models/baby-head_attack',                                
                                              'hit1':'models/baby-hit1',                                
                                              'hit2':'models/baby-hit2', 
                                              'die':'models/baby-die'})
            self.head_node = self.node.exposeJoint(None,"modelRoot","Bip01_Head")
            self.body_node = self.node.exposeJoint(None,"modelRoot","Bip01_Pelvis")
            self.node.setH(180)
            self.node.setScale(0.03)
            self.node.flattenLight()
            self.zpos = 0
            self.node.setPos(pos[0]*TILE_SIZE,pos[1]*TILE_SIZE,self.zpos)
            self.node.setTexture(loader.loadTexture('models/Zomby_D.png'))
            self.ts_normal = TextureStage('ts_normal')
            self.tex_normal = loader.loadTexture('models/Zomby_N.png')
            self.ts_normal.setMode(TextureStage.MNormal)
            self.node.setTexture(self.ts_normal, self.tex_normal)
            self.ts_gloss = TextureStage('ts_gloss')
            self.tex_gloss = loader.loadTexture('models/Zomby_S1.png')
            self.ts_gloss.setMode(TextureStage.MGloss)
            self.node.setTexture(self.ts_gloss, self.tex_gloss)   
            self.ts_glow = TextureStage('ts_glow')
            self.tex_glow = loader.loadTexture('models/Zomby_I.png')
            self.ts_glow.setMode(TextureStage.MGlow)
            self.node.setTexture(self.ts_glow, self.tex_glow)         
            self.node.reparentTo(render)
            self.node.loop('walk')
        elif type == 'nos':
            self.node = loader.loadModel('models/nos')
            self.zpos = 5
            self.node.setPos(pos[0]*TILE_SIZE,pos[1]*TILE_SIZE,self.zpos)
            self.node.setScale(2)
            if self.id == 1:
                self.node.setColor(1,0,0)
            elif self.id == 2:
                self.node.setColor(0,1,0)
            elif self.id == 3:
                self.node.setColor(0,0,1)
            else:
                self.node.setColor(1,1,1)
            self.node.reparentTo(render)


        #self.patrol_points = [(1,1), (4,11), (12,20), (18,4), (19,17)]
        
        #initialize 3d sound
        self.audio3d = Audio3DManager.Audio3DManager(base.sfxManagerList[0], base.camera)
        self.shot_head = self.audio3d.loadSfx('audio/Zombie In Pain-SoundBible.com-134322253.wav')
        self.shot_body = self.audio3d.loadSfx('audio/Zombie Moan-SoundBible.com-565291980.wav')
        self.moan1 = self.audio3d.loadSfx('audio/Mindless Zombie Awakening-SoundBible.com-255444348.wav')
        self.moan2 = self.audio3d.loadSfx('audio/Zombie Brain Eater-SoundBible.com-1076387080.wav')
        self.aggro_sound = self.audio3d.loadSfx('audio/Mummy Zombie-SoundBible.com-1966938763.wav')
        self.attack_sound = self.audio3d.loadSfx('audio/Chopping Off Limb-SoundBible.com-884800545.wav')
        self.audio3d.attachSoundToObject(self.moan1, self.node)
        self.audio3d.attachSoundToObject(self.moan2, self.node)
        self.audio3d.attachSoundToObject(self.shot_head, self.node)
        self.audio3d.attachSoundToObject(self.shot_body, self.node)
        self.audio3d.attachSoundToObject(self.aggro_sound, self.node)
        self.audio3d.attachSoundToObject(self.attack_sound, self.node)
        delay0 = Wait(d(35))
        delay1 = Wait(25+d(35))
        delay2 = Wait(25+d(35))
        self.moan_sequence = Sequence(delay0, SoundInterval(self.moan1), delay1, SoundInterval(self.moan2), delay2)
        self.moan_sequence.loop()
        
        self.parent.collision_manager.createMonsterCollision(self)

        self.aggro_sound_last_played = 0
        #--------------------------brain-------------------------
        self.node.setH( 160 )
        
        self.pause = False

        self.action = ACTION_IDLE

        if percent(20):
            self.orders = ORDERS_PATROL
        else:
            self.orders = ORDERS_IDLE

        self.last_melee = 0
        
        self.player_last_seen_abs = None

        self.idle_timer = time.time()
        self.idle_value = 1

        self.current_waypoint = None

        #self.wait_until = None
        self.herding_timer = None

        self.path = None

        taskMgr.doMethodLater(1, self.behaviourTask, 'MonsterBehaviourTask'+str(self.id) )
        taskMgr.doMethodLater(1, self.debugMoveTask, 'MonsterMoveTask'+str(self.id))


    def getLOS(self):
        return self.parent.collision_manager.checkMonsterPlayerLos(self)


    def sensePlayer(self):
        """Return True if player sensed, and his last known coordinates are stored in self.player_last_seen_abs"""
        
        # if the player is dead, do not sense him
        if self.parent.player.health <= 0:
            return False

        #get player's position
        p_pos_abs = self.parent.player.node.getPos()
        my_pos_abs = self.node.getPos()


        #--------------------------------SENSE---------------------------------
        #if player is within SENSING_RANGE we know he is there
        if self.distanceToPlayer() < SENSING_RANGE:
            #print "TOO CLOSE LOOSER!"
            self.player_last_seen_abs = p_pos_abs
            return True


        #---------------------------------HEAR----------------------------------
        #if player is within HEARING_RANGE we know he is there
        effective_hearing_range = HEARING_RANGE
        
        if self.parent.player.gunshot_at:
            effective_hearing_range *= 3
        else:
            if self.parent.player.sprint:
                effective_hearing_range *= 2
            if not self.parent.player.moving:
                effective_hearing_range = 0
                
        if self.distanceToPlayer() < effective_hearing_range:
            print "I HEAR U!"
            self.parent.player.adrenaline()
            #if we can see go chase him
            if self.getLOS():
                self.player_last_seen_abs = p_pos_abs
                return True
                
            #we cannot see him, build new path to that tile
            else:
                dest = getTile( p_pos_abs )
                path = pathFind(self.parent.level, getTile( self.node.getPos()), dest)
                if path:
                    self.path = path 
                    self.orders = ORDERS_PATROL
                    self.action = ACTION_FOLLOW_PATH
                    return False
                

        #-------------------------------SEE---------------------------------
        #if player is in front of us
        if self.angleToPlayerAbs() <= 45:
            #if he is close enough to see and we can see him
            if self.distanceToPlayer() <= VIEW_RANGE and self.getLOS():
                self.player_last_seen_abs = p_pos_abs
                #print "vidim!"
                return True
            
            #if player has a flashlight lit, and we can see him go after him
            if self.parent.player.flashlight and self.getLOS():
                self.player_last_seen_abs = p_pos_abs
                #print "vidim flashlight"
                return True
                
                
        #---------------------SEE MY OWN SHADOW---------------------------
        #if player is behind us and has a lit up flashlight and we have LOS to him
        if self.angleToPlayerAbs() > 135 and self.angleToPlayerAbs() < 225:
            if self.parent.player.flashlight and self.getLOS():
            
                #if he is looking at us
                my_pos_rel = self.node.getPos( self.parent.player.node )
                forward = Vec2( 0, 1 )
                if math.fabs( forward.signedAngleDeg( Vec2( my_pos_rel[0], my_pos_rel[1] ) ) ) <= 30:
                    #go after my own shadow
                    print "herding"
                    self.orders = ORDERS_HERDING
                    self.node.setH( self.parent.player.node.getH() )
                    self.herding_timer = time.time()
                
        return False        


    def distanceToPlayer(self):
        p_pos_abs = self.parent.player.node.getPos()
        my_pos_abs = self.node.getPos()
        return math.sqrt( math.pow( p_pos_abs[0] - my_pos_abs[0], 2) +  math.pow( p_pos_abs[1] - my_pos_abs[1], 2) )
        
        
    def angleToPlayer(self):
        p_pos_rel = self.parent.player.node.getPos( self.node )        
        forward = Vec2( 0, 1 )
        return forward.signedAngleDeg( Vec2( p_pos_rel[0], p_pos_rel[1] ) )
        
        
    def angleToPlayerAbs(self):
        return math.fabs( self.angleToPlayer() )


    def behaviourTask(self, task):
        if self.pause:
            return task.again
        
        #top priority, if we sense a player, go after him!
        if self.sensePlayer():
            if time.time() - self.aggro_sound_last_played > 5:
                self.aggro_sound.play()
                self.aggro_sound_last_played = time.time()
            
            self.action = ACTION_CHASE
            return task.again

        
        elif self.orders == ORDERS_IDLE:
            #percent chance to go on patrol
            if percent( 10 ):
                self.orders = ORDERS_PATROL
                return task.again
            self.action = ACTION_IDLE
            
        
        elif self.orders == ORDERS_PATROL:
            #percent chance to get idle
            if percent( 5 ):
                self.orders = ORDERS_IDLE
                return task.again
                      
            #if we are already patroling, dont change anything 
            if self.action == ACTION_FOLLOW_PATH:
                return task.again

            #build a new path for patrol
            dest = self.getNewPatrolPoint()
            self.path = pathFind(self.parent.level, getTile(self.node.getPos()), dest)
            self.action = ACTION_FOLLOW_PATH
                

        elif self.orders == ORDERS_HERDING:
            self.action = ACTION_MOVE
            if time.time() - self.herding_timer > HERDING_TIMEOUT:
                self.orders = ORDERS_IDLE
                
             
        return task.again
    
    
    def debugMoveTask(self, task):
        if self.pause:
            return task.cont

        #print "orders:", self.orders
        
        if self.action == ACTION_CHASE:
            self.parent.player.adrenaline()
            look_pos = Point3(self.player_last_seen_abs.getX(), self.player_last_seen_abs.getY(), self.zpos)
            self.node.lookAt( look_pos )
            self.node.setFluidPos(self.node, 0, CHASE_SPEED*globalClock.getDt(), 0)
                        
            if self.distanceToPlayer() <= MELEE_RANGE and self.angleToPlayerAbs() <= 45 and self.getLOS():
                if time.time() - self.last_melee >= MELEE_TIME:
                    self.attack_sound.play()
                    att = random.randint(0,2)
                    if att == 0:
                        animname = 'bite1'
                    elif att == 1:
                        animname = 'bite2'
                    else:
                        animname = 'head_attack'
                    self.node.play(animname)
                    duration = self.node.getNumFrames(animname) / 24  # animation play rate
                    taskMgr.doMethodLater(duration, self.finishedAnim, 'FinishedAnim', extraArgs = [])
                    self.parent.player.getDamage()
                    self.last_melee = time.time()
        
 
        elif self.action == ACTION_IDLE:
            if time.time() - self.idle_timer > IDLE_TIME:
                #we are standing still and rotating, see on whic side we will rotate now
                self.idle_timer = time.time()
                if percent(20):
                    self.idle_value *= -1
            self.rotateBy( self.idle_value * IDLE_ROTATE_SPEED )


        elif self.action == ACTION_FOLLOW_PATH:
            #if we dont have a waypoint, calculate one
            if not self.current_waypoint:
                try:
                    #get next tile from path
                    tile = self.path[0]
                    self.path = self.path[1:]
                    
                    #calculate waypoint
                    varx= 5 - (d(4) + d(4))
                    vary= 5 - (d(4) + d(4))
                    self.current_waypoint = (Point3( tile[0] * TILE_SIZE + varx, tile[1] * TILE_SIZE + vary, self.zpos ), time.time() )
                    #print "waypoint:", self.current_waypoint 
                    self.node.lookAt( self.current_waypoint[0] )
                    
                except (IndexError, TypeError):
                    #we have reached the end of path
                    self.orders = ORDERS_IDLE
                    self.current_waypoint = None
                    
            #if we have a waypoint move forward towards it, and check if we arrived at it
            else:
                self.node.setFluidPos(self.node, 0, NORMAL_SPEED*globalClock.getDt(), 0)
                my_pos = self.node.getPos() 
                
                #if we are close enough to the waypoint or if we didnt get to waypoint in time, delete it so we know we need a new one
                if math.fabs( my_pos[0] - self.current_waypoint[0][0] ) < 1 and math.fabs( my_pos[1] - self.current_waypoint[0][1] ) < 2 \
                        or time.time() - self.current_waypoint[1] > WAYPOINT_TIMER:
                    self.current_waypoint = None 


        elif self.action == ACTION_MOVE:
            self.node.setFluidPos(self.node, 0, NORMAL_SPEED*globalClock.getDt(), 0)            
 
 
        return task.cont

    def finishedAnim(self):
        if not self.pause:
            self.node.loop('walk')
        

    def rotateBy(self, value):
        self.node.setH( (self.node.getH() + value) % 360  )
        

    def getNewPatrolPoint(self):
        lvl = self.parent.level
        allTiles = lvl.getFloorTiles()
        while True:
            t = ( d(lvl.getMaxX()), d(lvl.getMaxY()) )
            if t in allTiles:
                return t
            

    def hitWall(self):
        
        if self.action == ACTION_CHASE:
            return
    
        #print "lupio!"
        """self.moan1.play()
        self.rotateBy( 180 )
        self.node.setFluidPos(self.node, 0, CHASE_SPEED*globalClock.getDt(), 0)            
        #self.action = IDLE
        """
        """
        old = self.node.getH()
        rnd = 80 + random.randint( 0, 20 )

        forward = Vec2( 0, 1 )
        impact = Vec2( pos[0], pos[1] )

        angle = forward.signedAngleDeg( impact )
        #print "angle:", angle
        
        if angle < 0:
            #+ cause angle is negative
            rnd = 91 + angle
            self.node.setH( (self.node.getH() + rnd)%360 )            
        elif angle > 0:
            rnd = -91 + angle
            self.node.setH( (self.node.getH() + rnd)%360 )
        
        #print "stari:", old, "  novi:", self.node.getH()    
        """ 
        pass

    def pauze(self):
        if self.moan_sequence:
            self.moan_sequence.pause()
        self.pause = True

        
    def resume(self):
        if self.moan_sequence:
            self.moan_sequence.resume()
        self.pause = False
        
        
    def destroy(self):
        self.audio3d.detachSound(self.moan1)
        self.audio3d.detachSound(self.moan2)
        self.audio3d.detachSound(self.shot_head)
        self.audio3d.detachSound(self.shot_body)
        self.audio3d.detachSound(self.aggro_sound)
        self.audio3d.detachSound(self.attack_sound)
        if self.moan_sequence != None:
            self.moan_sequence.pause()
            self.moan_sequence = None
        taskMgr.remove('MonsterBehaviourTask'+str(self.id))
        taskMgr.remove('MonsterMoveTask'+str(self.id))
        self.cn_head.node().clearPythonTag('node')
        self.cn_body.node().clearPythonTag('node')
        self.cn_pusher.node().clearPythonTag('node')  
        self.cn_ray.node().clearPythonTag('node')
        self.node.delete()
        self.node.cleanup()
        self.node.removeNode()
    
    """
示例#37
0
class Character(FSM.FSM, Vehicle):
    """
    An animated character with various steering behaviors. By enabling and
    disabling different steering behaviors Character can be used as
    a keyboard + mouse controlled player avatar, or can be controlled (for
    example) by a Finite State Machine and used to implement a non-player
    character.
    """

    # FIXME: Think it might be clearer and safer if Character has a FSM instead
    # of inheriting from FSM (classes that inherit from Character will likely
    # want to inherit from FSM too).

    def __init__(
            self,
            name='Ralph',
            model='models/ralph',
            run='models/ralph-run',
            walk='models/ralph-walk',
            pos=None,
            avoidObstacles=True,
            avoidVehicles=True,
            hprs=(180, 0, 0, 1, 1, 1),  # Ralph's Y is backward
    ):
        """Initialise the character.

        By default tries to load Panda3D's Ralph model: models/ralph,
        models/ralph-run and models/ralph-walk."""

        FSM.FSM.__init__(self, 'Character')
        Vehicle.__init__(self,
                         pos=pos,
                         avoidObstacles=avoidObstacles,
                         avoidVehicles=avoidVehicles,
                         radius=2.5)

        self.name = name
        self.lastPose = 0  # Used when transitioning between animations
        self.actor = Actor(model, {"run": run, "walk": walk})
        self.actor.setHprScale(*hprs)
        self.actor.reparentTo(self.prime)

        # Add a task for this Character to the global task manager.
        self.characterStepTask = taskMgr.add(self.characterStep,
                                             "Character step task")

    def characterStep(self, task):
        """Update the character. Called every frame by Panda's global task
        manager."""

        # Update the orientation of the Character. Want to face in the
        # direction of the Vehicle's velocity in the X and Y dimensions, but
        # always face straight forward (not up or down) in the Z dimension.
        pr = self.prime.getP(), self.prime.getR()
        self.prime.lookAt((self._pos + self._velocity).getX(),
                          (self._pos + self._velocity).getY(), 0)
        self.prime.setHpr(self.prime.getH(), *pr)

        # Animate the Character's Actor. The Character automatically changes
        # between stand, run and walk animations and varies the playrate of the
        # animations depending on the speed of the Character's Vehicle.
        speed = self.getspeed()
        if speed < .05:
            if self.getCurrentOrNextState() != 'Stand':
                self.request('Stand')
        elif speed < .25:
            self.actor.setPlayRate(speed * 4, "walk")
            if self.getCurrentOrNextState() != 'Walk':
                self.request('Walk')
        else:
            self.actor.setPlayRate(speed * 2, "run")
            if self.getCurrentOrNextState() != 'Run':
                self.request('Run')

        return Task.cont

    def destroy(self):
        """Prepare this Character to be garbage-collected by Python:
        
        Remove all of the Character's nodes from the scene graph, remove its
        CollisionSolids from the global CollisionTraverser, clear its
        CollisionHandler, remove tasks, destroy Actor.
        
        After executing this method, any remaining references to the Character
        object can be destroyed by the user module, and the Character will be
        garbage-collected by Python.
        """

        taskMgr.remove(self.characterStepTask)
        self.cleanup()
        self.actor.delete()
        Vehicle.destroy(self)

    # Methods for handling animations.

    def storeLastPose(self):
        currAnim = self.actor.getCurrentAnim()
        numFrames = self.actor.getNumFrames(currAnim)
        animFrame = self.actor.getCurrentFrame(currAnim)
        self.lastPose = float(animFrame) / float(numFrames)
        self.actor.stop(currAnim)

    def loopFromPose(self, animName):
        self.actor.pose(animName,
                        frame=self.lastPose *
                        self.actor.getNumFrames(animName))
        self.actor.loop(animName, restart=0)

    # FSM State handlers. Called when transitioning to a new state.
    def enterRun(self):
        self.loopFromPose("run")

    def exitRun(self):
        self.storeLastPose()

    def enterWalk(self):
        self.loopFromPose("walk")

    def exitWalk(self):
        self.storeLastPose()

    def enterStand(self):
        standPoseFrame = 6  # frame 6 (the most acceptable stand pose)
        numFrames = self.actor.getNumFrames("walk")
        lastFrame = self.lastPose * numFrames
        # "mirror" the frame to bring it closer to the most acceptable stand pose
        if lastFrame > .5 * (numFrames - 1):
            lastFrame = numFrames - 1 - lastFrame
        frameDiff = standPoseFrame - lastFrame
        # if already at stand pose, don't do anything
        if frameDiff == 0:
            return
        # forward animation playback
        if frameDiff >= 0:
            fromFrame = lastFrame
            toFrame = standPoseFrame
        else:
            # backward animation playback
            fromFrame = standPoseFrame
            toFrame = lastFrame
        playDir = 2 * frameDiff / numFrames
        self.actor.setPlayRate(playDir, "walk")
        self.actor.play("walk", fromFrame=fromFrame, toFrame=toFrame)
示例#38
0
class PlayerBase(DirectObject):
    def __init__(self):
        # Player Model setup
        self.player = Actor("Player",
                            {"Run":"Player-Run",
                            "Sidestep":"Player-Sidestep",
                            "Idle":"Player-Idle"})
        self.player.setBlend(frameBlend = True)
        self.player.setPos(0, 0, 0)
        self.player.pose("Idle", 0)
        self.player.reparentTo(render)
        self.player.hide()

        self.footstep = base.audio3d.loadSfx('footstep.ogg')
        self.footstep.setLoop(True)
        base.audio3d.attachSoundToObject(self.footstep, self.player)

        # Create a brush to paint on the texture
        splat = PNMImage("../data/Splat.png")
        self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1)

        CamMask = BitMask32.bit(0)
        AvBufMask = BitMask32.bit(1)
        self.avbuf = None
        if base.win:
            self.avbufTex = Texture('avbuf')
            self.avbuf = base.win.makeTextureBuffer('avbuf', 256, 256, self.avbufTex, True)
            cam = Camera('avbuf')
            cam.setLens(base.camNode.getLens())
            self.avbufCam = base.cam.attachNewNode(cam)
            dr = self.avbuf.makeDisplayRegion()
            dr.setCamera(self.avbufCam)
            self.avbuf.setActive(False)
            self.avbuf.setClearColor((1, 0, 0, 1))
            cam.setCameraMask(AvBufMask)
            base.camNode.setCameraMask(CamMask)

            # avbuf renders everything it sees with the gradient texture.
            tex = loader.loadTexture('gradient.png')
            np = NodePath('np')
            np.setTexture(tex, 100)
            np.setColor((1, 1, 1, 1), 100)
            np.setColorScaleOff(100)
            np.setTransparency(TransparencyAttrib.MNone, 100)
            np.setLightOff(100)
            cam.setInitialState(np.getState())
            #render.hide(AvBufMask)

        # Setup a texture stage to paint on the player
        self.paintTs = TextureStage('paintTs')
        self.paintTs.setMode(TextureStage.MDecal)
        self.paintTs.setSort(10)
        self.paintTs.setPriority(10)

        self.tex = Texture('paint_av_%s'%id(self))

        # Setup a PNMImage that will hold the paintable texture of the player
        self.imageSizeX = 64
        self.imageSizeY = 64
        self.p = PNMImage(self.imageSizeX, self.imageSizeY, 4)
        self.p.fill(1)
        self.p.alphaFill(0)
        self.tex.load(self.p)
        self.tex.setWrapU(self.tex.WMClamp)
        self.tex.setWrapV(self.tex.WMClamp)

        # Apply the paintable texture to the avatar
        self.player.setTexture(self.paintTs, self.tex)

        # team
        self.playerTeam = ""
        # A lable that will display the players team
        self.lblTeam = DirectLabel(
            scale = 1,
            pos = (0, 0, 3),
            frameColor = (0, 0, 0, 0),
            text = "TEAM",
            text_align = TextNode.ACenter,
            text_fg = (0,0,0,1))
        self.lblTeam.reparentTo(self.player)
        self.lblTeam.setBillboardPointEye()

        # basic player values
        self.maxHits = 3
        self.currentHits = 0
        self.isOut = False

        self.TorsorControl = self.player.controlJoint(None,"modelRoot","Torsor")

        # setup the collision detection
        # wall and object collision
        self.playerSphere = CollisionSphere(0, 0, 1, 1)
        self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision%d"%id(self)))
        self.playerCollision.node().addSolid(self.playerSphere)
        base.pusher.addCollider(self.playerCollision, self.player)
        base.cTrav.addCollider(self.playerCollision, base.pusher)
        # foot (walk) collision
        self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision%d"%id(self)))
        self.playerFootRay.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -1))
        self.playerFootRay.node().setIntoCollideMask(0)
        self.lifter = CollisionHandlerFloor()
        self.lifter.addCollider(self.playerFootRay, self.player)
        base.cTrav.addCollider(self.playerFootRay, self.lifter)

        # Player weapon setup
        self.gunAttach = self.player.exposeJoint(None, "modelRoot", "WeaponSlot_R")
        self.color = LPoint3f(1, 1, 1)
        self.gun = Gun(id(self))
        self.gun.reparentTo(self.gunAttach)
        self.gun.hide()
        self.gun.setColor(self.color)

        self.hud = None

        # Player controls setup
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0}
        # screen sizes
        self.winXhalf = base.win.getXSize() / 2
        self.winYhalf = base.win.getYSize() / 2
        self.mouseSpeedX = 0.1
        self.mouseSpeedY = 0.1
        # AI controllable variables
        self.AIP = 0.0
        self.AIH = 0.0

        self.movespeed = 5.0

        self.userControlled = False

        self.accept("Bulet-hit-playerCollision%d" % id(self), self.hit)
        self.accept("window-event", self.recalcAspectRatio)

    def runBase(self):
        self.player.show()
        self.gun.show()
        taskMgr.add(self.move, "moveTask%d"%id(self), priority=-4)

    def stopBase(self):
        taskMgr.remove("moveTask%d"%id(self))
        self.ignoreAll()
        self.gun.remove()
        self.footstep.stop()
        base.audio3d.detachSound(self.footstep)
        self.player.delete()

    def setKey(self, key, value):
        self.keyMap[key] = value

    def setPos(self, pos):
        self.player.setPos(pos)

    def setColor(self, color=LPoint3f(0,0,0)):
        self.color = color
        self.gun.setColor(color)
        c = (color[0], color[1], color[2], 1.0)
        self.lblTeam["text_fg"] = c

    def setTeam(self, team):
        self.playerTeam = team
        self.lblTeam["text"] = team


    def shoot(self, shotVec=None):
        self.gun.shoot(shotVec)
        if self.hud != None:
            self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition)

    def reload(self):
        self.gun.reload()
        if self.hud != None:
            self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition)

    def recalcAspectRatio(self, window):
        self.winXhalf = window.getXSize() / 2
        self.winYhalf = window.getYSize() / 2

    def hit(self, entry, color):
        self.currentHits += 1

        # Create a brush to paint on the texture
        splat = PNMImage("../data/Splat.png")
        splat = splat * LColorf(color[0], color[1], color[2], 1.0)
        self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1)

        self.paintAvatar(entry)

        if self.currentHits >= self.maxHits:
            base.messenger.send("GameOver-player%d" % id(self))
            self.isOut = True

    def __paint(self, s, t):
        """ Paints a point on the avatar at texture coordinates (s, t). """
        x = (s * self.p.getXSize())
        y = ((1.0 - t) * self.p.getYSize())

        # Draw in color directly on the avatar
        p1 = PNMPainter(self.p)
        p1.setPen(self.colorBrush)
        p1.drawPoint(x, y)

        self.tex.load(self.p)
        self.tex.setWrapU(self.tex.WMClamp)
        self.tex.setWrapV(self.tex.WMClamp)

        self.paintDirty = True

    def paintAvatar(self, entry):
        """ Paints onto an avatar.  Returns true on success, false on
        failure (because there are no avatar pixels under the mouse,
        for instance). """

        # First, we have to render the avatar in its false-color
        # image, to determine which part of its texture is under the
        # mouse.
        if not self.avbuf:
            return False

        #mpos = base.mouseWatcherNode.getMouse()
        mpos = entry.getSurfacePoint(self.player)
        ppos = entry.getSurfacePoint(render)

        self.player.showThrough(BitMask32.bit(1))
        self.avbuf.setActive(True)
        base.graphicsEngine.renderFrame()
        self.player.show(BitMask32.bit(1))
        self.avbuf.setActive(False)

        # Now we have the rendered image in self.avbufTex.
        if not self.avbufTex.hasRamImage():
            print "Weird, no image in avbufTex."
            return False
        p = PNMImage()
        self.avbufTex.store(p)
        ix = int((1 + mpos.getX()) * p.getXSize() * 0.5)
        iy = int((1 - mpos.getY()) * p.getYSize() * 0.5)
        x = 1
        if ix >= 0 and ix < p.getXSize() and iy >= 0 and iy < p.getYSize():
            s = p.getBlue(ix, iy)
            t = p.getGreen(ix, iy)
            x = p.getRed(ix, iy)
        if x > 0.5:
            # Off the avatar.
            return False

        # At point (s, t) on the avatar's map.

        self.__paint(s, t)
        return True

    def move(self, task):
        if self is None: return task.done
        if self.userControlled:
            if not base.mouseWatcherNode.hasMouse(): return task.cont
            self.pointer = base.win.getPointer(0)
            mouseX = self.pointer.getX()
            mouseY = self.pointer.getY()

            if base.win.movePointer(0, self.winXhalf, self.winYhalf):
                p = self.TorsorControl.getP() + (mouseY - self.winYhalf) * self.mouseSpeedY
                if p <-80:
                    p = -80
                elif p > 90:
                    p = 90
                self.TorsorControl.setP(p)

                h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX
                if h <-360:
                    h = 360
                elif h > 360:
                    h = -360
                self.player.setH(h)
        else:
            self.TorsorControl.setP(self.AIP)
            self.player.setH(self.AIH)

        forward =  self.keyMap["forward"] != 0
        backward = self.keyMap["backward"] != 0

        if self.keyMap["left"] != 0:
            if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward):
                self.player.loop("Sidestep")
                self.player.setPlayRate(5, "Sidestep")
            self.player.setX(self.player, self.movespeed * globalClock.getDt())
        elif self.keyMap["right"] != 0:
            if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward):
                self.player.loop("Sidestep")
                self.player.setPlayRate(5, "Sidestep")
            self.player.setX(self.player, -self.movespeed * globalClock.getDt())
        else:
            self.player.stop("Sidestep")
        if forward:
            if self.player.getCurrentAnim() != "Run":
                self.player.loop("Run")
                self.player.setPlayRate(5, "Run")
            self.player.setY(self.player, -self.movespeed * globalClock.getDt())
        elif backward:
            if self.player.getCurrentAnim() != "Run":
                self.player.loop("Run")
                self.player.setPlayRate(-5, "Run")
            self.player.setY(self.player, self.movespeed * globalClock.getDt())
        else:
            self.player.stop("Run")

        if not (self.keyMap["left"] or self.keyMap["right"] or
                self.keyMap["forward"] or self.keyMap["backward"] or
                self.player.getCurrentAnim() == "Idle"):
            self.player.loop("Idle")
            self.footstep.stop()
        else:
            self.footstep.play()

        return task.cont
示例#39
0
class MachineGun:
    def __init__(self, cycle, mount, audio3D):
        self.cycle = cycle
        self.name = "JR Martin J59 Jabber"

        self.actor = Actor("../Models/MGActor.egg")
        self.model = loader.loadModel("../Models/MachineGun.bam")
        self.actor.reparentTo(mount)
        self.model.reparentTo(self.actor)
        self.flashModel = loader.loadModel("../Models/LaserFlash.bam")
        self.projModel = loader.loadModel("../Models/LaserProj.bam")
        self.projModel.setScale(.25, 1, .25)

        self.refNP = self.cycle.trgtrMount.attachNewNode("MGRefNP")

        self.muzzle = self.actor.exposeJoint(None, "modelRoot", "Muzzle")

        self.audio3D = audio3D
        self.fireSfx = self.audio3D.loadSfx("../Sound/LaserShot.wav")
        self.audio3D.attachSoundToObject(self.fireSfx, self.muzzle)

        reloadTime = .25
        self.damage = 10
        self.energyCost = 1.25

        self.flashLerp = LerpScaleInterval(self.flashModel, reloadTime * .75,
                                           Point3(1, 1, 1), Point3(.1, .1, .1))

        self.firePar = Parallel(Func(self.checkForHit), Func(self.setEffects),
                                self.flashLerp)

        self.fireSeq = Sequence(self.firePar, Func(self.clearEffects),
                                Wait(reloadTime * .25))

    def fire(self):
        if (self.fireSeq.isPlaying() == False):
            self.fireSeq.start()
            self.fireSfx.play()
            self.cycle.energy -= self.energyCost
        return

    def setEffects(self):
        self.flashModel.reparentTo(self.muzzle)
        self.projModel.reparentTo(self.muzzle)
        self.projModel.lookAt(self.refNP.getPos(self.muzzle))
        self.projModel.setSy(
            trueDist(Point3(0, 0, 0), self.refNP.getPos(self.muzzle)) * 2)
        return

    def clearEffects(self):
        self.flashModel.detachNode()
        self.projModel.detachNode()
        return

    def checkForHit(self):
        self.cycle.trgtrCTrav.traverse(render)
        if (self.cycle.trgtrCHan.getNumEntries() > 0):
            self.cycle.trgtrCHan.sortEntries()
            entry = self.cycle.trgtrCHan.getEntry(0)
            # If collisions were detected sort them nearest to far and pull out the first one.

            colPoint = entry.getSurfacePoint(render)
            self.refNP.setPos(render, colPoint)
            # Get the collision point and the range to the collision.

            pop = Pop(colPoint)
            # Create an explosion at the collision point.

            thingHit = entry.getIntoNodePath()
            if (thingHit.hasPythonTag("owner")):
                thingHit.getPythonTag("owner").hit(self.damage)
        else:
            self.refNP.setPos(self.cycle.trgtrCNP, 0, 300, 0)
            pop = Pop(self.cycle.refNP.getPos(render))
            # If no collision was detected, create a pop at a distant point.

    def destroy(self):
        self.actor.delete()
        self.model.removeNode()
        self.flashModel.removeNode()
        self.projModel.removeNode()
        self.refNP.removeNode()
        self.cycle = None
        self.flashLerp = None
        self.firePar = None
        self.fireSeq = None
        self.audio3D.detachSound(self.fireSfx)
        return
示例#40
0
class DistributedPartyFireworksActivity(DistributedPartyActivity,
                                        FireworkShowMixin):

    notify = directNotify.newCategory("DistributedPartyFireworksActivity")

    def __init__(self, cr):
        """
        cr: instance of ClientRepository
        """
        DistributedPartyFireworksActivity.notify.debug("__init__")
        DistributedPartyActivity.__init__(self,
                                          cr,
                                          ActivityIds.PartyFireworks,
                                          ActivityTypes.HostInitiated,
                                          wantLever=True)
        FireworkShowMixin.__init__(self,
                                   restorePlaygroundMusic=True,
                                   startDelay=FireworksPostLaunchDelay)

    def setEventId(self, eventId):
        DistributedPartyFireworksActivity.notify.debug(
            "setEventId( %s )" % FireworkShows.getString(eventId))
        self.eventId = eventId

    def setShowStyle(self, showStyle):
        DistributedPartyFireworksActivity.notify.debug("setShowStyle( %d )" %
                                                       showStyle)
        self.showStyle = showStyle

    def load(self):
        """
        Load the necessary assets
        """
        DistributedPartyFireworksActivity.notify.debug("load")
        DistributedPartyActivity.load(self)

        self.eventId = PartyGlobals.FireworkShows.Summer

        # load the rocket platform and place it in party space
        self.launchPadModel = loader.loadModel(
            'phase_13/models/parties/launchPad')
        # Compensate for pivot of fireworks model and center it in 2x4 space
        self.launchPadModel.setH(90.0)
        self.launchPadModel.setPos(0.0, -18.0, 0.0)
        # reparent to root
        self.launchPadModel.reparentTo(self.root)
        # special case the depth testing on the railings to prevent
        # transparency oddness
        railingsCollection = self.launchPadModel.findAllMatches(
            "**/launchPad_mesh/*railing*")
        for i in range(railingsCollection.getNumPaths()):
            railingsCollection[i].setAttrib(
                AlphaTestAttrib.make(RenderAttrib.MGreater, 0.75))

        # place the lever on the platform
        leverLocator = self.launchPadModel.find("**/RocketLever_locator")
        self.lever.setPosHpr(Vec3.zero(), Vec3.zero())
        self.lever.reparentTo(leverLocator)
        self.toonPullingLeverInterval = None

        # place the activity sign
        self.sign.reparentTo(
            self.launchPadModel.find("**/launchPad_sign_locator"))

        # load the rocket with animation and place it on the platform
        self.rocketActor = Actor(
            'phase_13/models/parties/rocket_model',
            {'launch': 'phase_13/models/parties/rocket_launch'},
        )

        rocketLocator = self.launchPadModel.find("**/rocket_locator")
        self.rocketActor.reparentTo(rocketLocator)
        # ensure the rocket is never culled
        self.rocketActor.node().setBound(OmniBoundingVolume())
        self.rocketActor.node().setFinal(True)

        effectsLocator = self.rocketActor.find("**/joint1")
        self.rocketExplosionEffect = RocketExplosion(effectsLocator,
                                                     rocketLocator)

        self.rocketParticleSeq = None

        self.launchSound = base.loader.loadSfx(
            "phase_13/audio/sfx/rocket_launch.mp3")

        # create state machine and set initial state
        self.activityFSM = FireworksActivityFSM(self)
        self.activityFSM.request("Idle")

    def unload(self):
        DistributedPartyFireworksActivity.notify.debug("unload")
        taskMgr.remove(self.taskName("delayedStartShow"))
        if self.rocketParticleSeq:
            self.rocketParticleSeq.pause()
            self.rocketParticleSeq = None
        self.launchPadModel.removeNode()
        del self.launchPadModel
        del self.toonPullingLeverInterval
        self.rocketActor.delete()
        self.rocketExplosionEffect.destroy()
        self.activityFSM.request("Disabled")
        del self.rocketActor
        del self.launchSound
        del self.activityFSM
        del self.eventId
        del self.showStyle
        DistributedPartyActivity.unload(self)

    def _leverPulled(self, collEntry):
        DistributedPartyFireworksActivity.notify.debug("_leverPulled")
        hostPulledLever = DistributedPartyActivity._leverPulled(
            self, collEntry)
        if self.activityFSM.getCurrentOrNextState() == "Active":
            self.showMessage(TTLocalizer.PartyFireworksAlreadyActive)
        elif self.activityFSM.getCurrentOrNextState() == "Disabled":
            self.showMessage(TTLocalizer.PartyFireworksAlreadyDone)
        elif self.activityFSM.getCurrentOrNextState() == "Idle":
            if hostPulledLever:
                base.cr.playGame.getPlace().fsm.request(
                    "activity")  # prevent toon from moving
                self.toonPullingLeverInterval = self.getToonPullingLeverInterval(
                    base.localAvatar)
                self.toonPullingLeverInterval.append(
                    Func(self.d_toonJoinRequest))
                self.toonPullingLeverInterval.append(
                    Func(base.cr.playGame.getPlace().fsm.request, 'walk'))
                self.toonPullingLeverInterval.start()
            else:
                self.showMessage(TTLocalizer.PartyOnlyHostLeverPull)

    # FSM utility methods
    def setState(self, newState, timestamp):
        DistributedPartyFireworksActivity.notify.debug(
            "setState( newState=%s, ... )" % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        # pass additional parameters only to those states that need it
        if newState == "Active":
            self.activityFSM.request(newState, timestamp)
        else:
            self.activityFSM.request(newState)

    # FSM transition methods
    def startIdle(self):
        DistributedPartyFireworksActivity.notify.debug("startIdle")

    def finishIdle(self):
        DistributedPartyFireworksActivity.notify.debug("finishIdle")

    def startActive(self, showStartTimestamp):
        DistributedPartyFireworksActivity.notify.debug("startActive")
        messenger.send(FireworksStartedEvent)
        # if too much time has passed since the show started, don't bother
        # playing the rocket animation, just hide it
        timeSinceStart = globalClockDelta.localElapsedTime(showStartTimestamp)
        if timeSinceStart > self.rocketActor.getDuration("launch"):
            self.rocketActor.hide()
            self.startShow(self.eventId, self.showStyle, showStartTimestamp)
        else:
            self.rocketActor.play("launch")
            self.rocketParticleSeq = Sequence(Wait(RocketSoundDelay), \
                                                        Func(base.playSfx,self.launchSound), \
                                                        Func(self.rocketExplosionEffect.start), \
                                                        Wait(RocketDirectionDelay), \
                                                        LerpHprInterval(self.rocketActor, 4.0, Vec3(0, 0, -60)), \
                                                        Func(self.rocketExplosionEffect.end), \
                                                        Func(self.rocketActor.hide))
            self.rocketParticleSeq.start()

            # give rocket animation some time to play out before starting the show
            taskMgr.doMethodLater(
                FireworksPostLaunchDelay,
                self.startShow,
                self.taskName("delayedStartShow"),
                extraArgs=[
                    self.eventId, self.showStyle, showStartTimestamp, self.root
                ],
            )

    def finishActive(self):
        self.rocketParticleSeq = None
        DistributedPartyFireworksActivity.notify.debug("finishActive")
        messenger.send(FireworksFinishedEvent)
        taskMgr.remove(self.taskName("delayedStartShow"))
        FireworkShowMixin.disable(self)  # stop the fireworks show

    def startDisabled(self):
        DistributedPartyFireworksActivity.notify.debug("startDisabled")
        if not self.rocketActor.isEmpty():
            self.rocketActor.hide()  # so late comers won't see the rocket

    def finishDisabled(self):
        DistributedPartyFireworksActivity.notify.debug("finishDisabled")

    def handleToonDisabled(self, toonId):
        """
        A toon dropped unexpectedly from the game. Handle it!
        """
        self.notify.warning("handleToonDisabled no implementation yet")
class DistributedPartyJukeboxActivityBase(DistributedPartyActivity):
    notify = directNotify.newCategory("DistributedPartyJukeboxActivityBase")

    def __init__(self, cr, actId, phaseToMusicData):
        DistributedPartyActivity.__init__(self, cr, actId, ActivityTypes.Continuous)
        self.phaseToMusicData = phaseToMusicData
        self.jukebox = None
        self.gui = None
        self.tunes = []
        self.music = None
        self.currentSongData = None
        self.localQueuedSongInfo = None
        self.localQueuedSongListItem = None
        return

    def generateInit(self):
        self.gui = JukeboxGui(self.phaseToMusicData)

    def load(self):
        DistributedPartyActivity.load(self)
        self.jukebox = Actor(
            "phase_13/models/parties/jukebox_model", {"dance": "phase_13/models/parties/jukebox_dance"}
        )
        self.jukebox.reparentTo(self.root)
        self.jukebox.loop("dance", fromFrame=0, toFrame=48)
        self.collNode = CollisionNode(self.getCollisionName())
        self.collNode.setCollideMask(ToontownGlobals.CameraBitmask | ToontownGlobals.WallBitmask)
        collTube = CollisionTube(0, 0, 0, 0.0, 0.0, 4.25, 2.25)
        collTube.setTangible(1)
        self.collNode.addSolid(collTube)
        self.collNodePath = self.jukebox.attachNewNode(self.collNode)
        self.sign.setPos(-5.0, 0, 0)
        self.activate()

    def unload(self):
        DistributedPartyActivity.unload(self)
        self.gui.unload()
        if self.music is not None:
            self.music.stop()
        self.jukebox.stop()
        self.jukebox.delete()
        self.jukebox = None
        self.ignoreAll()
        return

    def getCollisionName(self):
        return self.uniqueName("jukeboxCollision")

    def activate(self):
        self.accept("enter" + self.getCollisionName(), self.__handleEnterCollision)

    def __handleEnterCollision(self, collisionEntry):
        if base.cr.playGame.getPlace().fsm.getCurrentState().getName() == "walk":
            base.cr.playGame.getPlace().fsm.request("activity")
            self.d_toonJoinRequest()

    def joinRequestDenied(self, reason):
        DistributedPartyActivity.joinRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyJukeboxOccupied)

    def handleToonJoined(self, toonId):
        toon = base.cr.doId2do.get(toonId)
        if toon:
            self.jukebox.lookAt(base.cr.doId2do[toonId])
            self.jukebox.setHpr(self.jukebox.getH() + 180.0, 0, 0)
        if toonId == base.localAvatar.doId:
            self.__localUseJukebox()

    def handleToonExited(self, toonId):
        if toonId == base.localAvatar.doId and self.gui.isLoaded():
            self.__deactivateGui()

    def handleToonDisabled(self, toonId):
        self.notify.warning("handleToonDisabled no implementation yet")

    def __localUseJukebox(self):
        base.localAvatar.disableAvatarControls()
        base.localAvatar.stopPosHprBroadcast()
        self.__activateGui()
        self.accept(JukeboxGui.CLOSE_EVENT, self.__handleGuiClose)
        taskMgr.doMethodLater(
            0.5, self.__localToonWillExitTask, self.uniqueName("toonWillExitJukeboxOnTimeout"), extraArgs=None
        )
        self.accept(JukeboxGui.ADD_SONG_CLICK_EVENT, self.__handleQueueSong)
        if self.isUserHost():
            self.accept(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT, self.__handleMoveSongToTop)
        return

    def __localToonWillExitTask(self, task):
        self.localToonExiting()
        return Task.done

    def __activateGui(self):
        self.gui.enable(timer=JUKEBOX_TIMEOUT)
        self.gui.disableAddSongButton()
        if self.currentSongData is not None:
            self.gui.setSongCurrentlyPlaying(self.currentSongData[0], self.currentSongData[1])
        self.d_queuedSongsRequest()
        return

    def __deactivateGui(self):
        self.ignore(JukeboxGui.CLOSE_EVENT)
        self.ignore(JukeboxGui.SONG_SELECT_EVENT)
        self.ignore(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT)
        base.cr.playGame.getPlace().setState("walk")
        base.localAvatar.startPosHprBroadcast()
        base.localAvatar.enableAvatarControls()
        self.gui.unload()
        self.__localClearQueuedSong()

    def isUserHost(self):
        return self.party.partyInfo.hostId == base.localAvatar.doId

    def d_queuedSongsRequest(self):
        self.sendUpdate("queuedSongsRequest")

    def queuedSongsResponse(self, songInfoList, index):
        if self.gui.isLoaded():
            for i in range(len(songInfoList)):
                songInfo = songInfoList[i]
                self.__addSongToQueue(songInfo, isLocalQueue=index >= 0 and i == index)

            self.gui.enableAddSongButton()

    def __handleGuiClose(self):
        self.__deactivateGui()
        self.d_toonExitDemand()

    def __handleQueueSong(self, name, values):
        self.d_setNextSong(values[0], values[1])

    def d_setNextSong(self, phase, filename):
        self.sendUpdate("setNextSong", [(phase, filename)])

    def setSongInQueue(self, songInfo):
        if self.gui.isLoaded():
            phase = sanitizePhase(songInfo[0])
            filename = songInfo[1]
            data = self.getMusicData(phase, filename)
            if data:
                if self.localQueuedSongListItem is not None:
                    self.localQueuedSongListItem["text"] = data[0]
                else:
                    self.__addSongToQueue(songInfo, isLocalQueue=True)
        return

    def __addSongToQueue(self, songInfo, isLocalQueue=False):
        isHost = isLocalQueue and self.isUserHost()
        data = self.getMusicData(sanitizePhase(songInfo[0]), songInfo[1])
        if data:
            listItem = self.gui.addSongToQueue(data[0], highlight=isLocalQueue, moveToTopButton=isHost)
            if isLocalQueue:
                self.localQueuedSongInfo = songInfo
                self.localQueuedSongListItem = listItem

    def __localClearQueuedSong(self):
        self.localQueuedSongInfo = None
        self.localQueuedSongListItem = None
        return

    def __play(self, phase, filename, length):
        self.music = base.loadMusic((MUSIC_PATH + "%s") % (phase, filename))
        if self.music:
            if (
                self.__checkPartyValidity()
                and hasattr(base.cr.playGame.getPlace().loader, "music")
                and base.cr.playGame.getPlace().loader.music
            ):
                base.cr.playGame.getPlace().loader.music.stop()
            self.music.setTime(0.0)
            self.music.setLoopCount(getMusicRepeatTimes(length))
            self.music.play()
            self.currentSongData = (phase, filename)

    def __stop(self):
        self.currentSongData = None
        if self.music:
            self.music.stop()
        if self.gui.isLoaded():
            self.gui.clearSongCurrentlyPlaying()
        return

    def setSongPlaying(self, songInfo, toonId):
        phase = sanitizePhase(songInfo[0])
        filename = songInfo[1]
        if not filename:
            self.__stop()
            return
        data = self.getMusicData(phase, filename)
        if data:
            self.__play(phase, filename, data[1])
            self.setSignNote(data[0])
            if self.gui.isLoaded():
                item = self.gui.popSongFromQueue()
                self.gui.setSongCurrentlyPlaying(phase, filename)
                if item == self.localQueuedSongListItem:
                    self.__localClearQueuedSong()
        if toonId == localAvatar.doId:
            localAvatar.setSystemMessage(0, TTLocalizer.PartyJukeboxNowPlaying)

    def __handleMoveSongToTop(self):
        if self.isUserHost() and self.localQueuedSongListItem is not None:
            self.d_moveHostSongToTopRequest()
        return

    def d_moveHostSongToTopRequest(self):
        self.notify.debug("d_moveHostSongToTopRequest")
        self.sendUpdate("moveHostSongToTopRequest")

    def moveHostSongToTop(self):
        self.notify.debug("moveHostSongToTop")
        if self.gui.isLoaded():
            self.gui.pushQueuedItemToTop(self.localQueuedSongListItem)

    def getMusicData(self, phase, filename):
        data = []
        phase = sanitizePhase(phase)
        phase = self.phaseToMusicData.get(phase)
        if phase:
            data = phase.get(filename, [])
        return data

    def __checkPartyValidity(self):
        if (
            hasattr(base.cr.playGame, "getPlace")
            and base.cr.playGame.getPlace()
            and hasattr(base.cr.playGame.getPlace(), "loader")
            and base.cr.playGame.getPlace().loader
        ):
            return True
        else:
            return False
class BossBattleHealthBar(DirectFrame):
    def __init__(self, dept, maxHp, **kw):
        DirectFrame.__init__(self, parent=render2d, relief=None, **kw)
        self.dept = dept
        self.filePrefix = ModelDict[dept]
        self.maxHp = float(maxHp)
        self.hp = self.maxHp

        self.head = None
        self.headActor = None
        self.animDict = {}

        self.healthBar = None
        self.healthCondition = None
        self.hitInterval = None
        self.blinkTask = None

        self.dizzy = False
        self.helmet = False

        self.healthColors = Suit.Suit.healthColors

    def load(self):
        self.head = loader.loadModel(self.filePrefix + '-head-zero')

        for anim in AnimList:
            self.animDict[anim] = '%s-%s-%s' % (GenericModel, 'head', anim)

        self.headActor = Actor(self.head, self.animDict)
        self.headActor.hide()
        self.headActor.setBin("fixed", 40)
        self.headActor.setDepthTest(True)
        self.headActor.setDepthWrite(True)

        self.headActor.reparentTo(self)
        self.headActor.setHpr(-90, 0, 270)
        self.headActor.setScale(0.021)
        self.headActor.setPos(-0.25, 0.0, 0.75)
        self.headActor.setPlayRate(2.0, 'turn2Fb')
        self.headActor.loop('Ff_neutral')

        self.eyes = loader.loadModel('phase_10/models/cogHQ/CashBotBossEyes.bam')
        self.eyes.setPosHprScale(4.5, 0, -2.5, 90, 90, 0, 0.4, 0.4, 0.4)
        self.eyes.reparentTo(self.headActor)
        self.eyes.hide()

        self.stars = globalPropPool.getProp('stun')
        self.stars.setPosHprScale(7, 0, 0, 0, 0, -90, 3, 3, 3)
        self.stars.loop('stun')

        self.safe = loader.loadModel('phase_10/models/cogHQ/CBSafe.bam')
        self.safe.reparentTo(self.headActor)
        self.safe.setPosHpr(-1, 0, 0.2, 0, -90, 90)
        self.safe.setBin("fixed", 40)
        self.safe.setDepthTest(True)
        self.safe.setDepthWrite(True)
        self.safe.hide()

        self.headActor.show()

        self.healthBar = DirectWaitBar(parent=self, pos=(0, 0, 0.85), relief=DGG.SUNKEN,
                                       frameSize=(-1.75, 1.75, -0.3, 0.3),
                                       borderWidth=(0.02, 0.02), scale=0.1, range=1, sortOrder=50,
                                       frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(0.75, 0.75, 1.0, 0.8), text='',
                                       text_scale=0.35, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter,
                                       text_pos=(0, -0.05), text_font=getSuitFont())

        self.updateHealthBar(self.maxHp)

    def getHealthCondition(self, hp):
        hp /= self.maxHp
        print hp
        if hp > 0.95:
            condition = 0
        elif hp > 0.9:
            condition = 1
        elif hp > 0.8:
            condition = 2
        elif hp > 0.7:
            condition = 3
        elif hp > 0.6:
            condition = 4
        elif hp > 0.5:
            condition = 5
        elif hp > 0.3:
            condition = 6
        elif hp > 0.15:
            condition = 7
        elif hp > 0.05:
            condition = 8
        elif hp > 0.0:
            condition = 9
        else:
            condition = 9

        return condition

    def updateHealthBar(self, hp):
        self.hp = float(hp)
        self.healthCondition = self.getHealthCondition(hp)

        if self.healthCondition == 9 and hp > 0:
            if self.blinkTask is None:
                self.startBlinkTask()
        elif self.blinkTask:
            self.stopBlinkTask()

        if self.healthBar:
            self.healthBar.setProp('text', str(int(hp)))
            self.healthBar.setProp('barColor', self.healthColors[self.healthCondition])
            self.healthBar.setProp('value', hp / self.maxHp)

        self.doHit()

    def cleanupHit(self):
        if self.hitInterval:
            self.hitInterval.finish()
            self.hitInterval = None
        return

    def doHit(self):
        self.cleanupHit()
        if not self.headActor:
            return

        self.hitInterval = Sequence(
            Parallel(
                Sequence(
                    Func(self.headActor.setColorScale, 1, 1, 1, 1),
                    self.headActor.colorScaleInterval(0.1, colorScale=VBase4(1, 0, 0, 1)),
                    self.headActor.colorScaleInterval(0.3, colorScale=VBase4(1, 1, 1, 1))
                ),
                ActorInterval(self.headActor, 'turn2Fb')
            ),
            Func(self.headActor.loop, 'Ff_neutral')
        )
        self.hitInterval.start()

    def startBlinkTask(self):
        self.blinkTask = Task.loop(Task(self.__blinkRed), Task.pause(0.75), Task(self.__blinkGray), Task.pause(0.1))
        taskMgr.add(self.blinkTask, 'bosshealthbar-blink-task')

    def __blinkRed(self, task):
        if not self.healthBar:
            return
        self.healthBar.setProp('barColor', self.healthColors[8])
        return Task.done

    def __blinkGray(self, task):
        if not self.healthBar:
            return
        self.healthBar.setProp('barColor', self.healthColors[9])
        return Task.done

    def stopBlinkTask(self):
        taskMgr.remove('bosshealthbar-blink-task')
        self.blinkTask = None

    def setDizzy(self, dizzy):
        self.dizzy = dizzy

        if dizzy:
            self.stars.reparentTo(self.headActor)
        else:
            self.stars.detachNode()

    def setHelmet(self, helmet):
        self.helmet = helmet

        if helmet:
            self.safe.show()
            self.eyes.show()

        else:
            self.safe.hide()
            self.eyes.hide()

    def destroy(self):
        self.cleanupHit()
        self.stars.cleanup()
        self.stopBlinkTask()
        self.healthBar.destroy()
        self.headActor.delete()
        self.head.removeNode()
        self.safe.removeNode()
        self.eyes.removeNode()