Example #1
0
    def __init__(self):
        ShowBase.__init__(self)
        
        self.createLoadScreen('./LEGameAssets/Textures/title_screen.png')
        base.graphicsEngine.renderFrame()
        
    #== Environment and Rendering Settings ==
        base.setFrameRateMeter(FLAG_SHOW_FRAMES_PER_SECOND)
        if FLAG_USE_AUTOSHADER:
            render.setShaderAuto()
        self.filters = CommonFilters(base.win, self.cam) # NEW
        if FLAG_SHOW_GLOW:
            bloomSize = 4#'small'
            filterok = self.filters.setBloom(blend=(0,0,0,1), desat=-0.5, intensity=3.0, size=bloomSize)
            if (filterok == False):
                print 'WARNING:Video card not powerful enough to do image postprocessing'
            
        #tex = loader.loadTexture("./LEGameAssets/Textures/loadbar_tray.png")
        self.loadBar = DirectWaitBar(text = "", value = 0, scale =(.35,.5,.5), pos = (0.006,.83,.83))
        #self.loadBar['barRelief'] = DirectWaitBar.GROOVE
        #self.loadBar['scale'] = 0.05
        #self.loadBar['barTexture'] = tex
        self.loadBar['barColor'] = (6.0/255.0, 11.0/255, 28.0/255.0, 1)
        self.loadBar.reparentTo(render2d)
        self.loadBar.hide()
        base.graphicsEngine.renderFrame()
        
        self.setBackgroundColor(166.0/255.0,207.0/255.0,240.0/255.0,1)
        self.skybox = self.loader.loadModel("LEGameAssets/Models/skybox_final.egg")
        self.skybox.setScale(50)
        self.skybox.reparentTo(render)
        
    #== Load the level and the managers ==
        self.assets, self.objects, self.gameObjects, self.sounds, self.sequences= loadWorld(SCENE_FILE, LIBRARY_INDEX)
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame() 
        
        
        self.conversations = loadConversations(SCENE_FILE, LIBRARY_INDEX)
        self.scenes = {}
        self.loadScenes()
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()
        
        self.journalMgr = JournalMgr(self)
        self.loadJournal(self.journalMgr,JOURNAL_FILE)
        
        self.conversationMgr = ConversationMgr(self, self.conversations)
        
        self.scriptMgr = ScriptMgr(self)
        self.scriptMgr.loadScripts(SCRIPTS_LIST)
        self.scriptInterface = ScriptInterface(self)
        
        self.inventoryMgr = InventoryMgr(self)
        loadInventory(self.inventoryMgr,INVENTORY_FILE)
        
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()
        
        self.ranSequences = []
        
    #== Main Character ==
        self.hero = None
        for name, gameObj in self.gameObjects.iteritems():
            if gameObj.getNP().hasTag('LE-mainChar'):
                self.hero = gameObj
                break
        else:
            # make a default hero
            defaultHeroNP = loader.loadModel("panda")
            self.hero = GameObject(defaultHeroNP)
            self.hero.reparentTo(render)
            self.hero.setPos(0, 0, 0)
            self.hero.setTag('LE-mainChar', '180')
            self.gameObjects[self.hero.getName()] = self.hero
        
        self.setCollideMasks(self.gameObjects)
             
        # remove the hero from the objects dict so it cannot be clicked by player
        if self.hero.getName() in self.objects:
            del self.objects[self.hero.getName()]
        
    #== Camera ==
        camHeightFactor = CAMERA_HEIGHT
        camTrailFactor = -CAMERA_TRAIL # careful of +/- distinction
        self.heroHeight = self.getModelHeight(self.hero)
        self.heroHeadingOffset = float(self.hero.getTag('LE-mainChar'))
        self.lastHeroH = self.hero.getH(render) + self.heroHeadingOffset
        
        # setup the camera pivot, which will follow the main character model and anchor the camera
        self.camPivot = NodePath('camPivot')
        self.camPivot.reparentTo(render)
        
        self.camHeight = camHeightFactor*self.heroHeight
        self.camTrail = camTrailFactor*self.heroHeight
        self.cam.setPos(self.camPivot.getPos() + (0, self.camTrail, self.camHeight))
        self.cam.wrtReparentTo(self.camPivot)
        
        self.placeCamera(self.hero) # match X and Y to main character
        self.alignCamera(self.hero) # match heading to main character
        #self.camPivot.setH(render, self.hero.getH(render) + self.heroHeadingOffset)
        
        self.gameCam = self.cam
        
    #== Collisions ==
        self.setupCollisions()
        
    #== Controls ==
        self.disableMouse()
        self.keyMap = { 'w':False, 'a':False, 's':False, 'd':False }
        self.enableMovement(self.hero)
        self.accept("mouse1", self.onClickin3D)
        self.accept('escape', sys.exit)
        
        self.accept('z', render.place) 
    
    #== UI and Combat ==
        self.gameplayUI = GameplayUI(self)
        self.gameplayUI.hideAll()
        
        # for health bars and on screen UI
        self.overlayAmbientLight = AmbientLight('overlayAmbientLight')
        self.overlayAmbientLight.setColor(VBase4(1.0, 1.0, 1.0, 1.0))
        self.overlayAmbientLightNP = render.attachNewNode(self.overlayAmbientLight)
        
        # initialize the combat manager (which includes AI) now that a main character and gameplayUI instance and overlay light is established
        self.combatMgr = CombatMgr(self)

        # initialize player's spells
        self.heroSpells = []
        for properties in PLAYER_SPELLS:
            spell = Spell(self.hero, properties)
            self.heroSpells.append(spell)
    
    #== Start Tasks
        taskMgr.add(self.moveHeroTask, 'moveHeroTask', appendTask=True)
        taskMgr.add(self.cameraFollowTask, 'cameraFollowTask', appendTask=True)
        taskMgr.add(self.processHeroCollisions, 'processHeroCollisions')
        taskMgr.add(self.updateHeroHeight, 'updateHeroHeight')
        self.combatMgr.startTasks()
        
        self.accept('enter', self.destroyLoadScreen)
        self.destroyLoadScreen()
    def __init__(self):
        ShowBase.__init__(self)

        self.createLoadScreen('./LEGameAssets/Textures/title_screen.png')
        base.graphicsEngine.renderFrame()

        #== Environment and Rendering Settings ==
        base.setFrameRateMeter(FLAG_SHOW_FRAMES_PER_SECOND)
        if FLAG_USE_AUTOSHADER:
            render.setShaderAuto()
        self.filters = CommonFilters(base.win, self.cam)  # NEW
        if FLAG_SHOW_GLOW:
            bloomSize = 4  #'small'
            filterok = self.filters.setBloom(blend=(0, 0, 0, 1),
                                             desat=-0.5,
                                             intensity=3.0,
                                             size=bloomSize)
            if (filterok == False):
                print 'WARNING:Video card not powerful enough to do image postprocessing'

        #tex = loader.loadTexture("./LEGameAssets/Textures/loadbar_tray.png")
        self.loadBar = DirectWaitBar(text="",
                                     value=0,
                                     scale=(.35, .5, .5),
                                     pos=(0.006, .83, .83))
        #self.loadBar['barRelief'] = DirectWaitBar.GROOVE
        #self.loadBar['scale'] = 0.05
        #self.loadBar['barTexture'] = tex
        self.loadBar['barColor'] = (6.0 / 255.0, 11.0 / 255, 28.0 / 255.0, 1)
        self.loadBar.reparentTo(render2d)
        self.loadBar.hide()
        base.graphicsEngine.renderFrame()

        self.setBackgroundColor(166.0 / 255.0, 207.0 / 255.0, 240.0 / 255.0, 1)
        self.skybox = self.loader.loadModel(
            "LEGameAssets/Models/skybox_final.egg")
        self.skybox.setScale(50)
        self.skybox.reparentTo(render)

        #== Load the level and the managers ==
        self.assets, self.objects, self.gameObjects, self.sounds, self.sequences = loadWorld(
            SCENE_FILE, LIBRARY_INDEX)
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()

        self.conversations = loadConversations(SCENE_FILE, LIBRARY_INDEX)
        self.scenes = {}
        self.loadScenes()
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()

        self.journalMgr = JournalMgr(self)
        self.loadJournal(self.journalMgr, JOURNAL_FILE)

        self.conversationMgr = ConversationMgr(self, self.conversations)

        self.scriptMgr = ScriptMgr(self)
        self.scriptMgr.loadScripts(SCRIPTS_LIST)
        self.scriptInterface = ScriptInterface(self)

        self.inventoryMgr = InventoryMgr(self)
        loadInventory(self.inventoryMgr, INVENTORY_FILE)

        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()

        self.ranSequences = []

        #== Main Character ==
        self.hero = None
        for name, gameObj in self.gameObjects.iteritems():
            if gameObj.getNP().hasTag('LE-mainChar'):
                self.hero = gameObj
                break
        else:
            # make a default hero
            defaultHeroNP = loader.loadModel("panda")
            self.hero = GameObject(defaultHeroNP)
            self.hero.reparentTo(render)
            self.hero.setPos(0, 0, 0)
            self.hero.setTag('LE-mainChar', '180')
            self.gameObjects[self.hero.getName()] = self.hero

        self.setCollideMasks(self.gameObjects)

        # remove the hero from the objects dict so it cannot be clicked by player
        if self.hero.getName() in self.objects:
            del self.objects[self.hero.getName()]

    #== Camera ==
        camHeightFactor = CAMERA_HEIGHT
        camTrailFactor = -CAMERA_TRAIL  # careful of +/- distinction
        self.heroHeight = self.getModelHeight(self.hero)
        self.heroHeadingOffset = float(self.hero.getTag('LE-mainChar'))
        self.lastHeroH = self.hero.getH(render) + self.heroHeadingOffset

        # setup the camera pivot, which will follow the main character model and anchor the camera
        self.camPivot = NodePath('camPivot')
        self.camPivot.reparentTo(render)

        self.camHeight = camHeightFactor * self.heroHeight
        self.camTrail = camTrailFactor * self.heroHeight
        self.cam.setPos(self.camPivot.getPos() +
                        (0, self.camTrail, self.camHeight))
        self.cam.wrtReparentTo(self.camPivot)

        self.placeCamera(self.hero)  # match X and Y to main character
        self.alignCamera(self.hero)  # match heading to main character
        #self.camPivot.setH(render, self.hero.getH(render) + self.heroHeadingOffset)

        self.gameCam = self.cam

        #== Collisions ==
        self.setupCollisions()

        #== Controls ==
        self.disableMouse()
        self.keyMap = {'w': False, 'a': False, 's': False, 'd': False}
        self.enableMovement(self.hero)
        self.accept("mouse1", self.onClickin3D)
        self.accept('escape', sys.exit)

        self.accept('z', render.place)

        #== UI and Combat ==
        self.gameplayUI = GameplayUI(self)
        self.gameplayUI.hideAll()

        # for health bars and on screen UI
        self.overlayAmbientLight = AmbientLight('overlayAmbientLight')
        self.overlayAmbientLight.setColor(VBase4(1.0, 1.0, 1.0, 1.0))
        self.overlayAmbientLightNP = render.attachNewNode(
            self.overlayAmbientLight)

        # initialize the combat manager (which includes AI) now that a main character and gameplayUI instance and overlay light is established
        self.combatMgr = CombatMgr(self)

        # initialize player's spells
        self.heroSpells = []
        for properties in PLAYER_SPELLS:
            spell = Spell(self.hero, properties)
            self.heroSpells.append(spell)

    #== Start Tasks
        taskMgr.add(self.moveHeroTask, 'moveHeroTask', appendTask=True)
        taskMgr.add(self.cameraFollowTask, 'cameraFollowTask', appendTask=True)
        taskMgr.add(self.processHeroCollisions, 'processHeroCollisions')
        taskMgr.add(self.updateHeroHeight, 'updateHeroHeight')
        self.combatMgr.startTasks()

        self.accept('enter', self.destroyLoadScreen)
        self.destroyLoadScreen()
Example #3
0
class World(ShowBase): # CONDISER: change to DirectObject/FSM
 
    def __init__(self):
        ShowBase.__init__(self)
        
        self.createLoadScreen('./LEGameAssets/Textures/title_screen.png')
        base.graphicsEngine.renderFrame()
        
    #== Environment and Rendering Settings ==
        base.setFrameRateMeter(FLAG_SHOW_FRAMES_PER_SECOND)
        if FLAG_USE_AUTOSHADER:
            render.setShaderAuto()
        self.filters = CommonFilters(base.win, self.cam) # NEW
        if FLAG_SHOW_GLOW:
            bloomSize = 4#'small'
            filterok = self.filters.setBloom(blend=(0,0,0,1), desat=-0.5, intensity=3.0, size=bloomSize)
            if (filterok == False):
                print 'WARNING:Video card not powerful enough to do image postprocessing'
            
        #tex = loader.loadTexture("./LEGameAssets/Textures/loadbar_tray.png")
        self.loadBar = DirectWaitBar(text = "", value = 0, scale =(.35,.5,.5), pos = (0.006,.83,.83))
        #self.loadBar['barRelief'] = DirectWaitBar.GROOVE
        #self.loadBar['scale'] = 0.05
        #self.loadBar['barTexture'] = tex
        self.loadBar['barColor'] = (6.0/255.0, 11.0/255, 28.0/255.0, 1)
        self.loadBar.reparentTo(render2d)
        self.loadBar.hide()
        base.graphicsEngine.renderFrame()
        
        self.setBackgroundColor(166.0/255.0,207.0/255.0,240.0/255.0,1)
        self.skybox = self.loader.loadModel("LEGameAssets/Models/skybox_final.egg")
        self.skybox.setScale(50)
        self.skybox.reparentTo(render)
        
    #== Load the level and the managers ==
        self.assets, self.objects, self.gameObjects, self.sounds, self.sequences= loadWorld(SCENE_FILE, LIBRARY_INDEX)
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame() 
        
        
        self.conversations = loadConversations(SCENE_FILE, LIBRARY_INDEX)
        self.scenes = {}
        self.loadScenes()
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()
        
        self.journalMgr = JournalMgr(self)
        self.loadJournal(self.journalMgr,JOURNAL_FILE)
        
        self.conversationMgr = ConversationMgr(self, self.conversations)
        
        self.scriptMgr = ScriptMgr(self)
        self.scriptMgr.loadScripts(SCRIPTS_LIST)
        self.scriptInterface = ScriptInterface(self)
        
        self.inventoryMgr = InventoryMgr(self)
        loadInventory(self.inventoryMgr,INVENTORY_FILE)
        
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()
        
        self.ranSequences = []
        
    #== Main Character ==
        self.hero = None
        for name, gameObj in self.gameObjects.iteritems():
            if gameObj.getNP().hasTag('LE-mainChar'):
                self.hero = gameObj
                break
        else:
            # make a default hero
            defaultHeroNP = loader.loadModel("panda")
            self.hero = GameObject(defaultHeroNP)
            self.hero.reparentTo(render)
            self.hero.setPos(0, 0, 0)
            self.hero.setTag('LE-mainChar', '180')
            self.gameObjects[self.hero.getName()] = self.hero
        
        self.setCollideMasks(self.gameObjects)
             
        # remove the hero from the objects dict so it cannot be clicked by player
        if self.hero.getName() in self.objects:
            del self.objects[self.hero.getName()]
        
    #== Camera ==
        camHeightFactor = CAMERA_HEIGHT
        camTrailFactor = -CAMERA_TRAIL # careful of +/- distinction
        self.heroHeight = self.getModelHeight(self.hero)
        self.heroHeadingOffset = float(self.hero.getTag('LE-mainChar'))
        self.lastHeroH = self.hero.getH(render) + self.heroHeadingOffset
        
        # setup the camera pivot, which will follow the main character model and anchor the camera
        self.camPivot = NodePath('camPivot')
        self.camPivot.reparentTo(render)
        
        self.camHeight = camHeightFactor*self.heroHeight
        self.camTrail = camTrailFactor*self.heroHeight
        self.cam.setPos(self.camPivot.getPos() + (0, self.camTrail, self.camHeight))
        self.cam.wrtReparentTo(self.camPivot)
        
        self.placeCamera(self.hero) # match X and Y to main character
        self.alignCamera(self.hero) # match heading to main character
        #self.camPivot.setH(render, self.hero.getH(render) + self.heroHeadingOffset)
        
        self.gameCam = self.cam
        
    #== Collisions ==
        self.setupCollisions()
        
    #== Controls ==
        self.disableMouse()
        self.keyMap = { 'w':False, 'a':False, 's':False, 'd':False }
        self.enableMovement(self.hero)
        self.accept("mouse1", self.onClickin3D)
        self.accept('escape', sys.exit)
        
        self.accept('z', render.place) 
    
    #== UI and Combat ==
        self.gameplayUI = GameplayUI(self)
        self.gameplayUI.hideAll()
        
        # for health bars and on screen UI
        self.overlayAmbientLight = AmbientLight('overlayAmbientLight')
        self.overlayAmbientLight.setColor(VBase4(1.0, 1.0, 1.0, 1.0))
        self.overlayAmbientLightNP = render.attachNewNode(self.overlayAmbientLight)
        
        # initialize the combat manager (which includes AI) now that a main character and gameplayUI instance and overlay light is established
        self.combatMgr = CombatMgr(self)

        # initialize player's spells
        self.heroSpells = []
        for properties in PLAYER_SPELLS:
            spell = Spell(self.hero, properties)
            self.heroSpells.append(spell)
    
    #== Start Tasks
        taskMgr.add(self.moveHeroTask, 'moveHeroTask', appendTask=True)
        taskMgr.add(self.cameraFollowTask, 'cameraFollowTask', appendTask=True)
        taskMgr.add(self.processHeroCollisions, 'processHeroCollisions')
        taskMgr.add(self.updateHeroHeight, 'updateHeroHeight')
        self.combatMgr.startTasks()
        
        self.accept('enter', self.destroyLoadScreen)
        self.destroyLoadScreen()
        
    

##== Utility and World Initialization functions =============================##
    
    def loadJournal(self,journalMgr,journalFile):
        f = open(Filename(journalFile).toOsSpecific())
        doc = xml.dom.minidom.parse(f)
        root = doc.childNodes[0]
        
        for n in root.childNodes:
            if n.localName == "journalEntries":
                journalMgr.decode(n)
        f.close()
    
    def getModelHeight(self, model):
        min, max = Point3(), Point3()
        model.calcTightBounds(min, max) 
        return max.getZ() - min.getZ()
    
    def createLoadScreen(self, imageFile='./LEGameAssets/Textures/load_screen.png'):
        self.loadScreen = OnscreenImage(image=imageFile)
        aspect2d.hide()
        self.loadScreen.reparentTo(render2d)
        if(hasattr(self, "gameplayUI")):
            self.gameplayUI.hideAll()

    def destroyLoadScreen(self):
        self.loadBar.hide()
        self.loadScreen.detachNode()
        self.loadScreen.destroy()
        aspect2d.show()
        self.ignore('enter')
        self.gameplayUI.showAll()
        for name, gameObj in self.gameObjects.iteritems():
            gameObj.callTrigger(self, 'LE-trigger-onScene')
    
    def startLoadBar(self, range=100):
        self.loadBar.show()
        self.loadBar['range'] = range
        self.loadBar['value'] = 0
        base.graphicsEngine.renderFrame()
        
    def increaseLoadBar(self, value):
        self.loadBar['value'] += value
        base.graphicsEngine.renderFrame()

##== Collisions =============================================================##
    
    def setupCollisions(self):
        self.cTrav = CollisionTraverser('mainTraverser')
        self.cTrav.setRespectPrevTransform(True)
        
        # Line collider for setting hero height based on ground geometry
        heroLine = CollisionNode('heroLine')
        heroLine.addSolid(CollisionRay(Point3(0,0,self.heroHeight), Vec3(0,0,-1)))
        heroLine.setFromCollideMask(BITMASK_GROUND)
        heroLine.setIntoCollideMask(BitMask32.allOff())
        self.heroGroundCollide = render.attachNewNode(heroLine)
        self.heroGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroGroundCollide, self.heroGroundHandler)
        
        
#        cameraSphere = CollisionNode('cameraSphere')
#        cameraSphere.addSolid(CollisionSphere(0,0,0,10))
#        cameraSphere.setFromCollideMask(BITMASK_CAMERA)
#        cameraSphere.setIntoCollideMask(BitMask32.allOff())
#        self.cameraSphereCollide = self.cam.attachNewNode(cameraSphere)
#        self.cameraSphereQueue = CollisionHandlerQueue()
#        self.cTrav.addCollider(self.cameraSphereCollide, self.cameraSphereQueue)
        
        
        self.herowallcollision = False
        
        self.heroWallCollideX = render.attachNewNode("heroWallX")
        self.heroWallCollideY = render.attachNewNode("heroWallY")
        self.heroWallCollideZ = render.attachNewNode("heroWallZ")
        
        # Line collider for running into obstacles and walls in X direction
        heroLineX = CollisionNode('heroLineX')
        heroLineX.addSolid(CollisionRay(Point3(0,0,0), Vec3(0,0,1)))
        self.heroWallCollideLineX = self.heroWallCollideX.attachNewNode(heroLineX)      
        self.heroWallCollideLineX.node().setFromCollideMask(BITMASK_WALL_TERRAIN)
        self.heroWallCollideLineX.node().setIntoCollideMask(BitMask32.allOff())
        self.heroWallQueueX = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideLineX, self.heroWallQueueX)
        
        # Line collider for running into obstacles and walls in Y direction
        heroLineY = CollisionNode('heroLineY')
        heroLineY.addSolid(CollisionRay(Point3(0,0,0), Vec3(0,0,1)))
        self.heroWallCollideLineY = self.heroWallCollideY.attachNewNode(heroLineY)      
        self.heroWallCollideLineY.node().setFromCollideMask(BITMASK_WALL_TERRAIN)
        self.heroWallCollideLineY.node().setIntoCollideMask(BitMask32.allOff())
        self.heroWallQueueY = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideLineY, self.heroWallQueueY)
        
        # Line collider for running into obstacles and walls in Z direction
        heroLineZ = CollisionNode('heroLineZ')
        heroLineZ.addSolid(CollisionRay(Point3(0,0,0), Vec3(0,0,1)))
        self.heroWallCollideLineZ = self.heroWallCollideZ.attachNewNode(heroLineZ)      
        self.heroWallCollideLineZ.node().setFromCollideMask(BITMASK_WALL_TERRAIN)
        self.heroWallCollideLineZ.node().setIntoCollideMask(BitMask32.allOff())
        self.heroWallQueueZ = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideLineZ, self.heroWallQueueZ)
        
#        # Sphere collider for running into obstacles and walls
#        heroSphere = CollisionNode('heroSphere')
#        heroSphere.addSolid(CollisionSphere(0,0,0,7))
#        self.heroWallCollide = render.attachNewNode(heroSphere)        
#        self.heroWallCollide.node().setFromCollideMask(BITMASK_WALL)
#        self.heroWallCollide.node().setIntoCollideMask(BitMask32.allOff())
#        self.heroWallQueue = CollisionHandlerQueue()
#        self.cTrav.addCollider(self.heroWallCollide, self.heroWallQueue)
#        self.herowallcollision = False
        
        # Sphere collider for running into obstacles and walls in X direction
        heroSphereX = CollisionNode('heroSphereX')
        heroSphereX.addSolid(CollisionSphere(0,0,0,7))
        self.heroWallCollideSphereX = self.heroWallCollideX.attachNewNode(heroSphereX)      
        self.heroWallCollideSphereX.node().setFromCollideMask(BITMASK_WALL)
        self.heroWallCollideSphereX.node().setIntoCollideMask(BitMask32.allOff())
        #self.heroWallQueueX = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideSphereX, self.heroWallQueueX)
        self.herowallcollision = False
        
        # Sphere collider for running into obstacles and walls in Y direction
        heroSphereY = CollisionNode('heroSphereY')
        heroSphereY.addSolid(CollisionSphere(0,0,0,7))
        self.heroWallCollideSphereY = self.heroWallCollideY.attachNewNode(heroSphereY)      
        self.heroWallCollideSphereY.node().setFromCollideMask(BITMASK_WALL)
        self.heroWallCollideSphereY.node().setIntoCollideMask(BitMask32.allOff())
        #self.heroWallQueueY = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideSphereY, self.heroWallQueueY)
        
        # Sphere collider for running into obstacles and walls in Z direction
        heroSphereZ = CollisionNode('heroSphereZ')
        heroSphereZ.addSolid(CollisionSphere(0,0,0,7))
        self.heroWallCollideSphereZ = self.heroWallCollideZ.attachNewNode(heroSphereZ)      
        self.heroWallCollideSphereZ.node().setFromCollideMask(BITMASK_WALL)
        self.heroWallCollideSphereZ.node().setIntoCollideMask(BitMask32.allOff())
        #self.heroWallQueueZ = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideSphereZ, self.heroWallQueueZ)
        
        
        
        
        
        
        
        # Ray collider for clicking on objects in the game
        self.pickerCollisionQueue = CollisionHandlerQueue()
        self.pickerCN = CollisionNode('pickerRayCN')
        self.pickerCNP = self.cam.attachNewNode(self.pickerCN)
        self.pickerCN.setFromCollideMask(BITMASK_CLICK)
        self.pickerCN.setIntoCollideMask(BitMask32.allOff())
        self.pickerRay = CollisionRay()
        self.pickerCN.addSolid(self.pickerRay)
        self.cTrav.addCollider(self.pickerCNP, self.pickerCollisionQueue)
    
        # Sphere collider for triggering scripts
        self.heroCN = CollisionNode('heroCN')
        self.heroCN.addSolid(CollisionSphere(0, 0, 0, 5)) # TODO: find good radius
        self.heroCNP = self.hero.attachNewNode(self.heroCN)
        self.heroCN.setFromCollideMask(BITMASK_HERO_COLLIDE)
        self.heroCN.setIntoCollideMask(BitMask32.allOff())
        self.heroCollisionQueue = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroCNP, self.heroCollisionQueue)
        
        # Line collider for transparency
        self.cameraEntriesPre = []
        radius = self.getModelHeight(self.hero)*CAMERA_TRAIL/2
        self.cameraCollisionQueue = CollisionHandlerQueue()
        self.cameraHero = CollisionNode('cameraHero')
        self.cameraHeroLine = CollisionSegment(self.hero.getPos(render), self.cam.getPos(render))
        self.cameraHero.addSolid(self.cameraHeroLine)
        self.cameraHero.setFromCollideMask(BITMASK_CAMERA)
        self.cameraHero.setIntoCollideMask(BitMask32.allOff())
        self.cameraHeroP = self.render.attachNewNode(self.cameraHero)
        self.cTrav.addCollider(self.cameraHeroP, self.cameraCollisionQueue)
        #self.cameraHeroP.show()
        
        if FLAG_SHOW_COLLISIONS:
            self.cTrav.showCollisions(render)
            # TODO: show specific collision nodepaths
    
    def setCollideMasks(self, gameObjDict):
        for name, obj in gameObjDict.iteritems():
            bitmask = obj.getCollideMask()
            if obj.hasTag('LE-ground'):
                bitmask |= BITMASK_GROUND
                #obj.getNP().setCollideMask(bitmask) # TODO: remove
            if obj.hasTag('LE-attackable'):
                bitmask |= BITMASK_CLICK
            if obj.hasTag('LE-wall'):
                if(isinstance(obj.getNP(), GeoMipTerrain)):
                    bitmask |= BITMASK_TERRAIN
                else:
                    bitmask |= BITMASK_WALL
            if obj.scripts.has_key('LE-trigger-onClick'):
                bitmask |=BITMASK_CLICK
            if obj.scripts.has_key('LE-trigger-onCollision'):
                bitmask |=BITMASK_HERO_COLLIDE
            if obj.hasTag('OBJRoot'):
                if obj.hasTag('LE-ground') or obj.hasTag('LE-mainChar'):
                    pass
                else:
                    bitmask |= BITMASK_CAMERA
                
            obj.setCollideMask(bitmask)
      
    def onClickin3D(self):
        pickedObj = None
        if self.conversationMgr.isConversationOpen():
            return
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
        else:
            return
            
        self.cTrav.addCollider(self.pickerCNP, self.pickerCollisionQueue)
        
        self.pickerRay.setFromLens(self.cam.node(), mpos.getX(), mpos.getY())
        
        self.cTrav.traverse(render)
        if(self.pickerCollisionQueue.getNumEntries() > 0):
            self.pickerCollisionQueue.sortEntries()
        for i in range(self.pickerCollisionQueue.getNumEntries()):
            parent = self.pickerCollisionQueue.getEntry(i).getIntoNodePath().getParent()
            while not self.objects.has_key(parent.getName()):
                if(parent.getName() == "render"):
                    return
                parent = parent.getParent()
            pickedObj = parent
            
            if(pickedObj == None):
                continue
            else:
                break
            
            #if pickedObj.hasTag("LE-trigger-onClick"): # TODO: needed, or is having key in self.objects enough?
        if (pickedObj == None):
            return
        
        self.pickerCollisionQueue.clearEntries()
        
        self.cTrav.removeCollider(self.pickerCNP)
        
        gameObj = self.gameObjects[pickedObj.getName()]
        distToTarget = self.hero.getDistance(gameObj)
        
        if self.combatMgr.checkCanAttack(self.hero, gameObj):
            if distToTarget <= self.heroSpells[self.curSpellIndex].getAttackRange():
                self.combatMgr.queueAttack(self.hero, self.heroSpells[self.curSpellIndex], gameObj)
            else:
                textObject = OnscreenText(text = 'The target is out of range!',fg =(1,0,0,1), pos = (0, 0), scale = 0.09, align = TextNode.ACenter )
                def destroyWarning1():
                    textObject.destroy()
                sequence =Sequence(Wait(2), Func(destroyWarning1))
                sequence.start()
                return
        elif(distToTarget > CLICK_RANGE):
            textObject = OnscreenText(text = 'The target is out of range!',fg =(1,0,0,1), pos = (0, 0), scale = 0.09, align = TextNode.ACenter )
            def destroyWarning2():
                textObject.destroy()
            sequence =Sequence(Wait(2), Func(destroyWarning2))
            sequence.start()
            return
        gameObj.callTrigger(self, 'LE-trigger-onClick')
        
        
            

    
    # Task for processing hero's collisions with GameObjects, triggering OnCollision scripts
    def processHeroCollisions(self, task):
        #self.cTrav.traverse(render)
        debug("processHeroCollisions")
        # CONSIDER: may not be necessary to sort
        if(self.heroCollisionQueue.getNumEntries() > 0):
            self.heroCollisionQueue.sortEntries()
        debug("queue size: "+str(self.heroCollisionQueue.getNumEntries()))
        for i in range(self.heroCollisionQueue.getNumEntries()):
            # CONSIDER: if entry.hasInto(): for efficiency
             
            debug("i: "+str(i))   
            # TODO: check if GameObject is passable, and react accordingly (store old position, revert to it)
            if(self.heroCollisionQueue.getNumEntries() <= 0):
                return
            entry = self.heroCollisionQueue.getEntry(i)
            debug("entry: "+str(entry))
            if(entry):
                intoNP = entry.getIntoNodePath()
            else:
                continue
            if (intoNP != None) or (not intoNP.isEmpty()):
                while not self.objects.has_key(intoNP.getName()):
                    if(intoNP.getName() == "render"):
                        return task.cont
                    intoNP = intoNP.getParent()
                pickedObj = intoNP
                
                if pickedObj == None:
                    continue
                gameObj = self.gameObjects[pickedObj.getName()]
                gameObj.callTrigger(self, 'LE-trigger-onCollision')
                
        return task.cont

##== Camera Movement ========================================================##

    # places the camera pivot to match the position of the node path parameter
    # used to have the camera pivot match the main character's position as he moves
    def placeCamera(self, np):
        self.camPivot.setX(render, np.getX(render))
        self.camPivot.setY(render, np.getY(render))
    
    def alignCamera(self, np):
        self.camPivot.setH(render, self.hero.getH(render) + self.heroHeadingOffset)
        self.cam.setP(CAMERA_PITCH)
    
    def cameraFollowTask(self, task):
        heroH = self.hero.getH(render) + self.heroHeadingOffset
        camPivotH = self.camPivot.getH(render)
        
        # normalizes the headings to avoid jumps in the difference
        # which could come from passing 360 and going back to 0, for example
        # TODO: stress test, esp. with different values of self.heroHeadingOffset
        while heroH + 180 < camPivotH:
            heroH += 360
        while camPivotH + 180 < heroH:
            camPivotH += 360
              
        self.lastHeroH = heroH
        rotateLeft = (heroH >= camPivotH)
        rotateRight = not rotateLeft
        diff = math.fabs(heroH - camPivotH)

        if diff > CAMERA_TURN_THRESHOLD:
            if rotateLeft:
                self.camPivot.setH(self.camPivot.getH() + CAMERA_TURN_SPEED)
            elif rotateRight:
                self.camPivot.setH(self.camPivot.getH() - CAMERA_TURN_SPEED)
        
#        if(len(self.cameraEntriesPre)>0):
#            #print self.cameraEntriesPre
#            if(self.hero.getDistance(self.cam) > 5):
#                moveAmount = min(globalClock.getDt()*200,5.0)
#                pos = self.cam.getQuat().getForward()*moveAmount
#                newpos = self.cam.getPos() + pos
#                self.oldCameraEntriesPre = []
#                for e in self.cameraEntriesPre:
#                    self.oldCameraEntriesPre.append(e)
#                self.cam.setFluidPos(newpos)
#            
#        else:
#            if(self.hero.getDistance(self.cam) < 100):
#                moveAmount = min(globalClock.getDt()*200,5.0)
#                pos = self.cam.getQuat().getForward()*(-moveAmount)
#                oldpos = self.cam.getPos()
#                newpos = self.cam.getPos() + pos
#                self.cam.setFluidPos(newpos)
#                for e in self.oldCameraEntriesPre:
#                    #print e.getIntoNodePath()
#                    self.cTrav.traverse(e.getIntoNodePath())
#                #self.cTrav.traverse(render)
#                    if(len(self.cameraSphereQueue.getEntries())>0):
#                        self.cam.setFluidPos(oldpos)
            
        
        return task.cont
    

    def runCamera(self, cameraName, sequence, isLoop = False):
        debug("Running the camera")
        #debug(str(self.sequences))

        self.oldCamera = self.cam
        self.dr = self.win.makeDisplayRegion()
        
        dr2 = self.cam.node().getDisplayRegion(0)#
        self.objects[cameraName].node().setLens(base.camLens)
        parent = self.cam.getParent()
        self.cam.detachNode()

        self.dr.setCamera(self.objects[cameraName])
        
        def temp():

            dr2.setCamera(self.oldCamera)
            self.oldCamera.reparentTo(parent)
            self.dr.setActive(False)
            del self.dr
            self.dr = None
            self.accept("mouse1", self.onClickin3D) 
            debug("Ran")
            
        if(isLoop):
            newSequence = Sequence(sequence)
            self.addSequence(newSequence)
            def stopCameraFromLoop():
                newSequence.finish()
                temp()
            self.accept("mouse1", stopCameraFromLoop)
            self.addSequence(newSequence)
            newSequence.loop()
        else:
            newSequence = Sequence(sequence,Func(temp))
            def stopCamera():
                newSequence.finish()
            self.accept("mouse1", stopCamera)
            self.addSequence(newSequence)
            newSequence.start()
        
 
 
##== Character Movement =====================================================##

    def moveHeroTo(self, destinationObj):
        pos = destinationObj.getPos(render)
        hpr = destinationObj.getHpr(render)
        self.hero.setPosHpr(render, pos, hpr)
        self.placeCamera(self.hero)
        self.alignCamera(self.hero)

    def updateHeroHeight(self, task=None):
        groundEntries = []
        #move the collision line to the hero position
        self.heroGroundCollide.setPos(self.hero.getPos(render))
        
        #loop through every collision entry for the line
        for e in self.heroGroundHandler.getEntries():
            if e.getIntoNodePath().hasNetTag('OBJRoot'):
                #find the actual root of the object
                np = e.getIntoNodePath().findNetTag('OBJRoot')
                #only react to objects that are tagged as the ground
                if np.hasTag('LE-ground'):
                    groundEntries.append(e)
                    
        if groundEntries:
            #sort the collision entries based on height
            groundEntries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),\
x.getSurfacePoint(render).getZ()))

            #set hero height and pivot height
            self.hero.setZ(groundEntries[0].getSurfacePoint(render).getZ() + MAIN_CHAR_GROUND_OFFSET)
            self.camPivot.setZ(groundEntries[0].getSurfacePoint(render).getZ() + MAIN_CHAR_GROUND_OFFSET)
            # TODO: unlink these from being in the same task in case we want pivot to not be linked to hero (ex. cutscene)
        
        self.heroGroundHandler.clearEntries()
        return task.cont
    
    def updateHeroPos(self, queue, stepSize):
        wallEntries = []
        for w in queue.getEntries():
            np = w.getIntoNodePath().findNetTag('OBJRoot')
            if np.hasTag('LE-wall'):
                if self.isInObstacleRange(self.hero, w, stepSize):
                    wallEntries.append(w)
        if len(wallEntries) > 0:
            self.herowallcollision = True
            #self.collisionsurfaceP = wallEntries[0].getSurfacePoint(render)
        else:
            self.herowallcollision = False
            
    def updateCameraCollision(self):
        self.cameraHeroLine.setPointA(self.cam.getPos(render))
        self.cameraHeroLine.setPointB(self.hero.getPos(render))

        if(self.cameraEntriesPre):
            for i in self.cameraEntriesPre:
                i.getIntoNodePath().setTransparency(TransparencyAttrib.MAlpha)
                i.getIntoNodePath().setAlphaScale(1.0)
            del self.cameraEntriesPre[:]
            
        for i in self.cameraCollisionQueue.getEntries():
            i.getIntoNodePath().setAlphaScale(0.5)
            self.cameraEntriesPre.append(i)
        
        
            
        

    def moveHero(self,direction, dt):
        temp = render.attachNewNode("Dummy")#NodePath()
        moveStep = MAIN_CHAR_MOVE_SPEED*dt
        if moveStep > MAIN_CHAR_MAX_STEP:
            moveStep = MAIN_CHAR_MAX_STEP
        temp.setPos(self.camPivot, 0,direction*moveStep, 0)
        
        #oldPos = self.heroWallCollideX.getPos()
        self.heroWallCollideX.setX(temp.getX())
        self.heroWallCollideY.setY(temp.getY())
        self.heroWallCollideZ.setZ(temp.getZ())#+10)
        self.cTrav.traverse(render)
        
        #check on X direction
        self.updateHeroPos(self.heroWallQueueX, moveStep)
        self.moveHeroToWallCollide(Point3(temp.getX(),self.hero.getY(),self.hero.getZ()))
        
        #check on Y direction
        self.updateHeroPos(self.heroWallQueueY, moveStep)
        self.moveHeroToWallCollide(Point3(self.hero.getX(),temp.getY(),self.hero.getZ()))
        
        #check on Z direction
        self.updateHeroPos(self.heroWallQueueZ, moveStep)
        self.moveHeroToWallCollide(Point3(self.hero.getX(),self.hero.getY(),temp.getZ()))
        
        
        self.heroWallCollideX.setPos(self.hero.getPos())
        self.heroWallCollideY.setPos(self.hero.getPos())
        self.heroWallCollideZ.setPos(self.hero.getPos())
        
        self.placeCamera(self.hero)
        self.updateCameraCollision()
        temp.detachNode()
        
    def moveHeroToWallCollide(self,pos):
        if self.herowallcollision==False:
            self.hero.setPos(pos)#self.camPivot, 0, MAIN_CHAR_MOVE_SPEED, 0)
    
    def isInObstacleRange(self, mover, colEntry, stepSize):
        colPoint = colEntry.getSurfacePoint(render)
        if colPoint[2] >= mover.getZ(render):
            dist = findDistance3D(mover.getX(), mover.getY(), mover.getZ(), colPoint[0], colPoint[1], colPoint[2])
            obstacleThreshold = self.heroHeight*self.heroHeight + stepSize*stepSize
            if dist*dist <= obstacleThreshold:
                return True
        return False

    
    def turnHeroLeft(self):
        up = render.getRelativeVector(base.cam, Vec3(0, 0, 1))
        up.normalize()
        
        curHeroQuat = self.hero.getQuat()
        newHeroQuat = Quat()
        newHeroQuat.setFromAxisAngle(MAIN_CHAR_ROTATE_SPEED, up)
        self.hero.setQuat(curHeroQuat*newHeroQuat)
        self.hero.setR(0)
        self.hero.setP(0)
        self.updateCameraCollision()
        
    def turnHeroRight(self):
        up = render.getRelativeVector(base.cam, Vec3(0, 0, 1))
        up.normalize()
        
        curHeroQuat = self.hero.getQuat()
        newHeroQuat = Quat()
        newHeroQuat.setFromAxisAngle(-MAIN_CHAR_ROTATE_SPEED, up)
        self.hero.setQuat(curHeroQuat*newHeroQuat)
        self.hero.setR(0)
        self.hero.setP(0)
        self.updateCameraCollision()
    
    def disableMovement(self, gameObj):
        if gameObj.getName() == self.hero.getName():
            self.ignore('w')
            self.ignore('w-up')
            self.ignore('a')
            self.ignore('a-up')
            self.ignore('s')
            self.ignore('s-up')
            self.ignore('d')
            self.ignore('d-up')
        else:
            if gameObj.getAIBehaviorsHandle().behaviorStatus('pursue') != -1:
                gameObj.getAIBehaviorsHandle().pauseAi('pursue')
    
    def enableMovement(self, gameObj):
        if gameObj.getName() == self.hero.getName():
            self.accept('w', self.setKeyStatus, extraArgs=['w', True])
            self.accept('w-up', self.setKeyStatus, extraArgs=['w', False])
            self.accept('a', self.setKeyStatus, extraArgs=['a', True])
            self.accept('a-up', self.setKeyStatus, extraArgs=['a', False])
            self.accept('s', self.setKeyStatus, extraArgs=['s', True])
            self.accept('s-up', self.setKeyStatus, extraArgs=['s', False])
            self.accept('d', self.setKeyStatus, extraArgs=['d', True])
            self.accept('d-up', self.setKeyStatus, extraArgs=['d', False])
        else:
            if gameObj.getAIBehaviorsHandle().behaviorStatus('pursue') == 'paused': 
                gameObj.getAIBehaviorsHandle().resumeAi('pursue')
    
    def setKeyStatus(self, key, isDown):
        self.keyMap[key] = isDown
        print self.hero.getName()
       
        ######################################################################
        ##  # ZJC - 07/29/2011: THIS CODE WAS COMMENTED OUT BECAUSE A MORE EFFICIENT WAY WAS FOUND
        ##
        ## prefixList = []
        ## #NEXT LINE- ZJC - 07/29/2011: This line is used to mark where to import the array used to deal with import flags.
        ## #LoaderFlagImportArray

        ## name = self.hero.getName().split('_')[0]   # ZJC - 07/29/2011: name is assumed to be formatted NAME_otherstuff
        ## name2 = self.hero.getName().split('_')[1]  # ZJC - 07/29/2011: name2 is assumed to be PREFIX_NAME_otherstuff
        ## if name in prefixList:  # ZJC - 07/29/2011: Checks if the name is in the array, if it is name is not formatted as assumed
            ## name = name2        # ZJC - 07/29/2011: Use the second format if the first name is in the list
        ## print name
        ######################################################################
        
        name = self.hero.getName().split('_')[0]        # ZJC - 07/29/2011: Assumes format is Name_mod:#
        ## print name
        for i in range(len(self.here.getName().split('_'))): # ZJC - 07/29/2011: Loop will check every possibility in the name string for any level of merges/imports
            name2 = self.hero.getName().split('_')[i]   # ZJC - 07/29/2011: name2 holds the current piece of the name string 
            if ("mod:" in name2) and (name != name2):                          # ZJC - 07/29/2011: This means the name format is Prefix(es)_Name_mod:#
                name = self.hero.getName().split('_')[i-1] # ZJC - 07/29/2011:  Assigns correct model name, the one just before mod:#
            

        if isDown:
            if key == 'w':
                if self.hero.getActorHandle() != None:
                    self.hero.getActorHandle().stop(name + '_ani_idle')                 # ZJC - 07/26/2011: Stop the 'name' specific idle animation
                    self.hero.getActorHandle().setPlayRate(1.0, name + '_ani_run')      # ZJC - 07/26/2011: Set play rate for the 'name' specific run animation
                    self.hero.getActorHandle().loop(name + '_ani_run')                  # ZJC - 07/26/2011: Run the 'name' specific run animation
                self.keyMap['s'] = False
            elif key == 's':
                if self.hero.getActorHandle() != None:
                    self.hero.getActorHandle().stop(name + '_ani_idle')                 # ZJC - 07/26/2011: Stop the 'name' specific idle animation
                    self.hero.getActorHandle().setPlayRate(-0.7, name + '_ani_run')     # ZJC - 07/26/2011: Set play rate for the 'name' specific run animation
                    self.hero.getActorHandle().loop(name + '_ani_run')                  # ZJC - 07/26/2011: Run the 'name' specific run animation
                self.keyMap['w'] = False
            elif key == 'a':
                self.keyMap['d'] = False
            elif key == 'd':
                self.keyMap['a'] = False
        elif not isDown:
            if key == 'w':
                if not self.keyMap['s']:
                    if self.hero.getActorHandle() != None:
                        self.hero.getActorHandle().stop(name + '_ani_run')              # ZJC - 07/26/2011: Stop the 'name' specific run animation
                        self.hero.getActorHandle().loop(name + '_ani_idle')             # ZJC - 07/26/2011: Run the 'name' specific idle animation
            elif key == 's':
                if not self.keyMap['w']:
                    if self.hero.getActorHandle() != None:
                        self.hero.getActorHandle().stop(name + '_ani_run')              # ZJC - 07/26/2011: Stop the 'name' specific run animation
                        self.hero.getActorHandle().loop(name + '_ani_idle')             # ZJC - 07/26/2011: Run the 'name' specific idle animation
            elif key == 'a':
                pass
            elif key == 'd':
                pass
    
    
            ## ZJC - 07/26/2011: This was the previous version of the code, it has been commented out and left as
            ##                  a reference. The changes made are defined in the comments above.     
            ## if isDown:
            ## if key == 'w':
                ## if self.hero.getActorHandle() != None:
                    ## self.hero.getActorHandle().stop('anim_idleFemale') # TODO: make a constant / set in LE
                    ## self.hero.getActorHandle().setPlayRate(1.0, 'anim_jogFemale')
                    ## self.hero.getActorHandle().loop('anim_jogFemale')  
                ## self.keyMap['s'] = False
            ## elif key == 's':
                ## if self.hero.getActorHandle() != None:
                    ## self.hero.getActorHandle().stop('anim_idleFemale') # TODO: make a constant / set in LE
                    ## self.hero.getActorHandle().setPlayRate(-0.7, 'anim_jogFemale')
                    ## self.hero.getActorHandle().loop('anim_jogFemale')
                ## self.keyMap['w'] = False
            ## elif key == 'a':
                ## self.keyMap['d'] = False
            ## elif key == 'd':
                ## self.keyMap['a'] = False
        ## elif not isDown:
            ## if key == 'w':
                ## if not self.keyMap['s']:
                    ## if self.hero.getActorHandle() != None:
                        ## self.hero.getActorHandle().stop('anim_jogFemale')
                        ## self.hero.getActorHandle().loop('anim_idleFemale')
            ## elif key == 's':
                ## if not self.keyMap['w']:
                    ## if self.hero.getActorHandle() != None:
                        ## self.hero.getActorHandle().stop('anim_jogFemale')
                        ## self.hero.getActorHandle().loop('anim_idleFemale')
            ## elif key == 'a':
                ## pass
            ## elif key == 'd':
                ## pass
    
    
    
    def moveHeroTask(self, task):
        dt = globalClock.getDt()

        direction = int(self.keyMap['w'])-int(self.keyMap['s'])
        self.moveHero(direction, dt)      
        if self.keyMap['a']:
            self.turnHeroLeft()
        elif self.keyMap['d']:
            self.turnHeroRight()
        
        return task.cont
            
    
##== Scene Handling =========================================================##

    def loadScenes(self):
        # NOTE: Do not remove!  This function is populated by StandaloneExporter
        pass
    
    def addSequence(self, sequence):
        self.ranSequences.append(sequence)
        
    #this is for changing scenes
    def resetAllSequences(self):
        for seq in self.ranSequences:
            seq.finish()
        
        dr = self.cam.node().getDisplayRegion(0)
        dr.setCamera(self.gameCam)
        
        self.ranSequences = []
    
    def openScene(self, sceneName):
        if (self.scenes.has_key(sceneName)==False):
            print "ERROR:There is no scene under the name ", sceneName,"."
            return
        
        self.startLoadBar(12)
        self.createLoadScreen()
        
        #Part2:Clear all of the collision lists
        self.cTrav.removeCollider(self.heroCNP)
        self.heroGroundHandler.clearEntries()
        self.heroCollisionQueue.clearEntries()
        
        

        self.resetAllSequences()
        self.increaseLoadBar(1)
        
        #Part3: stop all of the tasks
        
        taskMgr.remove('processHeroCollisions')
        taskMgr.remove('updateHeroHeight')
        taskMgr.remove('moveHeroTask')
        taskMgr.remove('cameraFollowTask')
        taskMgr.remove("updateShaders") # ?
        self.combatMgr.stopTasks()
        
        self.gameplayUI.stop()
        self.gameplayUI.removeAllHealthBars()
        
        self.increaseLoadBar(1)
        
        #Part1.1: Stop currently running parts like conversations or camera
        if(self.conversationMgr.isConversationOpen()):
            self.conversationMgr.closeConversation()
        
        #Part 1.2: stop the camera

        
        self.increaseLoadBar(1)
        
        #Part4: Turn-Off all of the player controls
        self.ignore("mouse1")
        
        self.increaseLoadBar(1)
        
        #Part5: Remove all of the game elements that are related with the current scene  
        del self.combatMgr
        
        self.increaseLoadBar(1)
        
        #Part6: Remove all of the children and the lights from the render
        render.getChildren().detach()
        render.clearLight()
        
        self.increaseLoadBar(1)
        
        #Part7:Add the camera and hero or any game element that should be exist in any scene back 
        self.camPivot.reparentTo(render)
        self.hero.reparentTo(render)
        #self.heroWallCollide.reparentTo(render)
        self.heroWallCollideX.reparentTo(render)
        self.heroWallCollideY.reparentTo(render)
        self.heroWallCollideZ.reparentTo(render)
        self.heroGroundCollide.reparentTo(render)
        self.cameraHeroP.reparentTo(render)
        
        self.overlayAmbientLightNP.reparentTo(render)
        
        self.increaseLoadBar(1)
        
        #Part8:Add the new objects from the new scene        
        self.assets, self.objects, self.gameObjects, self.sounds, self.sequences = loadWorld(self.scenes[sceneName], LIBRARY_INDEX)
        
        self.increaseLoadBar(1)
        
        #Part9:Add the hero to the new gameObject list and remove the duplicates of the hero
        self.gameObjects[self.hero.getName()] = self.hero      
        if(self.objects.has_key(self.hero.getName())):
           object = self.objects[self.hero.getName()]
           if(object.hasTag('LE-mainChar')):
               object.detachNode()
               del self.objects[self.hero.getName()]
               
        for name, gameObj in self.gameObjects.iteritems():
            if gameObj.getNP().hasTag('LE-ground'):
                #debug("is Ground")
                bitmask = gameObj.getNP().getCollideMask()
                bitmask |= BITMASK_GROUND
                gameObj.getNP().setCollideMask(bitmask)
        self.increaseLoadBar(1)
        
        #Part10:Restart the tasks.                    
        self.combatMgr = CombatMgr(self)
        
        taskMgr.add(self.processHeroCollisions, 'processHeroCollisions')
        taskMgr.add(self.updateHeroHeight, 'updateHeroHeight')
        taskMgr.add(self.moveHeroTask, 'moveHeroTask')
        taskMgr.add(self.cameraFollowTask, 'cameraFollowTask')
        self.combatMgr.startTasks()
        self.gameplayUI.start()
        
        self.increaseLoadBar(1)
        
        
        self.setCollideMasks(self.gameObjects)
        
        self.increaseLoadBar(1)
        
        #Part11: Change the color of the sky
        if(sceneName.startswith("interior") or sceneName.startswith("Interior")):
            self.setBackgroundColor(BGC_DARK_GREY)
        else:
            self.skybox.reparentTo(render)
            self.setBackgroundColor(BGC_LIGHT_BLUE)
            
        self.increaseLoadBar(1)    
        
        #Part12: Restart the player controls    
        self.accept("mouse1", self.onClickin3D)
        
        self.increaseLoadBar(1)
        self.accept("enter",self.destroyLoadScreen)
        
        debug("After open Scene: "+str(self.heroCollisionQueue.getNumEntries()))
        self.heroCollisionQueue.clearEntries()
        self.cTrav.addCollider(self.heroCNP, self.heroCollisionQueue)
        
        self.destroyLoadScreen()
class World(ShowBase):  # CONDISER: change to DirectObject/FSM
    def __init__(self):
        ShowBase.__init__(self)

        self.createLoadScreen('./LEGameAssets/Textures/title_screen.png')
        base.graphicsEngine.renderFrame()

        #== Environment and Rendering Settings ==
        base.setFrameRateMeter(FLAG_SHOW_FRAMES_PER_SECOND)
        if FLAG_USE_AUTOSHADER:
            render.setShaderAuto()
        self.filters = CommonFilters(base.win, self.cam)  # NEW
        if FLAG_SHOW_GLOW:
            bloomSize = 4  #'small'
            filterok = self.filters.setBloom(blend=(0, 0, 0, 1),
                                             desat=-0.5,
                                             intensity=3.0,
                                             size=bloomSize)
            if (filterok == False):
                print 'WARNING:Video card not powerful enough to do image postprocessing'

        #tex = loader.loadTexture("./LEGameAssets/Textures/loadbar_tray.png")
        self.loadBar = DirectWaitBar(text="",
                                     value=0,
                                     scale=(.35, .5, .5),
                                     pos=(0.006, .83, .83))
        #self.loadBar['barRelief'] = DirectWaitBar.GROOVE
        #self.loadBar['scale'] = 0.05
        #self.loadBar['barTexture'] = tex
        self.loadBar['barColor'] = (6.0 / 255.0, 11.0 / 255, 28.0 / 255.0, 1)
        self.loadBar.reparentTo(render2d)
        self.loadBar.hide()
        base.graphicsEngine.renderFrame()

        self.setBackgroundColor(166.0 / 255.0, 207.0 / 255.0, 240.0 / 255.0, 1)
        self.skybox = self.loader.loadModel(
            "LEGameAssets/Models/skybox_final.egg")
        self.skybox.setScale(50)
        self.skybox.reparentTo(render)

        #== Load the level and the managers ==
        self.assets, self.objects, self.gameObjects, self.sounds, self.sequences = loadWorld(
            SCENE_FILE, LIBRARY_INDEX)
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()

        self.conversations = loadConversations(SCENE_FILE, LIBRARY_INDEX)
        self.scenes = {}
        self.loadScenes()
        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()

        self.journalMgr = JournalMgr(self)
        self.loadJournal(self.journalMgr, JOURNAL_FILE)

        self.conversationMgr = ConversationMgr(self, self.conversations)

        self.scriptMgr = ScriptMgr(self)
        self.scriptMgr.loadScripts(SCRIPTS_LIST)
        self.scriptInterface = ScriptInterface(self)

        self.inventoryMgr = InventoryMgr(self)
        loadInventory(self.inventoryMgr, INVENTORY_FILE)

        self.loadBar['value'] += 5
        base.graphicsEngine.renderFrame()

        self.ranSequences = []

        #== Main Character ==
        self.hero = None
        for name, gameObj in self.gameObjects.iteritems():
            if gameObj.getNP().hasTag('LE-mainChar'):
                self.hero = gameObj
                break
        else:
            # make a default hero
            defaultHeroNP = loader.loadModel("panda")
            self.hero = GameObject(defaultHeroNP)
            self.hero.reparentTo(render)
            self.hero.setPos(0, 0, 0)
            self.hero.setTag('LE-mainChar', '180')
            self.gameObjects[self.hero.getName()] = self.hero

        self.setCollideMasks(self.gameObjects)

        # remove the hero from the objects dict so it cannot be clicked by player
        if self.hero.getName() in self.objects:
            del self.objects[self.hero.getName()]

    #== Camera ==
        camHeightFactor = CAMERA_HEIGHT
        camTrailFactor = -CAMERA_TRAIL  # careful of +/- distinction
        self.heroHeight = self.getModelHeight(self.hero)
        self.heroHeadingOffset = float(self.hero.getTag('LE-mainChar'))
        self.lastHeroH = self.hero.getH(render) + self.heroHeadingOffset

        # setup the camera pivot, which will follow the main character model and anchor the camera
        self.camPivot = NodePath('camPivot')
        self.camPivot.reparentTo(render)

        self.camHeight = camHeightFactor * self.heroHeight
        self.camTrail = camTrailFactor * self.heroHeight
        self.cam.setPos(self.camPivot.getPos() +
                        (0, self.camTrail, self.camHeight))
        self.cam.wrtReparentTo(self.camPivot)

        self.placeCamera(self.hero)  # match X and Y to main character
        self.alignCamera(self.hero)  # match heading to main character
        #self.camPivot.setH(render, self.hero.getH(render) + self.heroHeadingOffset)

        self.gameCam = self.cam

        #== Collisions ==
        self.setupCollisions()

        #== Controls ==
        self.disableMouse()
        self.keyMap = {'w': False, 'a': False, 's': False, 'd': False}
        self.enableMovement(self.hero)
        self.accept("mouse1", self.onClickin3D)
        self.accept('escape', sys.exit)

        self.accept('z', render.place)

        #== UI and Combat ==
        self.gameplayUI = GameplayUI(self)
        self.gameplayUI.hideAll()

        # for health bars and on screen UI
        self.overlayAmbientLight = AmbientLight('overlayAmbientLight')
        self.overlayAmbientLight.setColor(VBase4(1.0, 1.0, 1.0, 1.0))
        self.overlayAmbientLightNP = render.attachNewNode(
            self.overlayAmbientLight)

        # initialize the combat manager (which includes AI) now that a main character and gameplayUI instance and overlay light is established
        self.combatMgr = CombatMgr(self)

        # initialize player's spells
        self.heroSpells = []
        for properties in PLAYER_SPELLS:
            spell = Spell(self.hero, properties)
            self.heroSpells.append(spell)

    #== Start Tasks
        taskMgr.add(self.moveHeroTask, 'moveHeroTask', appendTask=True)
        taskMgr.add(self.cameraFollowTask, 'cameraFollowTask', appendTask=True)
        taskMgr.add(self.processHeroCollisions, 'processHeroCollisions')
        taskMgr.add(self.updateHeroHeight, 'updateHeroHeight')
        self.combatMgr.startTasks()

        self.accept('enter', self.destroyLoadScreen)
        self.destroyLoadScreen()

##== Utility and World Initialization functions =============================##

    def loadJournal(self, journalMgr, journalFile):
        f = open(Filename(journalFile).toOsSpecific())
        doc = xml.dom.minidom.parse(f)
        root = doc.childNodes[0]

        for n in root.childNodes:
            if n.localName == "journalEntries":
                journalMgr.decode(n)
        f.close()

    def getModelHeight(self, model):
        min, max = Point3(), Point3()
        model.calcTightBounds(min, max)
        return max.getZ() - min.getZ()

    def createLoadScreen(self,
                         imageFile='./LEGameAssets/Textures/load_screen.png'):
        self.loadScreen = OnscreenImage(image=imageFile)
        aspect2d.hide()
        self.loadScreen.reparentTo(render2d)
        if (hasattr(self, "gameplayUI")):
            self.gameplayUI.hideAll()

    def destroyLoadScreen(self):
        self.loadBar.hide()
        self.loadScreen.detachNode()
        self.loadScreen.destroy()
        aspect2d.show()
        self.ignore('enter')
        self.gameplayUI.showAll()
        for name, gameObj in self.gameObjects.iteritems():
            gameObj.callTrigger(self, 'LE-trigger-onScene')

    def startLoadBar(self, range=100):
        self.loadBar.show()
        self.loadBar['range'] = range
        self.loadBar['value'] = 0
        base.graphicsEngine.renderFrame()

    def increaseLoadBar(self, value):
        self.loadBar['value'] += value
        base.graphicsEngine.renderFrame()

##== Collisions =============================================================##

    def setupCollisions(self):
        self.cTrav = CollisionTraverser('mainTraverser')
        self.cTrav.setRespectPrevTransform(True)

        # Line collider for setting hero height based on ground geometry
        heroLine = CollisionNode('heroLine')
        heroLine.addSolid(
            CollisionRay(Point3(0, 0, self.heroHeight), Vec3(0, 0, -1)))
        heroLine.setFromCollideMask(BITMASK_GROUND)
        heroLine.setIntoCollideMask(BitMask32.allOff())
        self.heroGroundCollide = render.attachNewNode(heroLine)
        self.heroGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroGroundCollide, self.heroGroundHandler)

        #        cameraSphere = CollisionNode('cameraSphere')
        #        cameraSphere.addSolid(CollisionSphere(0,0,0,10))
        #        cameraSphere.setFromCollideMask(BITMASK_CAMERA)
        #        cameraSphere.setIntoCollideMask(BitMask32.allOff())
        #        self.cameraSphereCollide = self.cam.attachNewNode(cameraSphere)
        #        self.cameraSphereQueue = CollisionHandlerQueue()
        #        self.cTrav.addCollider(self.cameraSphereCollide, self.cameraSphereQueue)

        self.herowallcollision = False

        self.heroWallCollideX = render.attachNewNode("heroWallX")
        self.heroWallCollideY = render.attachNewNode("heroWallY")
        self.heroWallCollideZ = render.attachNewNode("heroWallZ")

        # Line collider for running into obstacles and walls in X direction
        heroLineX = CollisionNode('heroLineX')
        heroLineX.addSolid(CollisionRay(Point3(0, 0, 0), Vec3(0, 0, 1)))
        self.heroWallCollideLineX = self.heroWallCollideX.attachNewNode(
            heroLineX)
        self.heroWallCollideLineX.node().setFromCollideMask(
            BITMASK_WALL_TERRAIN)
        self.heroWallCollideLineX.node().setIntoCollideMask(BitMask32.allOff())
        self.heroWallQueueX = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideLineX, self.heroWallQueueX)

        # Line collider for running into obstacles and walls in Y direction
        heroLineY = CollisionNode('heroLineY')
        heroLineY.addSolid(CollisionRay(Point3(0, 0, 0), Vec3(0, 0, 1)))
        self.heroWallCollideLineY = self.heroWallCollideY.attachNewNode(
            heroLineY)
        self.heroWallCollideLineY.node().setFromCollideMask(
            BITMASK_WALL_TERRAIN)
        self.heroWallCollideLineY.node().setIntoCollideMask(BitMask32.allOff())
        self.heroWallQueueY = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideLineY, self.heroWallQueueY)

        # Line collider for running into obstacles and walls in Z direction
        heroLineZ = CollisionNode('heroLineZ')
        heroLineZ.addSolid(CollisionRay(Point3(0, 0, 0), Vec3(0, 0, 1)))
        self.heroWallCollideLineZ = self.heroWallCollideZ.attachNewNode(
            heroLineZ)
        self.heroWallCollideLineZ.node().setFromCollideMask(
            BITMASK_WALL_TERRAIN)
        self.heroWallCollideLineZ.node().setIntoCollideMask(BitMask32.allOff())
        self.heroWallQueueZ = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideLineZ, self.heroWallQueueZ)

        #        # Sphere collider for running into obstacles and walls
        #        heroSphere = CollisionNode('heroSphere')
        #        heroSphere.addSolid(CollisionSphere(0,0,0,7))
        #        self.heroWallCollide = render.attachNewNode(heroSphere)
        #        self.heroWallCollide.node().setFromCollideMask(BITMASK_WALL)
        #        self.heroWallCollide.node().setIntoCollideMask(BitMask32.allOff())
        #        self.heroWallQueue = CollisionHandlerQueue()
        #        self.cTrav.addCollider(self.heroWallCollide, self.heroWallQueue)
        #        self.herowallcollision = False

        # Sphere collider for running into obstacles and walls in X direction
        heroSphereX = CollisionNode('heroSphereX')
        heroSphereX.addSolid(CollisionSphere(0, 0, 0, 7))
        self.heroWallCollideSphereX = self.heroWallCollideX.attachNewNode(
            heroSphereX)
        self.heroWallCollideSphereX.node().setFromCollideMask(BITMASK_WALL)
        self.heroWallCollideSphereX.node().setIntoCollideMask(
            BitMask32.allOff())
        #self.heroWallQueueX = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideSphereX,
                               self.heroWallQueueX)
        self.herowallcollision = False

        # Sphere collider for running into obstacles and walls in Y direction
        heroSphereY = CollisionNode('heroSphereY')
        heroSphereY.addSolid(CollisionSphere(0, 0, 0, 7))
        self.heroWallCollideSphereY = self.heroWallCollideY.attachNewNode(
            heroSphereY)
        self.heroWallCollideSphereY.node().setFromCollideMask(BITMASK_WALL)
        self.heroWallCollideSphereY.node().setIntoCollideMask(
            BitMask32.allOff())
        #self.heroWallQueueY = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideSphereY,
                               self.heroWallQueueY)

        # Sphere collider for running into obstacles and walls in Z direction
        heroSphereZ = CollisionNode('heroSphereZ')
        heroSphereZ.addSolid(CollisionSphere(0, 0, 0, 7))
        self.heroWallCollideSphereZ = self.heroWallCollideZ.attachNewNode(
            heroSphereZ)
        self.heroWallCollideSphereZ.node().setFromCollideMask(BITMASK_WALL)
        self.heroWallCollideSphereZ.node().setIntoCollideMask(
            BitMask32.allOff())
        #self.heroWallQueueZ = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroWallCollideSphereZ,
                               self.heroWallQueueZ)

        # Ray collider for clicking on objects in the game
        self.pickerCollisionQueue = CollisionHandlerQueue()
        self.pickerCN = CollisionNode('pickerRayCN')
        self.pickerCNP = self.cam.attachNewNode(self.pickerCN)
        self.pickerCN.setFromCollideMask(BITMASK_CLICK)
        self.pickerCN.setIntoCollideMask(BitMask32.allOff())
        self.pickerRay = CollisionRay()
        self.pickerCN.addSolid(self.pickerRay)
        self.cTrav.addCollider(self.pickerCNP, self.pickerCollisionQueue)

        # Sphere collider for triggering scripts
        self.heroCN = CollisionNode('heroCN')
        self.heroCN.addSolid(CollisionSphere(0, 0, 0,
                                             5))  # TODO: find good radius
        self.heroCNP = self.hero.attachNewNode(self.heroCN)
        self.heroCN.setFromCollideMask(BITMASK_HERO_COLLIDE)
        self.heroCN.setIntoCollideMask(BitMask32.allOff())
        self.heroCollisionQueue = CollisionHandlerQueue()
        self.cTrav.addCollider(self.heroCNP, self.heroCollisionQueue)

        # Line collider for transparency
        self.cameraEntriesPre = []
        radius = self.getModelHeight(self.hero) * CAMERA_TRAIL / 2
        self.cameraCollisionQueue = CollisionHandlerQueue()
        self.cameraHero = CollisionNode('cameraHero')
        self.cameraHeroLine = CollisionSegment(self.hero.getPos(render),
                                               self.cam.getPos(render))
        self.cameraHero.addSolid(self.cameraHeroLine)
        self.cameraHero.setFromCollideMask(BITMASK_CAMERA)
        self.cameraHero.setIntoCollideMask(BitMask32.allOff())
        self.cameraHeroP = self.render.attachNewNode(self.cameraHero)
        self.cTrav.addCollider(self.cameraHeroP, self.cameraCollisionQueue)
        #self.cameraHeroP.show()

        if FLAG_SHOW_COLLISIONS:
            self.cTrav.showCollisions(render)
            # TODO: show specific collision nodepaths

    def setCollideMasks(self, gameObjDict):
        for name, obj in gameObjDict.iteritems():
            bitmask = obj.getCollideMask()
            if obj.hasTag('LE-ground'):
                bitmask |= BITMASK_GROUND
                #obj.getNP().setCollideMask(bitmask) # TODO: remove
            if obj.hasTag('LE-attackable'):
                bitmask |= BITMASK_CLICK
            if obj.hasTag('LE-wall'):
                if (isinstance(obj.getNP(), GeoMipTerrain)):
                    bitmask |= BITMASK_TERRAIN
                else:
                    bitmask |= BITMASK_WALL
            if obj.scripts.has_key('LE-trigger-onClick'):
                bitmask |= BITMASK_CLICK
            if obj.scripts.has_key('LE-trigger-onCollision'):
                bitmask |= BITMASK_HERO_COLLIDE
            if obj.hasTag('OBJRoot'):
                if obj.hasTag('LE-ground') or obj.hasTag('LE-mainChar'):
                    pass
                else:
                    bitmask |= BITMASK_CAMERA

            obj.setCollideMask(bitmask)

    def onClickin3D(self):
        pickedObj = None
        if self.conversationMgr.isConversationOpen():
            return
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
        else:
            return

        self.cTrav.addCollider(self.pickerCNP, self.pickerCollisionQueue)

        self.pickerRay.setFromLens(self.cam.node(), mpos.getX(), mpos.getY())

        self.cTrav.traverse(render)
        if (self.pickerCollisionQueue.getNumEntries() > 0):
            self.pickerCollisionQueue.sortEntries()
        for i in range(self.pickerCollisionQueue.getNumEntries()):
            parent = self.pickerCollisionQueue.getEntry(
                i).getIntoNodePath().getParent()
            while not self.objects.has_key(parent.getName()):
                if (parent.getName() == "render"):
                    return
                parent = parent.getParent()
            pickedObj = parent

            if (pickedObj == None):
                continue
            else:
                break

            #if pickedObj.hasTag("LE-trigger-onClick"): # TODO: needed, or is having key in self.objects enough?
        if (pickedObj == None):
            return

        self.pickerCollisionQueue.clearEntries()

        self.cTrav.removeCollider(self.pickerCNP)

        gameObj = self.gameObjects[pickedObj.getName()]
        distToTarget = self.hero.getDistance(gameObj)

        if self.combatMgr.checkCanAttack(self.hero, gameObj):
            if distToTarget <= self.heroSpells[
                    self.curSpellIndex].getAttackRange():
                self.combatMgr.queueAttack(self.hero,
                                           self.heroSpells[self.curSpellIndex],
                                           gameObj)
            else:
                textObject = OnscreenText(text='The target is out of range!',
                                          fg=(1, 0, 0, 1),
                                          pos=(0, 0),
                                          scale=0.09,
                                          align=TextNode.ACenter)

                def destroyWarning1():
                    textObject.destroy()

                sequence = Sequence(Wait(2), Func(destroyWarning1))
                sequence.start()
                return
        elif (distToTarget > CLICK_RANGE):
            textObject = OnscreenText(text='The target is out of range!',
                                      fg=(1, 0, 0, 1),
                                      pos=(0, 0),
                                      scale=0.09,
                                      align=TextNode.ACenter)

            def destroyWarning2():
                textObject.destroy()

            sequence = Sequence(Wait(2), Func(destroyWarning2))
            sequence.start()
            return
        gameObj.callTrigger(self, 'LE-trigger-onClick')

    # Task for processing hero's collisions with GameObjects, triggering OnCollision scripts
    def processHeroCollisions(self, task):
        #self.cTrav.traverse(render)
        debug("processHeroCollisions")
        # CONSIDER: may not be necessary to sort
        if (self.heroCollisionQueue.getNumEntries() > 0):
            self.heroCollisionQueue.sortEntries()
        debug("queue size: " + str(self.heroCollisionQueue.getNumEntries()))
        for i in range(self.heroCollisionQueue.getNumEntries()):
            # CONSIDER: if entry.hasInto(): for efficiency

            debug("i: " + str(i))
            # TODO: check if GameObject is passable, and react accordingly (store old position, revert to it)
            if (self.heroCollisionQueue.getNumEntries() <= 0):
                return
            entry = self.heroCollisionQueue.getEntry(i)
            debug("entry: " + str(entry))
            if (entry):
                intoNP = entry.getIntoNodePath()
            else:
                continue
            if (intoNP != None) or (not intoNP.isEmpty()):
                while not self.objects.has_key(intoNP.getName()):
                    if (intoNP.getName() == "render"):
                        return task.cont
                    intoNP = intoNP.getParent()
                pickedObj = intoNP

                if pickedObj == None:
                    continue
                gameObj = self.gameObjects[pickedObj.getName()]
                gameObj.callTrigger(self, 'LE-trigger-onCollision')

        return task.cont

##== Camera Movement ========================================================##

# places the camera pivot to match the position of the node path parameter
# used to have the camera pivot match the main character's position as he moves

    def placeCamera(self, np):
        self.camPivot.setX(render, np.getX(render))
        self.camPivot.setY(render, np.getY(render))

    def alignCamera(self, np):
        self.camPivot.setH(render,
                           self.hero.getH(render) + self.heroHeadingOffset)
        self.cam.setP(CAMERA_PITCH)

    def cameraFollowTask(self, task):
        heroH = self.hero.getH(render) + self.heroHeadingOffset
        camPivotH = self.camPivot.getH(render)

        # normalizes the headings to avoid jumps in the difference
        # which could come from passing 360 and going back to 0, for example
        # TODO: stress test, esp. with different values of self.heroHeadingOffset
        while heroH + 180 < camPivotH:
            heroH += 360
        while camPivotH + 180 < heroH:
            camPivotH += 360

        self.lastHeroH = heroH
        rotateLeft = (heroH >= camPivotH)
        rotateRight = not rotateLeft
        diff = math.fabs(heroH - camPivotH)

        if diff > CAMERA_TURN_THRESHOLD:
            if rotateLeft:
                self.camPivot.setH(self.camPivot.getH() + CAMERA_TURN_SPEED)
            elif rotateRight:
                self.camPivot.setH(self.camPivot.getH() - CAMERA_TURN_SPEED)

#        if(len(self.cameraEntriesPre)>0):
#            #print self.cameraEntriesPre
#            if(self.hero.getDistance(self.cam) > 5):
#                moveAmount = min(globalClock.getDt()*200,5.0)
#                pos = self.cam.getQuat().getForward()*moveAmount
#                newpos = self.cam.getPos() + pos
#                self.oldCameraEntriesPre = []
#                for e in self.cameraEntriesPre:
#                    self.oldCameraEntriesPre.append(e)
#                self.cam.setFluidPos(newpos)
#
#        else:
#            if(self.hero.getDistance(self.cam) < 100):
#                moveAmount = min(globalClock.getDt()*200,5.0)
#                pos = self.cam.getQuat().getForward()*(-moveAmount)
#                oldpos = self.cam.getPos()
#                newpos = self.cam.getPos() + pos
#                self.cam.setFluidPos(newpos)
#                for e in self.oldCameraEntriesPre:
#                    #print e.getIntoNodePath()
#                    self.cTrav.traverse(e.getIntoNodePath())
#                #self.cTrav.traverse(render)
#                    if(len(self.cameraSphereQueue.getEntries())>0):
#                        self.cam.setFluidPos(oldpos)

        return task.cont

    def runCamera(self, cameraName, sequence, isLoop=False):
        debug("Running the camera")
        #debug(str(self.sequences))

        self.oldCamera = self.cam
        self.dr = self.win.makeDisplayRegion()

        dr2 = self.cam.node().getDisplayRegion(0)  #
        self.objects[cameraName].node().setLens(base.camLens)
        parent = self.cam.getParent()
        self.cam.detachNode()

        self.dr.setCamera(self.objects[cameraName])

        def temp():

            dr2.setCamera(self.oldCamera)
            self.oldCamera.reparentTo(parent)
            self.dr.setActive(False)
            del self.dr
            self.dr = None
            self.accept("mouse1", self.onClickin3D)
            debug("Ran")

        if (isLoop):
            newSequence = Sequence(sequence)
            self.addSequence(newSequence)

            def stopCameraFromLoop():
                newSequence.finish()
                temp()

            self.accept("mouse1", stopCameraFromLoop)
            self.addSequence(newSequence)
            newSequence.loop()
        else:
            newSequence = Sequence(sequence, Func(temp))

            def stopCamera():
                newSequence.finish()

            self.accept("mouse1", stopCamera)
            self.addSequence(newSequence)
            newSequence.start()

##== Character Movement =====================================================##

    def moveHeroTo(self, destinationObj):
        pos = destinationObj.getPos(render)
        hpr = destinationObj.getHpr(render)
        self.hero.setPosHpr(render, pos, hpr)
        self.placeCamera(self.hero)
        self.alignCamera(self.hero)

    def updateHeroHeight(self, task=None):
        groundEntries = []
        #move the collision line to the hero position
        self.heroGroundCollide.setPos(self.hero.getPos(render))

        #loop through every collision entry for the line
        for e in self.heroGroundHandler.getEntries():
            if e.getIntoNodePath().hasNetTag('OBJRoot'):
                #find the actual root of the object
                np = e.getIntoNodePath().findNetTag('OBJRoot')
                #only react to objects that are tagged as the ground
                if np.hasTag('LE-ground'):
                    groundEntries.append(e)

        if groundEntries:
            #sort the collision entries based on height
            groundEntries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),\
x.getSurfacePoint(render).getZ()))

            #set hero height and pivot height
            self.hero.setZ(groundEntries[0].getSurfacePoint(render).getZ() +
                           MAIN_CHAR_GROUND_OFFSET)
            self.camPivot.setZ(
                groundEntries[0].getSurfacePoint(render).getZ() +
                MAIN_CHAR_GROUND_OFFSET)
            # TODO: unlink these from being in the same task in case we want pivot to not be linked to hero (ex. cutscene)

        self.heroGroundHandler.clearEntries()
        return task.cont

    def updateHeroPos(self, queue, stepSize):
        wallEntries = []
        for w in queue.getEntries():
            np = w.getIntoNodePath().findNetTag('OBJRoot')
            if np.hasTag('LE-wall'):
                if self.isInObstacleRange(self.hero, w, stepSize):
                    wallEntries.append(w)
        if len(wallEntries) > 0:
            self.herowallcollision = True
            #self.collisionsurfaceP = wallEntries[0].getSurfacePoint(render)
        else:
            self.herowallcollision = False

    def updateCameraCollision(self):
        self.cameraHeroLine.setPointA(self.cam.getPos(render))
        self.cameraHeroLine.setPointB(self.hero.getPos(render))

        if (self.cameraEntriesPre):
            for i in self.cameraEntriesPre:
                i.getIntoNodePath().setTransparency(TransparencyAttrib.MAlpha)
                i.getIntoNodePath().setAlphaScale(1.0)
            del self.cameraEntriesPre[:]

        for i in self.cameraCollisionQueue.getEntries():
            i.getIntoNodePath().setAlphaScale(0.5)
            self.cameraEntriesPre.append(i)

    def moveHero(self, direction, dt):
        temp = render.attachNewNode("Dummy")  #NodePath()
        moveStep = MAIN_CHAR_MOVE_SPEED * dt
        if moveStep > MAIN_CHAR_MAX_STEP:
            moveStep = MAIN_CHAR_MAX_STEP
        temp.setPos(self.camPivot, 0, direction * moveStep, 0)

        #oldPos = self.heroWallCollideX.getPos()
        self.heroWallCollideX.setX(temp.getX())
        self.heroWallCollideY.setY(temp.getY())
        self.heroWallCollideZ.setZ(temp.getZ())  #+10)
        self.cTrav.traverse(render)

        #check on X direction
        self.updateHeroPos(self.heroWallQueueX, moveStep)
        self.moveHeroToWallCollide(
            Point3(temp.getX(), self.hero.getY(), self.hero.getZ()))

        #check on Y direction
        self.updateHeroPos(self.heroWallQueueY, moveStep)
        self.moveHeroToWallCollide(
            Point3(self.hero.getX(), temp.getY(), self.hero.getZ()))

        #check on Z direction
        self.updateHeroPos(self.heroWallQueueZ, moveStep)
        self.moveHeroToWallCollide(
            Point3(self.hero.getX(), self.hero.getY(), temp.getZ()))

        self.heroWallCollideX.setPos(self.hero.getPos())
        self.heroWallCollideY.setPos(self.hero.getPos())
        self.heroWallCollideZ.setPos(self.hero.getPos())

        self.placeCamera(self.hero)
        self.updateCameraCollision()
        temp.detachNode()

    def moveHeroToWallCollide(self, pos):
        if self.herowallcollision == False:
            self.hero.setPos(pos)  #self.camPivot, 0, MAIN_CHAR_MOVE_SPEED, 0)

    def isInObstacleRange(self, mover, colEntry, stepSize):
        colPoint = colEntry.getSurfacePoint(render)
        if colPoint[2] >= mover.getZ(render):
            dist = findDistance3D(mover.getX(), mover.getY(), mover.getZ(),
                                  colPoint[0], colPoint[1], colPoint[2])
            obstacleThreshold = self.heroHeight * self.heroHeight + stepSize * stepSize
            if dist * dist <= obstacleThreshold:
                return True
        return False

    def turnHeroLeft(self):
        up = render.getRelativeVector(base.cam, Vec3(0, 0, 1))
        up.normalize()

        curHeroQuat = self.hero.getQuat()
        newHeroQuat = Quat()
        newHeroQuat.setFromAxisAngle(MAIN_CHAR_ROTATE_SPEED, up)
        self.hero.setQuat(curHeroQuat * newHeroQuat)
        self.hero.setR(0)
        self.hero.setP(0)
        self.updateCameraCollision()

    def turnHeroRight(self):
        up = render.getRelativeVector(base.cam, Vec3(0, 0, 1))
        up.normalize()

        curHeroQuat = self.hero.getQuat()
        newHeroQuat = Quat()
        newHeroQuat.setFromAxisAngle(-MAIN_CHAR_ROTATE_SPEED, up)
        self.hero.setQuat(curHeroQuat * newHeroQuat)
        self.hero.setR(0)
        self.hero.setP(0)
        self.updateCameraCollision()

    def disableMovement(self, gameObj):
        if gameObj.getName() == self.hero.getName():
            self.ignore('w')
            self.ignore('w-up')
            self.ignore('a')
            self.ignore('a-up')
            self.ignore('s')
            self.ignore('s-up')
            self.ignore('d')
            self.ignore('d-up')
        else:
            if gameObj.getAIBehaviorsHandle().behaviorStatus('pursue') != -1:
                gameObj.getAIBehaviorsHandle().pauseAi('pursue')

    def enableMovement(self, gameObj):
        if gameObj.getName() == self.hero.getName():
            self.accept('w', self.setKeyStatus, extraArgs=['w', True])
            self.accept('w-up', self.setKeyStatus, extraArgs=['w', False])
            self.accept('a', self.setKeyStatus, extraArgs=['a', True])
            self.accept('a-up', self.setKeyStatus, extraArgs=['a', False])
            self.accept('s', self.setKeyStatus, extraArgs=['s', True])
            self.accept('s-up', self.setKeyStatus, extraArgs=['s', False])
            self.accept('d', self.setKeyStatus, extraArgs=['d', True])
            self.accept('d-up', self.setKeyStatus, extraArgs=['d', False])
        else:
            if gameObj.getAIBehaviorsHandle().behaviorStatus(
                    'pursue') == 'paused':
                gameObj.getAIBehaviorsHandle().resumeAi('pursue')

    def setKeyStatus(self, key, isDown):
        self.keyMap[key] = isDown
        print self.hero.getName()

        ######################################################################
        ##  # ZJC - 07/29/2011: THIS CODE WAS COMMENTED OUT BECAUSE A MORE EFFICIENT WAY WAS FOUND
        ##
        ## prefixList = []
        ## #NEXT LINE- ZJC - 07/29/2011: This line is used to mark where to import the array used to deal with import flags.
        ## #LoaderFlagImportArray

        ## name = self.hero.getName().split('_')[0]   # ZJC - 07/29/2011: name is assumed to be formatted NAME_otherstuff
        ## name2 = self.hero.getName().split('_')[1]  # ZJC - 07/29/2011: name2 is assumed to be PREFIX_NAME_otherstuff
        ## if name in prefixList:  # ZJC - 07/29/2011: Checks if the name is in the array, if it is name is not formatted as assumed
        ## name = name2        # ZJC - 07/29/2011: Use the second format if the first name is in the list
        ## print name
        ######################################################################

        name = self.hero.getName().split('_')[
            0]  # ZJC - 07/29/2011: Assumes format is Name_mod:#
        ## print name
        for i in range(
                len(self.here.getName().split('_'))
        ):  # ZJC - 07/29/2011: Loop will check every possibility in the name string for any level of merges/imports
            name2 = self.hero.getName().split(
                '_'
            )[i]  # ZJC - 07/29/2011: name2 holds the current piece of the name string
            if ("mod:" in name2) and (
                    name != name2
            ):  # ZJC - 07/29/2011: This means the name format is Prefix(es)_Name_mod:#
                name = self.hero.getName().split(
                    '_'
                )[i -
                  1]  # ZJC - 07/29/2011:  Assigns correct model name, the one just before mod:#

        if isDown:
            if key == 'w':
                if self.hero.getActorHandle() != None:
                    self.hero.getActorHandle().stop(
                        name + '_ani_idle'
                    )  # ZJC - 07/26/2011: Stop the 'name' specific idle animation
                    self.hero.getActorHandle().setPlayRate(
                        1.0, name + '_ani_run'
                    )  # ZJC - 07/26/2011: Set play rate for the 'name' specific run animation
                    self.hero.getActorHandle().loop(
                        name + '_ani_run'
                    )  # ZJC - 07/26/2011: Run the 'name' specific run animation
                self.keyMap['s'] = False
            elif key == 's':
                if self.hero.getActorHandle() != None:
                    self.hero.getActorHandle().stop(
                        name + '_ani_idle'
                    )  # ZJC - 07/26/2011: Stop the 'name' specific idle animation
                    self.hero.getActorHandle().setPlayRate(
                        -0.7, name + '_ani_run'
                    )  # ZJC - 07/26/2011: Set play rate for the 'name' specific run animation
                    self.hero.getActorHandle().loop(
                        name + '_ani_run'
                    )  # ZJC - 07/26/2011: Run the 'name' specific run animation
                self.keyMap['w'] = False
            elif key == 'a':
                self.keyMap['d'] = False
            elif key == 'd':
                self.keyMap['a'] = False
        elif not isDown:
            if key == 'w':
                if not self.keyMap['s']:
                    if self.hero.getActorHandle() != None:
                        self.hero.getActorHandle().stop(
                            name + '_ani_run'
                        )  # ZJC - 07/26/2011: Stop the 'name' specific run animation
                        self.hero.getActorHandle().loop(
                            name + '_ani_idle'
                        )  # ZJC - 07/26/2011: Run the 'name' specific idle animation
            elif key == 's':
                if not self.keyMap['w']:
                    if self.hero.getActorHandle() != None:
                        self.hero.getActorHandle().stop(
                            name + '_ani_run'
                        )  # ZJC - 07/26/2011: Stop the 'name' specific run animation
                        self.hero.getActorHandle().loop(
                            name + '_ani_idle'
                        )  # ZJC - 07/26/2011: Run the 'name' specific idle animation
            elif key == 'a':
                pass
            elif key == 'd':
                pass

            ## ZJC - 07/26/2011: This was the previous version of the code, it has been commented out and left as
            ##                  a reference. The changes made are defined in the comments above.
            ## if isDown:
            ## if key == 'w':
            ## if self.hero.getActorHandle() != None:
            ## self.hero.getActorHandle().stop('anim_idleFemale') # TODO: make a constant / set in LE
            ## self.hero.getActorHandle().setPlayRate(1.0, 'anim_jogFemale')
            ## self.hero.getActorHandle().loop('anim_jogFemale')
            ## self.keyMap['s'] = False
            ## elif key == 's':
            ## if self.hero.getActorHandle() != None:
            ## self.hero.getActorHandle().stop('anim_idleFemale') # TODO: make a constant / set in LE
            ## self.hero.getActorHandle().setPlayRate(-0.7, 'anim_jogFemale')
            ## self.hero.getActorHandle().loop('anim_jogFemale')
            ## self.keyMap['w'] = False
            ## elif key == 'a':
            ## self.keyMap['d'] = False
            ## elif key == 'd':
            ## self.keyMap['a'] = False
        ## elif not isDown:
        ## if key == 'w':
        ## if not self.keyMap['s']:
        ## if self.hero.getActorHandle() != None:
        ## self.hero.getActorHandle().stop('anim_jogFemale')
        ## self.hero.getActorHandle().loop('anim_idleFemale')
        ## elif key == 's':
        ## if not self.keyMap['w']:
        ## if self.hero.getActorHandle() != None:
        ## self.hero.getActorHandle().stop('anim_jogFemale')
        ## self.hero.getActorHandle().loop('anim_idleFemale')
        ## elif key == 'a':
        ## pass
        ## elif key == 'd':
        ## pass

    def moveHeroTask(self, task):
        dt = globalClock.getDt()

        direction = int(self.keyMap['w']) - int(self.keyMap['s'])
        self.moveHero(direction, dt)
        if self.keyMap['a']:
            self.turnHeroLeft()
        elif self.keyMap['d']:
            self.turnHeroRight()

        return task.cont


##== Scene Handling =========================================================##

    def loadScenes(self):
        # NOTE: Do not remove!  This function is populated by StandaloneExporter
        pass

    def addSequence(self, sequence):
        self.ranSequences.append(sequence)

    #this is for changing scenes
    def resetAllSequences(self):
        for seq in self.ranSequences:
            seq.finish()

        dr = self.cam.node().getDisplayRegion(0)
        dr.setCamera(self.gameCam)

        self.ranSequences = []

    def openScene(self, sceneName):
        if (self.scenes.has_key(sceneName) == False):
            print "ERROR:There is no scene under the name ", sceneName, "."
            return

        self.startLoadBar(12)
        self.createLoadScreen()

        #Part2:Clear all of the collision lists
        self.cTrav.removeCollider(self.heroCNP)
        self.heroGroundHandler.clearEntries()
        self.heroCollisionQueue.clearEntries()

        self.resetAllSequences()
        self.increaseLoadBar(1)

        #Part3: stop all of the tasks

        taskMgr.remove('processHeroCollisions')
        taskMgr.remove('updateHeroHeight')
        taskMgr.remove('moveHeroTask')
        taskMgr.remove('cameraFollowTask')
        taskMgr.remove("updateShaders")  # ?
        self.combatMgr.stopTasks()

        self.gameplayUI.stop()
        self.gameplayUI.removeAllHealthBars()

        self.increaseLoadBar(1)

        #Part1.1: Stop currently running parts like conversations or camera
        if (self.conversationMgr.isConversationOpen()):
            self.conversationMgr.closeConversation()

        #Part 1.2: stop the camera

        self.increaseLoadBar(1)

        #Part4: Turn-Off all of the player controls
        self.ignore("mouse1")

        self.increaseLoadBar(1)

        #Part5: Remove all of the game elements that are related with the current scene
        del self.combatMgr

        self.increaseLoadBar(1)

        #Part6: Remove all of the children and the lights from the render
        render.getChildren().detach()
        render.clearLight()

        self.increaseLoadBar(1)

        #Part7:Add the camera and hero or any game element that should be exist in any scene back
        self.camPivot.reparentTo(render)
        self.hero.reparentTo(render)
        #self.heroWallCollide.reparentTo(render)
        self.heroWallCollideX.reparentTo(render)
        self.heroWallCollideY.reparentTo(render)
        self.heroWallCollideZ.reparentTo(render)
        self.heroGroundCollide.reparentTo(render)
        self.cameraHeroP.reparentTo(render)

        self.overlayAmbientLightNP.reparentTo(render)

        self.increaseLoadBar(1)

        #Part8:Add the new objects from the new scene
        self.assets, self.objects, self.gameObjects, self.sounds, self.sequences = loadWorld(
            self.scenes[sceneName], LIBRARY_INDEX)

        self.increaseLoadBar(1)

        #Part9:Add the hero to the new gameObject list and remove the duplicates of the hero
        self.gameObjects[self.hero.getName()] = self.hero
        if (self.objects.has_key(self.hero.getName())):
            object = self.objects[self.hero.getName()]
            if (object.hasTag('LE-mainChar')):
                object.detachNode()
                del self.objects[self.hero.getName()]

        for name, gameObj in self.gameObjects.iteritems():
            if gameObj.getNP().hasTag('LE-ground'):
                #debug("is Ground")
                bitmask = gameObj.getNP().getCollideMask()
                bitmask |= BITMASK_GROUND
                gameObj.getNP().setCollideMask(bitmask)
        self.increaseLoadBar(1)

        #Part10:Restart the tasks.
        self.combatMgr = CombatMgr(self)

        taskMgr.add(self.processHeroCollisions, 'processHeroCollisions')
        taskMgr.add(self.updateHeroHeight, 'updateHeroHeight')
        taskMgr.add(self.moveHeroTask, 'moveHeroTask')
        taskMgr.add(self.cameraFollowTask, 'cameraFollowTask')
        self.combatMgr.startTasks()
        self.gameplayUI.start()

        self.increaseLoadBar(1)

        self.setCollideMasks(self.gameObjects)

        self.increaseLoadBar(1)

        #Part11: Change the color of the sky
        if (sceneName.startswith("interior")
                or sceneName.startswith("Interior")):
            self.setBackgroundColor(BGC_DARK_GREY)
        else:
            self.skybox.reparentTo(render)
            self.setBackgroundColor(BGC_LIGHT_BLUE)

        self.increaseLoadBar(1)

        #Part12: Restart the player controls
        self.accept("mouse1", self.onClickin3D)

        self.increaseLoadBar(1)
        self.accept("enter", self.destroyLoadScreen)

        debug("After open Scene: " +
              str(self.heroCollisionQueue.getNumEntries()))
        self.heroCollisionQueue.clearEntries()
        self.cTrav.addCollider(self.heroCNP, self.heroCollisionQueue)

        self.destroyLoadScreen()