class World(DirectObject):
    def __init__(self):
        DirectObject.__init__(self)

        self.pathSmoothening = False
        self.showWaypoints = True
        self.showCollisions = False

        self.accept("escape", sys.exit)

        self.__setupEnvironment()
        self.__setupCollisions()
        self.__setupGravity()
        self.__setupLevel()
        self.__setupTarget()
        self.__setupNPC()
        self.__setupCamera()
        self.__setupTasks()

        self.setKeymap()
        self.__NPC.pathSmoothening = self.pathSmoothening

        if (self.showWaypoints):
            print("Showing waypoints")
            for w in self.roomWaypoints:
                w.draw()

    def __setupCollisions(self):
        self.cTrav = CollisionTraverser("traverser")
        base.cTrav = self.cTrav

        self.physicsCollisionHandler = PhysicsCollisionHandler()
        self.physicsCollisionHandler.setDynamicFrictionCoef(0.5)
        self.physicsCollisionHandler.setStaticFrictionCoef(0.7)

    def __setupGravity(self):
        base.particlesEnabled = True
        base.enableParticles()

        gravityFN = ForceNode('world-forces')
        gravityFNP = render.attachNewNode(gravityFN)
        gravityForce = LinearVectorForce(0, 0,
                                         -6)  #gravity acceleration ft/s^2
        gravityFN.addForce(gravityForce)

        base.physicsMgr.addLinearForce(gravityForce)

    def __setupEnvironment(self):
        cm = CardMaker("ground")
        size = 100
        cm.setFrame(-size, size, -size, size)
        environment = render.attachNewNode(cm.generate())
        environment.lookAt(0, 0, -1)
        environment.setPos(0, 0, 0)
        environment.setCollideMask(BitMask32.allOn())
        environment.reparentTo(render)

        texture = loader.loadTexture("textures/ground.png")

        # This is so the textures can look better from a distance
        texture.setMinfilter(Texture.FTLinearMipmapLinear)

        environment.setTexGen(TextureStage.getDefault(),
                              TexGenAttrib.MWorldPosition)
        environment.setTexScale(TextureStage.getDefault(), 0.02, 0.02)
        environment.setTexture(texture, 1)

    def __setupLevel(self):
        """
        Originally planned to have multiple levels, that never happened.
        """
        level1 = render.attachNewNode("level 1 node path")

        execfile("rooms/room.py")

        self.room = loader.loadModel("rooms/room")
        self.room.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room.setScale(10, 10, 5)
        self.room.setTexScale(TextureStage.getDefault(), 10)
        self.room.reparentTo(render)
        self.room.find("**/Cube;+h").setTag("Room", "1")

        gate = loader.loadModel("models/box")

        gateTo2 = self.room.attachNewNode("gateTo2")
        gate.instanceTo(gateTo2)
        gateTo2.setPos(8, -10, 0)
        gateTo2.hide()

        self.physicsCollisionHandler.addInPattern("%fn-into-%in")
        self.physicsCollisionHandler.addOutPattern("%fn-out-%in")

        #messenger.toggleVerbose()
        self.gate = gate

    __globalAgentList = []
    __mainTarget = None

    def __setupTarget(self):
        modelStanding = "models/ralph"
        modelRunning = "models/ralph-run"
        modelWalking = "models/ralph-walk"
        self.__mainTarget = NPC(modelStanding, {
            "run": modelRunning,
            "walk": modelWalking
        },
                                turnRate=150,
                                speed=0,
                                agentList=self.__globalAgentList,
                                collisionMask=BitMask32.bit(1),
                                name="target",
                                massKg=35.0,
                                collisionHandler=self.physicsCollisionHandler,
                                collisionTraverser=self.cTrav)
        # Make it visible
        self.__mainTarget.reparentTo(render)
        self.__mainTarget.setPos(-20, -10, 0)  #-210
        self.gate.find("**/Cube;+h").setCollideMask(
            ~self.__mainTarget.collisionMask)

    __targetCount = 0
    __targets = []
    __agentToTargetMap = {}

    def __setupNPC(self):
        # This is to support the collisions for each node. See the paragraph comment
        # above where we modify the npc's collision node
        #        playerCollisionNP = self.__mainTarget.find("* collision node")

        modelStanding = "models/ralph"
        modelRunning = "models/ralph-run"
        modelWalking = "models/ralph-walk"
        self.__NPC = NPC(modelStanding, {
            "run": modelRunning,
            "walk": modelWalking
        },
                         turnRate=150,
                         speed=15,
                         agentList=self.__globalAgentList,
                         name="Ralph",
                         collisionMask=BitMask32.bit(3),
                         rangeFinderCount=13,
                         adjacencySensorThreshold=5,
                         radarSlices=5,
                         radarLength=0,
                         scale=1.0,
                         massKg=35.0,
                         collisionHandler=self.physicsCollisionHandler,
                         collisionTraverser=self.cTrav,
                         waypoints=self.roomWaypoints)
        self.__NPC.setFluidPos(render, 20, 10, 0)  #-190
        self.__NPC.setScale(render, 1)
        self.__NPC.setTarget(self.__mainTarget)

        self.__NPC.reparentTo(render)
        self.__NPC.start()

    def __setupTasks(self):
        """
        This function sets up all the tasks used in the world
        """
        taskMgr.add(taskTimer, "taskTimer")
        taskMgr.add(self.__NPC.act, "actTask")

    def __setupCamera(self):
        #This camera position shows the whole level
        base.camera.setPos(100, -100, 795)  #This is debug camera position.
        base.camera.lookAt(100, -100, 0)
        base.disableMouse()
        base.camera.reparentTo(self.__NPC.actor)
        base.camera.setPos(0, 60, 200)
        base.camera.lookAt(self.__NPC)
        base.camera.setP(base.camera.getP() + 10)

    def cameraViewRoomPos(self):
        base.camera.reparentTo(render)
        #This camera position shows entire room at once
        base.camera.setPos(0, 0, 300)  #This is debug camera position.
        base.camera.lookAt(0, 0, 0)

    def cameraRegularPos(self):
        base.camera.reparentTo(self.__NPC.actor)
        base.camera.setPos(0, 60, 200)
        base.camera.lookAt(self.__NPC)
        base.camera.setP(base.camera.getP() + 10)

    positionHeadingText = OnscreenText(text="",
                                       style=1,
                                       fg=(1, 1, 1, 1),
                                       pos=(-1.3, -0.95),
                                       align=TextNode.ALeft,
                                       scale=.05,
                                       mayChange=True)

    __keyMap = {"enablePathSmoothening": False, "showWaypoints": False}

    def setKeymap(self):
        def toggleWaypoints(key):
            self.showWaypoints = not self.showWaypoints
            if (self.showWaypoints):
                print("Showing waypoints")
                for w in self.roomWaypoints:
                    w.draw()
            else:
                print("Hiding waypoints")
                for w in self.roomWaypoints:
                    w.erase()

        def togglePathSmoothening(key):
            self.__NPC.togglePathSmoothening()

        def toggleCollisions(key):
            if (self.showCollisions):
                base.cTrav.showCollisions(render)
            else:
                base.cTrav.hideCollisions()

            self.showCollisions = not self.showCollisions
            print("showCollisions = " + str(self.showCollisions))

        self.accept("p", togglePathSmoothening, ["togglePathSmoothening"])
        self.accept("w", toggleWaypoints, ["toggleWaypoints"])
        self.accept("c", toggleCollisions, ["toggleCollisions"])
        self.accept("1", self.cameraRegularPos)
        self.accept("2", self.cameraViewRoomPos)
Ejemplo n.º 2
0
class World(DirectObject):
    def __init__(self):
        DirectObject.__init__(self)

        self.pathSmoothening = True
        self.showWaypoints = False
        self.showCollisions = False

        self.accept("escape", sys.exit)

        self.__setupEnvironment()
        self.__setupCollisions()
        self.__setupGravity()
        self.__setupLevel()
        self.__setupMainAgent()
        #        self.__setupOtherAgents()
        self.__setupNPCs()
        self.__setupCamera()
        self.__setupRandomClutter()
        #Many things within the NPC are dependant on the level it is in.
        self.__room1NPC.setKeyAndNestReference(self.keyNest1, self.room1Key)
        self.__room2NPC.setKeyAndNestReference(self.keyNest2, self.room2Key)
        #self.__room2NPC.handleTransition("playerLeftRoom")
        self.__room3NPC.setKeyAndNestReference(self.keyNest3, self.room3Key)
        #self.__room3NPC.handleTransition("playerLeftRoom")
        self.__setupTasks()

        self.setKeymap()

        # This is for the HUD
        self.keyImages = {
            self.room1Key: "models/redKeyHUD.png",
            self.room2Key: "models/blueKeyHUD.png",
            self.room3Key: "models/greenKeyHUD.png"
        }
        self.room1KeyInHUD = False
        self.room2KeyInHUD = False
        self.room3KeyInHUD = False
        self.redKeyImage = OnscreenImage(image=self.keyImages[self.room1Key],
                                         pos=(0.9, 0, 0.9),
                                         scale=(0.0451, 0, 0.1))
        self.redKeyImage.setTransparency(TransparencyAttrib.MAlpha)
        self.redKeyImage.hide()
        self.blueKeyImage = OnscreenImage(image=self.keyImages[self.room2Key],
                                          pos=(0.7, 0, 0.9),
                                          scale=(0.0451, 0, 0.1))
        self.blueKeyImage.setTransparency(TransparencyAttrib.MAlpha)
        self.blueKeyImage.hide()
        self.greenKeyImage = OnscreenImage(image=self.keyImages[self.room3Key],
                                           pos=(0.5, 0, 0.9),
                                           scale=(0.0451, 0, 0.1))
        self.greenKeyImage.setTransparency(TransparencyAttrib.MAlpha)
        self.greenKeyImage.hide()

    def reComputeHUD(self, room):
        """
       reComputeHUD is called when the player leaves a room and enters another room.
       The HUD shows the images of the keys that the player has in his backpack,
       but not the key to the current room.
       """
        ##       assert False, "add the hack to make sure she doesn't fall through the ground"
        if self.__mainAgent.hasKey(self.room1Key) and room is not self.room1:
            #self.redKeyImage.show()
            self.room1Key.reparentTo(base.cam)
            self.room1Key.setScale(render, 1.25)
            self.room1Key.setP(base.cam, 0)
            self.room1Key.setPos(
                base.cam.getX(base.cam) + 2.1,
                base.cam.getY(base.cam) + 10,
                base.cam.getZ(base.cam) + 2.1)
            self.room1KeyInHUD = True
        elif self.__mainAgent.hasKey(self.room1Key) and room is self.room1:
            rightHand = self.__mainAgent.actor.exposeJoint(
                None, 'modelRoot', 'RightHand')
            self.room1Key.reparentTo(rightHand)
            self.room1Key.setPosHpr(.11, -1.99, .06, 0, -90, 0)
            self.room1Key.setScale(render, 10)
            self.room1Key.setTexScale(TextureStage.getDefault(), 1)
            self.room1KeyInHUD = False
            self.redKeyImage.hide()
        else:
            self.redKeyImage.hide()
            self.room1KeyInHUD = False

        if self.__mainAgent.hasKey(self.room2Key) and room is not self.room2:
            #self.blueKeyImage.show()
            self.room2Key.reparentTo(base.cam)
            self.room2Key.setScale(render, 1.25)
            self.room2Key.setP(base.cam, 0)
            self.room2Key.setPos(
                base.cam.getX(base.cam) + 2.5,
                base.cam.getY(base.cam) + 10,
                base.cam.getZ(base.cam) + 2.1)
            self.room2KeyInHUD = True
        elif self.__mainAgent.hasKey(self.room2Key) and room is self.room2:
            rightHand = self.__mainAgent.actor.exposeJoint(
                None, 'modelRoot', 'RightHand')
            self.room2Key.reparentTo(rightHand)
            self.room2Key.setPosHpr(.11, -1.99, .06, 0, -90, 0)
            self.room2Key.setScale(render, 10)
            self.room2Key.setTexScale(TextureStage.getDefault(), 1)
            self.room2KeyInHUD = False
            self.blueKeyImage.hide()
        elif (self.blueKeyImage != None):
            self.blueKeyImage.hide()
            self.room2KeyInHUD = False

        if self.__mainAgent.hasKey(self.room3Key) and room is not self.room3:
            #self.greenKeyImage.show()
            self.room3Key.reparentTo(base.cam)
            self.room3Key.setScale(render, 1.25)
            self.room3Key.setP(base.cam, 0)
            self.room3Key.setPos(
                base.cam.getX(base.cam) + 3.0,
                base.cam.getY(base.cam) + 10,
                base.cam.getZ(base.cam) + 2.1)
            self.room3KeyInHUD = True
        elif self.__mainAgent.hasKey(self.room3Key) and room is self.room3:
            rightHand = self.__mainAgent.actor.exposeJoint(
                None, 'modelRoot', 'RightHand')
            self.room3Key.reparentTo(rightHand)
            self.room3Key.setPosHpr(.11, -1.99, .06, 0, -90, 0)
            self.room3Key.setScale(render, 10)
            self.room3Key.setTexScale(TextureStage.getDefault(), 1)
            self.room3KeyInHUD = False
            self.greenKeyImage.hide()
        elif (self.greenKeyImage != None):
            self.greenKeyImage.hide()

    def __setupCollisions(self):
        self.cTrav = CollisionTraverser("traverser")
        base.cTrav = self.cTrav

        self.physicsCollisionHandler = PhysicsCollisionHandler()
        self.physicsCollisionHandler.setDynamicFrictionCoef(0.5)
        self.physicsCollisionHandler.setStaticFrictionCoef(0.7)

    def __setupGravity(self):
        base.particlesEnabled = True
        base.enableParticles()

        gravityFN = ForceNode('world-forces')
        gravityFNP = render.attachNewNode(gravityFN)
        gravityForce = LinearVectorForce(0, 0,
                                         -6)  #gravity acceleration ft/s^2
        gravityFN.addForce(gravityForce)

        base.physicsMgr.addLinearForce(gravityForce)

    def __setupEnvironment(self):
        cm = CardMaker("ground")
        size = 200
        cm.setFrame(-size, size, -size, size)
        environment = render.attachNewNode(cm.generate())
        environment.lookAt(0, 0, -1)
        environment.setPos(100, -100, 0)
        environment.setCollideMask(BitMask32.allOn())
        environment.reparentTo(render)

        texture = loader.loadTexture("textures/ground.png")

        # This is so the textures can look better from a distance
        texture.setMinfilter(Texture.FTLinearMipmapLinear)

        environment.setTexGen(TextureStage.getDefault(),
                              TexGenAttrib.MWorldPosition)
        environment.setTexScale(TextureStage.getDefault(), 0.02, 0.02)
        environment.setTexture(texture, 1)

#        skyBox = loader.loadModel("models/SunnySky/sunny")
#        skyBox.setScale(10)
#        skyBox.reparentTo(render)

    def animateItems(self, task):
        if (not (self.__mainAgent.hasKey(self.room1Key)
                 or self.__room1NPC.hasKey()) or self.room1KeyInHUD):
            self.rotate(self.room1Key)
        if (not self.__mainAgent.hasKey(self.room2Key)
                and not self.__room2NPC.hasKey() or self.room2KeyInHUD):
            self.rotate(self.room2Key)
        if (not self.__mainAgent.hasKey(self.room3Key)
                and not self.__room3NPC.hasKey() or self.room3KeyInHUD):
            self.rotate(self.room3Key)
        return Task.cont

    hasAllKeys = False
    playerWasKilledByNPC1 = False
    playerWasKilledByNPC2 = False
    playerWasKilledByNPC3 = False
    #gameOver = False
    fadeCounter = 200

    def checkGameState(self, task, message=None):
        goodEndingText = OnscreenText(text="",
                                      style=1,
                                      fg=(0, 0, 1, 0.01),
                                      pos=(0, .4),
                                      align=TextNode.ACenter,
                                      scale=.25,
                                      mayChange=True)
        BaadEndingText = OnscreenText(text="",
                                      style=1,
                                      fg=(1, 0, 0, 0.01),
                                      pos=(0, .4),
                                      align=TextNode.ACenter,
                                      scale=.25,
                                      mayChange=True)
        if (self.fadeCounter > 0):
            if (self.__mainAgent.hasKey(self.room1Key)
                    and self.__mainAgent.hasKey(self.room2Key)
                    and self.__mainAgent.hasKey(self.room3Key)):
                self.hasAllKeys = True
                #goodEndingText.setText("You have all 3 keys!")
            if (self.hasAllKeys):
                goodEndingText.setText("You have all 3 keys!")
            if (PathFinder.distance(self.__mainAgent, self.__room1NPC) < 5
                    and self.__room1NPC.getState() != "returnKey"):
                if (not self.__mainAgent.hasKey(self.room1Key)):
                    self.playerWasKilledByNPC1 = True
            if (self.playerWasKilledByNPC1):
                self.fadeCounter = self.fadeCounter - 1
                BaadEndingText.setText("Killed by Eve clone Alpha")
            if (PathFinder.distance(self.__mainAgent, self.__room2NPC) < 5
                    and self.__room2NPC.getState() != "returnKey"):
                if (not self.__mainAgent.hasKey(self.room2Key)):
                    self.playerWasKilledByNPC2 = True
            if (self.playerWasKilledByNPC2):
                self.fadeCounter = self.fadeCounter - 1
                BaadEndingText.setText("Killed by Eve clone Beta")
            if (PathFinder.distance(self.__mainAgent, self.__room3NPC) < 5
                    and self.__room3NPC.getState() != "returnKey"):
                if (not self.__mainAgent.hasKey(self.room3Key)):
                    self.playerWasKilledByNPC3 = True
            if (self.playerWasKilledByNPC3):
                self.fadeCounter = self.fadeCounter - 1
                BaadEndingText.setText("Killed by Eve clone Gamma")
        return Task.cont

    currentAngle = 0

    def rotate(self, someItem):
        if someItem != None:
            self.currentAngle = self.currentAngle + 250 * taskTimer.elapsedTime
            self.currentAngle %= 360
            someItem.setH(self.currentAngle)

    def __setupLevel(self):
        """
        Some notes and caveats: Each time you add a room, make sure that you tag it with key "Room" and value "<room number>".
        This is so our A* algorithm can do clear path detection on only the rooms, not anything else.
        """
        level1 = render.attachNewNode("level 1 node path")

        execfile("rooms/room1.py")

        self.room1 = loader.loadModel("rooms/room1")
        self.room1.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room1.setScale(10)
        self.room1.setTexScale(TextureStage.getDefault(), 10)
        self.room1.reparentTo(render)
        self.room1.find("**/Cube*;+h").setTag("Room", "1")

        keyNest = loader.loadModel("models/nest")
        keyNest.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        keyNest.setScale(0.5)
        keyNest.setTexScale(TextureStage.getDefault(), 0.1)

        #place keyNest (Like a birds nest, but for keys!)
        self.keyNest1 = self.room1.attachNewNode("key nest 1")
        keyNest.instanceTo(self.keyNest1)
        self.keyNest1.setPos(0, 0, 0.05)

        self.room1Key = loader.loadModel("models/redKey")
        self.room1Key.findTexture("*").setMinfilter(
            Texture.FTLinearMipmapLinear)
        self.room1Key.reparentTo(self.keyNest1)
        self.room1Key.setScale(render, 10)
        self.room1Key.setTexScale(TextureStage.getDefault(), 0.1)

        #self.setWaypoints("room2")
        self.room2waypoints = None
        execfile("rooms/room2.py")

        self.room2 = loader.loadModel("rooms/room2")
        self.room2.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room2.setScale(10)
        self.room2.setTexScale(TextureStage.getDefault(), 10)
        self.room2.reparentTo(level1)
        self.room2.setY(self.room1, -20)
        self.room2.find("**/Cube*;+h").setTag("Room", "2")

        self.keyNest2 = self.room2.attachNewNode("key nest 2")
        keyNest.instanceTo(self.keyNest2)
        self.keyNest2.setPos(-2.5, -2.5, 0.05)

        self.room2Key = loader.loadModel("models/blueKey")
        self.room2Key.findTexture("*").setMinfilter(
            Texture.FTLinearMipmapLinear)
        self.room2Key.reparentTo(self.keyNest2)
        self.room2Key.setScale(render, 10)
        self.room2Key.setTexScale(TextureStage.getDefault(), 0.1)

        # Jim thinks there should be a comment here
        # he also thinks that the above comment is very useful
        # TODO: fix this hack by re-creating room3 in blender

        execfile("rooms/room3.py")

        room3Model = loader.loadModel("rooms/room3")
        room3Model.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        room3Model.setH(90)
        room3Model.setP(180)
        room3Model.setZ(2)
        self.room3 = level1.attachNewNode("room 3")
        room3Model.reparentTo(self.room3)
        self.room3.setScale(10)
        self.room3.setTexScale(TextureStage.getDefault(), 10)
        self.room3.reparentTo(level1)
        self.room3.setX(self.room1, 20)
        self.room3.find("**/Cube*;+h").setTag("Room", "3")

        self.keyNest3 = self.room3.attachNewNode("room 3 keynest")
        keyNest.instanceTo(self.keyNest3)
        self.keyNest3.setPos(0, 0, 0.05)

        self.room3Key = loader.loadModel("models/greenKey")
        self.room3Key.findTexture("*").setMinfilter(
            Texture.FTLinearMipmapLinear)
        self.room3Key.reparentTo(self.keyNest3)
        self.room3Key.setScale(render, 10)
        self.room3Key.setTexScale(TextureStage.getDefault(), 0.1)

        room3SphereOfDoom = self.room3.attachNewNode(
            CollisionNode("Jim's Hair"))
        room3SphereOfDoom.node().addSolid(CollisionSphere(3, -9, 0.5, 1.0))

        room1Floor = self.room1.attachNewNode(CollisionNode("room1Floor"))
        room1Floor.node().addSolid(
            CollisionPolygon(Point3(9, -9, 0), Point3(9, 9, 0),
                             Point3(-9, 9, 0), Point3(-9, -9, 0)))

        room2Floor = self.room2.attachNewNode(CollisionNode("room2Floor"))
        room2Floor.node().addSolid(
            CollisionPolygon(Point3(9, -9, 0), Point3(9, 9, 0),
                             Point3(-9, 9, 0), Point3(-9, -9, 0)))

        room3Floor = self.room3.attachNewNode(CollisionNode("room3Floor"))
        room3Floor.node().addSolid(
            CollisionPolygon(Point3(9, -9, 0), Point3(9, 9, 0),
                             Point3(-9, 9, 0), Point3(-9, -9, 0)))

        gate = loader.loadModel("models/box")

        gateTo2 = self.room1.attachNewNode("gateTo2")
        gate.instanceTo(gateTo2)
        gateTo2.setPos(8, -10, 0)
        gateTo2.hide()

        gateTo3 = self.room1.attachNewNode("gateTo3")
        gate.instanceTo(gateTo3)
        gateTo3.setPos(10, 8, 0)
        gateTo3.hide()

        self.physicsCollisionHandler.addInPattern("%fn-into-%in")
        self.physicsCollisionHandler.addOutPattern("%fn-out-%in")

        def orderNPC(parameters, entry):

            if (parameters == "ralph has entered room 1"):
                self.__room1NPC.handleTransition("playerEnteredRoom")
                self.reComputeHUD(self.room1)
                if self.__mainAgent.hasKey(self.room1Key):
                    self.__mainAgent.setCurrentKey(self.room1Key)
            elif (parameters == "ralph has left room 1"):
                self.__room1NPC.handleTransition("playerLeftRoom")
                if self.__mainAgent.hasKey(self.room1Key):
                    self.__mainAgent.setCurrentKey(None)
            elif (parameters == "ralph has entered room 2"):
                self.__room2NPC.handleTransition("playerEnteredRoom")
                self.reComputeHUD(self.room2)
                if self.__mainAgent.hasKey(self.room2Key):
                    self.__mainAgent.setCurrentKey(self.room2Key)
            elif (parameters == "ralph has left room 2"):
                self.__room2NPC.handleTransition("playerLeftRoom")
                if self.__mainAgent.hasKey(self.room2Key):
                    self.__mainAgent.setCurrentKey(None)
            elif (parameters == "ralph has entered room 3"):
                self.__room3NPC.handleTransition("playerEnteredRoom")
                if self.__mainAgent.hasKey(self.room3Key):
                    self.__mainAgent.setCurrentKey(self.room3Key)
                self.reComputeHUD(self.room3)
            elif (parameters == "ralph has left room 3"):
                self.__room3NPC.handleTransition("playerLeftRoom")
                if self.__mainAgent.hasKey(self.room3Key):
                    self.__mainAgent.setCurrentKey(None)
            elif (parameters == "NPC1 bumped into wall"):
                self.__room1NPC.handleTransition("bumpedIntoWall")
            elif (parameters == "NPC2 bumped into wall"):
                self.__room2NPC.handleTransition("bumpedIntoWall")
            elif (parameters == "NPC3 bumped into wall"):
                self.__room3NPC.handleTransition("bumpedIntoWall")

        self.accept("ralph collision node-into-room1Floor", orderNPC,
                    ["ralph has entered room 1"])
        self.accept("ralph collision node-out-room1Floor", orderNPC,
                    ["ralph has left room 1"])
        self.accept("ralph collision node-into-room2Floor", orderNPC,
                    ["ralph has entered room 2"])
        self.accept("ralph collision node-out-room2Floor", orderNPC,
                    ["ralph has left room 2"])
        self.accept("ralph collision node-into-room3Floor", orderNPC,
                    ["ralph has entered room 3"])
        self.accept("ralph collision node-out-room3Floor", orderNPC,
                    ["ralph has left room 3"])
        self.accept("Eve 1 collision node-into-Cube1", orderNPC,
                    ["NPC1 bumped into wall"])
        self.accept("Eve 2 collision node-into-Cube2", orderNPC,
                    ["NPC2 bumped into wall"])
        self.accept("Eve 3 collision node-into-Cube3", orderNPC,
                    ["NPC3 bumped into wall"])

        #messenger.toggleVerbose()
        self.gate = gate

    __globalAgentList = []
    __mainAgent = None

    def __setupMainAgent(self):
        modelStanding = "models/ralph"
        modelRunning = "models/ralph-run"
        modelWalking = "models/ralph-walk"
        self.__mainAgent = Player(
            modelStanding, {
                "run": modelRunning,
                "walk": modelWalking
            },
            turnRate=150,
            speed=25,
            agentList=self.__globalAgentList,
            collisionMask=BitMask32.bit(1),
            name="ralph",
            massKg=35.0,
            collisionHandler=self.physicsCollisionHandler,
            collisionTraverser=self.cTrav)
        # Make it visible
        self.__mainAgent.reparentTo(render)
        self.__mainAgent.setPos(31, 35, 50)
        self.gate.find("**/Cube;+h").setCollideMask(
            ~self.__mainAgent.collisionMask)

    __targetCount = 0
    __targets = []
    __agentToTargetMap = {}

    def __setupNPCs(self):
        # This is to support the collisions for each node. See the paragraph comment
        # above where we modify the npc's collision node
        playerCollisionNP = self.__mainAgent.find("* collision node")

        modelStanding = "models/eve"
        modelRunning = "models/eve-run"
        modelWalking = "models/eve-walk"
        self.__room1NPC = NPC(modelStanding, {
            "run": modelRunning,
            "walk": modelWalking
        },
                              turnRate=150,
                              speed=15,
                              agentList=self.__globalAgentList,
                              name="Eve 1",
                              collisionMask=BitMask32.bit(3),
                              rangeFinderCount=13,
                              adjacencySensorThreshold=5,
                              radarSlices=5,
                              radarLength=40,
                              scale=1.0,
                              massKg=35.0,
                              collisionHandler=self.physicsCollisionHandler,
                              collisionTraverser=self.cTrav,
                              waypoints=self.room1waypoints)
        self.__room1NPC.setFluidPos(render, 0, 0, 10)
        self.__room1NPC.setScale(render, 1)
        self.__room1NPC.setPlayer(self.__mainAgent)
        self.__room1NPC.reparentTo(render)

        # So here's what I'm thinking. Currently, two collisions are happening when
        # we collide with an NPC. Those are Player-->NPC and NPC-->Player. This is
        # causing some jumpiness, which in tern causes some collisions to fail (e.g.,
        # falling through the floor). In order to fix this, we need to ignore one of
        # these collisions. Since the NPC should react to the Player, and not vice-versa,
        # I'll ignore the Player-->NPC collision. To do this, we need to set Player's into
        # collide mask to exclude NPC's from collide mask. Let's hope this doesn't break
        # anything.
        npcCollisionNP = self.__room1NPC.find("* collision node")
        npcCollisionNP.node().setIntoCollideMask(
            npcCollisionNP.node().getIntoCollideMask()
            & ~playerCollisionNP.node().getIntoCollideMask())

        ##        modelStanding = "models/bunny/bunny"
        ##        modelRunning = "models/bunny/bunny"
        ##        modelWalking = "models/bunny/bunny"
        self.__room2NPC = NPC(
            modelStanding,
            {
                "run": modelRunning,
                "walk": modelWalking
            },
            turnRate=150,
            speed=15,
            agentList=self.__globalAgentList,
            name="Eve 2",  #"das Osterhase",
            collisionMask=BitMask32.bit(4),
            rangeFinderCount=13,
            adjacencySensorThreshold=5,
            radarSlices=5,
            radarLength=40,
            scale=1.0,
            massKg=35.0,
            collisionHandler=self.physicsCollisionHandler,
            collisionTraverser=self.cTrav,
            waypoints=self.room2waypoints)
        self.__room2NPC.setPos(-20, -210, 10)
        self.__room2NPC.setPlayer(self.__mainAgent)
        self.__room2NPC.reparentTo(render)
        npcCollisionNP = self.__room2NPC.find("* collision node")
        npcCollisionNP.node().setIntoCollideMask(
            npcCollisionNP.node().getIntoCollideMask()
            & ~playerCollisionNP.node().getIntoCollideMask())

        self.__room3NPC = NPC(
            modelStanding,
            {
                "run": modelRunning,
                "walk": modelWalking
            },
            turnRate=150,
            speed=15,
            agentList=self.__globalAgentList,
            name="Eve 3",  #"der Hoppelhaschen",
            collisionMask=BitMask32.bit(5),
            rangeFinderCount=13,
            adjacencySensorThreshold=5,
            radarSlices=5,
            radarLength=40,
            scale=1.0,
            massKg=35.0,
            collisionHandler=self.physicsCollisionHandler,
            collisionTraverser=self.cTrav,
            waypoints=self.room3waypoints)
        self.__room3NPC.setPos(210, 0, 10)
        self.__room3NPC.setPlayer(self.__mainAgent)
        self.__room3NPC.reparentTo(render)
        npcCollisionNP = self.__room3NPC.find("* collision node")
        npcCollisionNP.node().setIntoCollideMask(
            npcCollisionNP.node().getIntoCollideMask()
            & ~playerCollisionNP.node().getIntoCollideMask())

    def __setupRandomClutter(self):
        ##        self.ball1 = loader.loadModel("models/ball")
        ##        #self.ball1.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        ##        self.ball1.findTexture("hedge.jpg")
        ##        self.ball1.setTexScale(TextureStage.getDefault(), 0.1)
        ##        self.ball1.setPos(0,0,0)
        ##        self.ball1.reparentTo(render)
        pass

    def __setupTasks(self):
        """
        This function sets up all the tasks used in the world
        """
        taskMgr.add(taskTimer, "taskTimer")

        #for index, ralph in enumerate(self.__otherRalphs):

        ##            taskMgr.add(ralph.sense, "sense" + str(index))
        ##            taskMgr.add(ralph.think, "think" + str(index))
        ##            taskMgr.add(ralph.act,   "act"   + str(index))
        #taskMgr.add(ralph.wanderTask, "wander" + str(index))
        ##            taskMgr.add(ralph.seekTask, "seekTask" + str(index), extraArgs = [self.__agentToTargetMap[ralph]], appendTask = True)

        taskMgr.add(self.__printPositionAndHeading,
                    "__printPositionAndHeading")

        ##        listOfTargets = [(target.getX(), target.getY()) for target in self.__targets]
        ##        agentList = [(ralph.getX(), ralph.getY()) for ralph in self.__otherRalphs]
        ##        taskMgr.add(self.neatEvaluateTask, "self.neatEvaluateTask", extraArgs = [listOfTargets, self.__otherRalphs], appendTask = True)

        self.__mainAgent.setKeymap()
        taskMgr.add(self.__mainAgent.processKey, "processKeyTask")

        #  taskMgr.add(self.__mainAgent.handleCollisionTask, "handleCollisionTask")
        ##        taskMgr.add(self.ralph.wanderTask, "wander")

        taskMgr.add(self.__room1NPC.sense, "senseTask")
        taskMgr.add(self.__room2NPC.sense, "senseTask")
        taskMgr.add(self.__room3NPC.sense, "senseTask")
        ##        taskMgr.add(self.ralph.think, "thinkTask")
        taskMgr.add(self.__room1NPC.act, "actTask")
        taskMgr.add(self.__room2NPC.act, "actTask")
        taskMgr.add(self.__room3NPC.act, "actTask")
        taskMgr.add(self.checkGameState, "gameStateTask")
        taskMgr.add(self.animateItems, "animateItemsTask")
        #taskMgr.add(self.processKey, "processKeyTask")

        # This is for path finding
        #taskMgr.add(self.__room1NPC.followPath, "followPathTask", extraArgs = [self.bestPath], appendTask = True)

    def __setupCamera(self):
        #This camera position shows the whole level
        base.camera.setPos(100, -100, 795)  #This is debug camera position.
        base.camera.lookAt(100, -100, 0)
        #This camera position shows room1
        #base.camera.setPos(0,0, 375) #This is debug camera position.
        #base.camera.lookAt(0,0,0)
        #This camera position shows room2
        #base.camera.setPos(0,-200, 375) #This is debug camera position.
        #base.camera.lookAt(0,-200,0)
        #This camera position shows room3
        #base.camera.setPos(200,0, 375) #This is debug camera position.
        #base.camera.lookAt(200,0,0)
        #base.oobeCull()
        #base.oobe()
        base.disableMouse()
        base.camera.reparentTo(self.__mainAgent.actor)
        base.camera.setPos(0, 60, 60)
        base.camera.lookAt(self.__mainAgent)
        base.camera.setP(base.camera.getP() + 10)

    def cameraRoom1Pos(self):
        base.camera.reparentTo(render)
        #This camera position shows room1
        base.camera.setPos(0, 0, 375)  #This is debug camera position.
        base.camera.lookAt(0, 0, 0)

    def cameraRoom2Pos(self):
        base.camera.reparentTo(render)
        #This camera position shows room2
        base.camera.setPos(0, -200, 375)  #This is debug camera position.
        base.camera.lookAt(0, -200, 0)

    def cameraRoom3Pos(self):
        base.camera.reparentTo(render)
        #This camera position shows room3
        base.camera.setPos(200, 0, 375)  #This is debug camera position.
        base.camera.lookAt(200, 0, 0)

    def cameraRegularPos(self):
        base.camera.reparentTo(self.__mainAgent.actor)
        base.camera.setPos(0, 60, 60)
        base.camera.lookAt(self.__mainAgent)
        base.camera.setP(base.camera.getP() + 10)

    positionHeadingText = OnscreenText(text="",
                                       style=1,
                                       fg=(1, 1, 1, 1),
                                       pos=(-1.3, -0.95),
                                       align=TextNode.ALeft,
                                       scale=.05,
                                       mayChange=True)

    def __printPositionAndHeading(self, task):
        heading = self.__mainAgent.getH()
        heading %= 360.0


##        self.positionHeadingText.setText("Position: (" +
##            str(self.__mainAgent.getX()) + ", " +
##            str(self.__mainAgent.getY()) + ", " +
##            str(self.__mainAgent.getZ()) + ") at heading " +
##            str(heading))
##        return Task.cont

# Every generation, throw out the old brains and put in the new ones. At
# this point we can start all over with new nodes.

    generationCount = 0
    generationLifetimeTicks = 500
    neatEvaluateTaskCallCount = 0

    ##    neuralNetwork = NeuralNetwork()
    def neatEvaluateTask(self, listOfTargets, agentList, task):
        self.neatEvaluateTaskCallCount += 1
        if self.generationLifetimeTicks == self.neatEvaluateTaskCallCount:
            self.neatEvaluateTaskCallCount = 0
            oldBrains = [agent.brain for agent in agentList]
            self.generationCount += 1
            listOfPositions = [(agent.getX(), agent.getY())
                               for agent in agentList]
            newBrains = self.neuralNetwork.nextGeneration(
                oldBrains, listOfTargets, listOfPositions)

            for agent, brain in zip(agentList, newBrains):
                agent.brain = brain
                agent.setPos(self.startingPositions[agent])

        return Task.cont

    __keyMap = {"enablePathSmoothening": False, "showWaypoints": False}

    def setKeymap(self):
        def toggleWaypoints(key):
            self.showWaypoints = not self.showWaypoints
            if (self.showWaypoints):
                print("Showing waypoints")
                for w in self.room1waypoints:
                    w.draw()
                for w in self.room2waypoints:
                    w.draw()
                for w in self.room3waypoints:
                    w.draw()
            else:
                print("Hiding waypoints")
                for w in self.room1waypoints:
                    w.erase()
                for w in self.room2waypoints:
                    w.erase()
                for w in self.room3waypoints:
                    w.erase()

        def togglePathSmoothening(key):
            self.__room1NPC.togglePathSmoothening()
            self.__room2NPC.togglePathSmoothening()
            self.__room3NPC.togglePathSmoothening()

        def toggleCollisions(key):
            if (self.showCollisions):
                base.cTrav.showCollisions(render)
            else:
                base.cTrav.hideCollisions()

            self.showCollisions = not self.showCollisions
            print("showCollisions = " + str(self.showCollisions))

        self.accept("p", togglePathSmoothening, ["togglePathSmoothening"])
        self.accept("w", toggleWaypoints, ["toggleWaypoints"])
        self.accept("c", toggleCollisions, ["toggleCollisions"])
        self.accept("1", self.cameraRoom1Pos)
        self.accept("2", self.cameraRoom2Pos)
        self.accept("3", self.cameraRoom3Pos)
        self.accept("4", self.cameraRegularPos)
class World(DirectObject):     
    def __init__(self):
        DirectObject.__init__(self)
        
        self.pathSmoothening = True
        self.showWaypoints = False
        self.showCollisions = False
        
        self.accept("escape", sys.exit)
        
        self.__setupEnvironment()
        self.__setupCollisions()
        self.__setupGravity()
        self.__setupLevel()
        self.__setupMainAgent()
#        self.__setupOtherAgents()
        self.__setupNPCs()
        self.__setupCamera()
        self.__setupRandomClutter()
        #Many things within the NPC are dependant on the level it is in.
        self.__room1NPC.setKeyAndNestReference(self.keyNest1, self.room1Key)
        self.__room2NPC.setKeyAndNestReference(self.keyNest2, self.room2Key)
        #self.__room2NPC.handleTransition("playerLeftRoom")
        self.__room3NPC.setKeyAndNestReference(self.keyNest3, self.room3Key)
        #self.__room3NPC.handleTransition("playerLeftRoom")
        self.__setupTasks()
        
        self.setKeymap()

        # This is for the HUD
        self.keyImages = {
              self.room1Key:"models/redKeyHUD.png",
              self.room2Key:"models/blueKeyHUD.png",
              self.room3Key:"models/greenKeyHUD.png" }
        self.room1KeyInHUD = False
        self.room2KeyInHUD = False
        self.room3KeyInHUD = False
        self.redKeyImage = OnscreenImage(image = self.keyImages[self.room1Key], pos = (0.9, 0, 0.9), scale = (0.0451, 0, 0.1))
        self.redKeyImage.setTransparency(TransparencyAttrib.MAlpha)
        self.redKeyImage.hide()
        self.blueKeyImage = OnscreenImage(image = self.keyImages[self.room2Key], pos = (0.7, 0, 0.9), scale = (0.0451, 0, 0.1))
        self.blueKeyImage.setTransparency(TransparencyAttrib.MAlpha)
        self.blueKeyImage.hide()
        self.greenKeyImage = OnscreenImage(image = self.keyImages[self.room3Key], pos = (0.5, 0, 0.9), scale = (0.0451, 0, 0.1))
        self.greenKeyImage.setTransparency(TransparencyAttrib.MAlpha)
        self.greenKeyImage.hide()

        

    def reComputeHUD(self, room):
       """
       reComputeHUD is called when the player leaves a room and enters another room.
       The HUD shows the images of the keys that the player has in his backpack,
       but not the key to the current room.
       """
##       assert False, "add the hack to make sure she doesn't fall through the ground"
       if self.__mainAgent.hasKey(self.room1Key) and room is not self.room1:
          #self.redKeyImage.show()
          self.room1Key.reparentTo(base.cam)
          self.room1Key.setScale(render, 1.25)
          self.room1Key.setP(base.cam, 0)
          self.room1Key.setPos(base.cam.getX(base.cam) + 2.1, base.cam.getY(base.cam) + 10, base.cam.getZ(base.cam) + 2.1)
          self.room1KeyInHUD = True
       elif self.__mainAgent.hasKey(self.room1Key) and room is self.room1:
          rightHand = self.__mainAgent.actor.exposeJoint(None, 'modelRoot', 'RightHand')
          self.room1Key.reparentTo(rightHand)
          self.room1Key.setPosHpr(.11,-1.99,.06, 0,-90,0)
          self.room1Key.setScale(render, 10)
          self.room1Key.setTexScale(TextureStage.getDefault(), 1)
          self.room1KeyInHUD = False
          self.redKeyImage.hide()
       else:
          self.redKeyImage.hide()
          self.room1KeyInHUD = False

       if self.__mainAgent.hasKey(self.room2Key) and room is not self.room2:
          #self.blueKeyImage.show()
          self.room2Key.reparentTo(base.cam)
          self.room2Key.setScale(render, 1.25)
          self.room2Key.setP(base.cam, 0)
          self.room2Key.setPos(base.cam.getX(base.cam) + 2.5, base.cam.getY(base.cam) + 10, base.cam.getZ(base.cam) + 2.1)
          self.room2KeyInHUD = True
       elif self.__mainAgent.hasKey(self.room2Key) and room is self.room2:
          rightHand = self.__mainAgent.actor.exposeJoint(None, 'modelRoot', 'RightHand')
          self.room2Key.reparentTo(rightHand)
          self.room2Key.setPosHpr(.11,-1.99,.06, 0,-90,0)
          self.room2Key.setScale(render, 10)
          self.room2Key.setTexScale(TextureStage.getDefault(), 1)
          self.room2KeyInHUD = False
          self.blueKeyImage.hide()
       elif (self.blueKeyImage != None):
          self.blueKeyImage.hide()
          self.room2KeyInHUD = False

       if self.__mainAgent.hasKey(self.room3Key) and room is not self.room3:
          #self.greenKeyImage.show()
          self.room3Key.reparentTo(base.cam)
          self.room3Key.setScale(render, 1.25)
          self.room3Key.setP(base.cam, 0)
          self.room3Key.setPos(base.cam.getX(base.cam) + 3.0, base.cam.getY(base.cam) + 10, base.cam.getZ(base.cam) + 2.1)
          self.room3KeyInHUD = True
       elif self.__mainAgent.hasKey(self.room3Key) and room is self.room3:
          rightHand = self.__mainAgent.actor.exposeJoint(None, 'modelRoot', 'RightHand')
          self.room3Key.reparentTo(rightHand)
          self.room3Key.setPosHpr(.11,-1.99,.06, 0,-90,0)
          self.room3Key.setScale(render, 10)
          self.room3Key.setTexScale(TextureStage.getDefault(), 1)
          self.room3KeyInHUD = False
          self.greenKeyImage.hide()
       elif (self.greenKeyImage != None):
          self.greenKeyImage.hide()

    def __setupCollisions(self):
        self.cTrav = CollisionTraverser("traverser")
        base.cTrav = self.cTrav
        
        self.physicsCollisionHandler = PhysicsCollisionHandler()
        self.physicsCollisionHandler.setDynamicFrictionCoef(0.5)
        self.physicsCollisionHandler.setStaticFrictionCoef(0.7)

    def __setupGravity(self):
        base.particlesEnabled = True
        base.enableParticles()
        
        gravityFN=ForceNode('world-forces')
        gravityFNP=render.attachNewNode(gravityFN)
        gravityForce=LinearVectorForce(0,0,-6) #gravity acceleration ft/s^2
        gravityFN.addForce(gravityForce)
        


        base.physicsMgr.addLinearForce(gravityForce)

    def __setupEnvironment(self):
        cm = CardMaker("ground")
        size = 200
        cm.setFrame(-size, size, -size, size)
        environment = render.attachNewNode(cm.generate())
        environment.lookAt(0, 0, -1)
        environment.setPos(100, -100, 0)
        environment.setCollideMask(BitMask32.allOn())
        environment.reparentTo(render)
        
        texture = loader.loadTexture("textures/ground.png")
        
        # This is so the textures can look better from a distance
        texture.setMinfilter(Texture.FTLinearMipmapLinear)
        
        environment.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldPosition) 
        environment.setTexScale(TextureStage.getDefault(), 0.02, 0.02)
        environment.setTexture(texture, 1)

#        skyBox = loader.loadModel("models/SunnySky/sunny")
#        skyBox.setScale(10)
#        skyBox.reparentTo(render)
        
    def animateItems(self, task):
        if(not (self.__mainAgent.hasKey(self.room1Key) or self.__room1NPC.hasKey()) or self.room1KeyInHUD):
            self.rotate(self.room1Key)
        if(not self.__mainAgent.hasKey(self.room2Key) and not self.__room2NPC.hasKey() or self.room2KeyInHUD):
            self.rotate(self.room2Key)
        if(not self.__mainAgent.hasKey(self.room3Key) and not self.__room3NPC.hasKey() or self.room3KeyInHUD):
            self.rotate(self.room3Key)
        return Task.cont

    hasAllKeys = False
    playerWasKilledByNPC1 = False
    playerWasKilledByNPC2 = False
    playerWasKilledByNPC3 = False
    #gameOver = False
    fadeCounter = 200
    def checkGameState(self, task, message = None):
        goodEndingText = OnscreenText(text="", style=1, fg=(0,0,1,0.01),
                            pos=(0,.4), align=TextNode.ACenter, scale = .25, mayChange = True)
        BaadEndingText = OnscreenText(text="", style=1, fg=(1,0,0,0.01),
                            pos=(0,.4), align=TextNode.ACenter, scale = .25, mayChange = True)
        if(self.fadeCounter > 0):
            if(self.__mainAgent.hasKey(self.room1Key) and self.__mainAgent.hasKey(self.room2Key) and self.__mainAgent.hasKey(self.room3Key)):
                self.hasAllKeys = True
                #goodEndingText.setText("You have all 3 keys!")
            if(self.hasAllKeys):
                goodEndingText.setText("You have all 3 keys!")
            if(PathFinder.distance(self.__mainAgent, self.__room1NPC) < 5 and self.__room1NPC.getState() != "returnKey"):
                if(not self.__mainAgent.hasKey(self.room1Key)):
                    self.playerWasKilledByNPC1 = True
            if(self.playerWasKilledByNPC1):
                self.fadeCounter = self.fadeCounter - 1
                BaadEndingText.setText("Killed by Eve clone Alpha")
            if(PathFinder.distance(self.__mainAgent, self.__room2NPC) < 5 and self.__room2NPC.getState() != "returnKey"):
                if(not self.__mainAgent.hasKey(self.room2Key)):
                    self.playerWasKilledByNPC2 = True
            if(self.playerWasKilledByNPC2):
                self.fadeCounter = self.fadeCounter - 1
                BaadEndingText.setText("Killed by Eve clone Beta")
            if(PathFinder.distance(self.__mainAgent, self.__room3NPC) < 5 and self.__room3NPC.getState() != "returnKey"):
                if(not self.__mainAgent.hasKey(self.room3Key)):
                    self.playerWasKilledByNPC3 = True
            if(self.playerWasKilledByNPC3):
                self.fadeCounter = self.fadeCounter - 1
                BaadEndingText.setText("Killed by Eve clone Gamma")
        return Task.cont
    
    currentAngle = 0
    def rotate(self, someItem):
        if someItem != None:
            self.currentAngle = self.currentAngle + 250 * taskTimer.elapsedTime
            self.currentAngle %= 360
            someItem.setH(self.currentAngle)
            
    def __setupLevel(self):
        """
        Some notes and caveats: Each time you add a room, make sure that you tag it with key "Room" and value "<room number>".
        This is so our A* algorithm can do clear path detection on only the rooms, not anything else.
        """
        level1 = render.attachNewNode("level 1 node path")
        
        execfile("rooms/room1.py")

        self.room1 = loader.loadModel("rooms/room1")
        self.room1.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room1.setScale(10)
        self.room1.setTexScale(TextureStage.getDefault(), 10)
        self.room1.reparentTo(render)
        self.room1.find("**/Cube*;+h").setTag("Room", "1")

        keyNest = loader.loadModel("models/nest")
        keyNest.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        keyNest.setScale(0.5)
        keyNest.setTexScale(TextureStage.getDefault(), 0.1)

        #place keyNest (Like a birds nest, but for keys!)
        self.keyNest1 = self.room1.attachNewNode("key nest 1")
        keyNest.instanceTo(self.keyNest1)
        self.keyNest1.setPos(0, 0, 0.05)

        self.room1Key = loader.loadModel("models/redKey")
        self.room1Key.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room1Key.reparentTo(self.keyNest1)
        self.room1Key.setScale(render, 10)
        self.room1Key.setTexScale(TextureStage.getDefault(), 0.1)
        
        #self.setWaypoints("room2")
        self.room2waypoints = None
        execfile("rooms/room2.py")

        self.room2 = loader.loadModel("rooms/room2")
        self.room2.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room2.setScale(10)
        self.room2.setTexScale(TextureStage.getDefault(), 10)
        self.room2.reparentTo(level1)
        self.room2.setY(self.room1, -20)
        self.room2.find("**/Cube*;+h").setTag("Room", "2")
        
        self.keyNest2 = self.room2.attachNewNode("key nest 2")
        keyNest.instanceTo(self.keyNest2)
        self.keyNest2.setPos(-2.5, -2.5, 0.05)
        
        self.room2Key = loader.loadModel("models/blueKey")
        self.room2Key.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room2Key.reparentTo(self.keyNest2)
        self.room2Key.setScale(render, 10)
        self.room2Key.setTexScale(TextureStage.getDefault(), 0.1)
        
        # Jim thinks there should be a comment here
        # he also thinks that the above comment is very useful
        # TODO: fix this hack by re-creating room3 in blender
        
        execfile("rooms/room3.py")
        
        room3Model = loader.loadModel("rooms/room3")
        room3Model.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        room3Model.setH(90)
        room3Model.setP(180)
        room3Model.setZ(2)
        self.room3 = level1.attachNewNode("room 3")
        room3Model.reparentTo(self.room3)
        self.room3.setScale(10)
        self.room3.setTexScale(TextureStage.getDefault(), 10)
        self.room3.reparentTo(level1)
        self.room3.setX(self.room1, 20)
        self.room3.find("**/Cube*;+h").setTag("Room", "3")
        
        
        self.keyNest3 = self.room3.attachNewNode("room 3 keynest") 
        keyNest.instanceTo(self.keyNest3)
        self.keyNest3.setPos(0, 0, 0.05)
        
        
        self.room3Key = loader.loadModel("models/greenKey")
        self.room3Key.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room3Key.reparentTo(self.keyNest3)
        self.room3Key.setScale(render, 10)
        self.room3Key.setTexScale(TextureStage.getDefault(), 0.1)
        
        
        room3SphereOfDoom = self.room3.attachNewNode(CollisionNode("Jim's Hair"))
        room3SphereOfDoom.node().addSolid(CollisionSphere(3, -9, 0.5, 1.0))
        
        room1Floor = self.room1.attachNewNode(CollisionNode("room1Floor"))
        room1Floor.node().addSolid(CollisionPolygon(Point3(9,-9,0), Point3(9,9,0),
                                                Point3(-9,9,0), Point3(-9,-9,0)))
                                                
        room2Floor = self.room2.attachNewNode(CollisionNode("room2Floor"))
        room2Floor.node().addSolid(CollisionPolygon(Point3(9,-9,0), Point3(9,9,0),
                                                Point3(-9,9,0), Point3(-9,-9,0)))

        room3Floor = self.room3.attachNewNode(CollisionNode("room3Floor"))
        room3Floor.node().addSolid(CollisionPolygon(Point3(9,-9,0), Point3(9,9,0),
                                                Point3(-9,9,0), Point3(-9,-9,0)))
                                                

        
        gate = loader.loadModel("models/box")
        
        gateTo2 = self.room1.attachNewNode("gateTo2")
        gate.instanceTo(gateTo2)
        gateTo2.setPos(8, -10, 0)
        gateTo2.hide()
        
        gateTo3 = self.room1.attachNewNode("gateTo3")
        gate.instanceTo(gateTo3)
        gateTo3.setPos(10, 8, 0)
        gateTo3.hide()
        
        self.physicsCollisionHandler.addInPattern("%fn-into-%in")
        self.physicsCollisionHandler.addOutPattern("%fn-out-%in")
        
    
        
        def orderNPC(parameters, entry):
            
            if(parameters == "ralph has entered room 1"):
                self.__room1NPC.handleTransition("playerEnteredRoom")
                self.reComputeHUD(self.room1)
                if self.__mainAgent.hasKey(self.room1Key):
                    self.__mainAgent.setCurrentKey(self.room1Key)
            elif(parameters == "ralph has left room 1"):
                self.__room1NPC.handleTransition("playerLeftRoom")
                if self.__mainAgent.hasKey(self.room1Key):
                    self.__mainAgent.setCurrentKey(None)
            elif(parameters == "ralph has entered room 2"):
                self.__room2NPC.handleTransition("playerEnteredRoom")
                self.reComputeHUD(self.room2)
                if self.__mainAgent.hasKey(self.room2Key):
                    self.__mainAgent.setCurrentKey(self.room2Key)
            elif(parameters == "ralph has left room 2"):
                self.__room2NPC.handleTransition("playerLeftRoom")
                if self.__mainAgent.hasKey(self.room2Key):
                    self.__mainAgent.setCurrentKey(None)
            elif(parameters == "ralph has entered room 3"):
                self.__room3NPC.handleTransition("playerEnteredRoom")
                if self.__mainAgent.hasKey(self.room3Key):
                    self.__mainAgent.setCurrentKey(self.room3Key)
                self.reComputeHUD(self.room3)
            elif(parameters == "ralph has left room 3"):
                self.__room3NPC.handleTransition("playerLeftRoom")
                if self.__mainAgent.hasKey(self.room3Key):
                    self.__mainAgent.setCurrentKey(None)
            elif(parameters == "NPC1 bumped into wall"):
                self.__room1NPC.handleTransition("bumpedIntoWall")
            elif(parameters == "NPC2 bumped into wall"):
                self.__room2NPC.handleTransition("bumpedIntoWall")
            elif(parameters == "NPC3 bumped into wall"):
                self.__room3NPC.handleTransition("bumpedIntoWall")
                
        
        self.accept("ralph collision node-into-room1Floor", orderNPC, ["ralph has entered room 1"])
        self.accept("ralph collision node-out-room1Floor", orderNPC, ["ralph has left room 1"])
        self.accept("ralph collision node-into-room2Floor", orderNPC, ["ralph has entered room 2"])
        self.accept("ralph collision node-out-room2Floor", orderNPC, ["ralph has left room 2"])
        self.accept("ralph collision node-into-room3Floor", orderNPC, ["ralph has entered room 3"])
        self.accept("ralph collision node-out-room3Floor", orderNPC, ["ralph has left room 3"])
        self.accept("Eve 1 collision node-into-Cube1", orderNPC, ["NPC1 bumped into wall"])
        self.accept("Eve 2 collision node-into-Cube2", orderNPC, ["NPC2 bumped into wall"])
        self.accept("Eve 3 collision node-into-Cube3", orderNPC, ["NPC3 bumped into wall"])
        

        #messenger.toggleVerbose()
        self.gate = gate
        

    __globalAgentList = []
    __mainAgent = None
    def __setupMainAgent(self):
        modelStanding = "models/ralph"
        modelRunning = "models/ralph-run"
        modelWalking = "models/ralph-walk"
        self.__mainAgent = Player(modelStanding, 
                            {"run":modelRunning, "walk":modelWalking},
                            turnRate = 150, 
                            speed = 25,
                            agentList = self.__globalAgentList,
                            collisionMask = BitMask32.bit(1),
                            name="ralph",
                            massKg = 35.0,
                            collisionHandler = self.physicsCollisionHandler,
                            collisionTraverser = self.cTrav)
        # Make it visible
        self.__mainAgent.reparentTo(render)
        self.__mainAgent.setPos(31, 35, 50)
        self.gate.find("**/Cube;+h").setCollideMask(~self.__mainAgent.collisionMask)
        
    __targetCount = 0
    __targets = []
    __agentToTargetMap = {}
    def __setupNPCs(self):
        # This is to support the collisions for each node. See the paragraph comment
        # above where we modify the npc's collision node
        playerCollisionNP = self.__mainAgent.find("* collision node")

        modelStanding = "models/eve"
        modelRunning = "models/eve-run"
        modelWalking = "models/eve-walk"
        self.__room1NPC = NPC(modelStanding, 
                                {"run":modelRunning, "walk":modelWalking},
                                turnRate = 150, 
                                speed = 15,
                                agentList = self.__globalAgentList,
                                name = "Eve 1",
                                collisionMask = BitMask32.bit(3),
                                rangeFinderCount = 13,
                                adjacencySensorThreshold = 5,
                                radarSlices = 5,
                                radarLength = 40,
                                scale = 1.0,
                                massKg = 35.0,
                                collisionHandler = self.physicsCollisionHandler,
                                collisionTraverser = self.cTrav,
                                waypoints = self.room1waypoints)
        self.__room1NPC.setFluidPos(render, 0, 0, 10)
        self.__room1NPC.setScale(render, 1)
        self.__room1NPC.setPlayer(self.__mainAgent)
        self.__room1NPC.reparentTo(render)


        # So here's what I'm thinking. Currently, two collisions are happening when
        # we collide with an NPC. Those are Player-->NPC and NPC-->Player. This is
        # causing some jumpiness, which in tern causes some collisions to fail (e.g.,
        # falling through the floor). In order to fix this, we need to ignore one of
        # these collisions. Since the NPC should react to the Player, and not vice-versa,
        # I'll ignore the Player-->NPC collision. To do this, we need to set Player's into
        # collide mask to exclude NPC's from collide mask. Let's hope this doesn't break
        # anything.
        npcCollisionNP = self.__room1NPC.find("* collision node")
        npcCollisionNP.node().setIntoCollideMask(npcCollisionNP.node().getIntoCollideMask() & 
                                                ~playerCollisionNP.node().getIntoCollideMask())
        
##        modelStanding = "models/bunny/bunny"
##        modelRunning = "models/bunny/bunny"
##        modelWalking = "models/bunny/bunny"
        self.__room2NPC = NPC(modelStanding,
                                {"run":modelRunning, "walk":modelWalking},
                                turnRate = 150, 
                                speed = 15,
                                agentList = self.__globalAgentList,
                                name = "Eve 2",#"das Osterhase",
                                collisionMask = BitMask32.bit(4),
                                rangeFinderCount = 13,
                                adjacencySensorThreshold = 5,
                                radarSlices = 5,
                                radarLength = 40,
                                scale = 1.0,
                                massKg = 35.0,
                                collisionHandler = self.physicsCollisionHandler,
                                collisionTraverser = self.cTrav,
                                waypoints = self.room2waypoints)
        self.__room2NPC.setPos(-20, -210, 10)
        self.__room2NPC.setPlayer(self.__mainAgent)
        self.__room2NPC.reparentTo(render)
        npcCollisionNP = self.__room2NPC.find("* collision node")
        npcCollisionNP.node().setIntoCollideMask(npcCollisionNP.node().getIntoCollideMask() & 
                                                ~playerCollisionNP.node().getIntoCollideMask())

        self.__room3NPC = NPC(modelStanding, 
                                {"run":modelRunning, "walk":modelWalking},
                                turnRate = 150, 
                                speed = 15,
                                agentList = self.__globalAgentList,
                                name = "Eve 3",#"der Hoppelhaschen",
                                collisionMask = BitMask32.bit(5),
                                rangeFinderCount = 13,
                                adjacencySensorThreshold = 5,
                                radarSlices = 5,
                                radarLength = 40,
                                scale = 1.0,
                                massKg = 35.0,
                                collisionHandler = self.physicsCollisionHandler,
                                collisionTraverser = self.cTrav,
                                waypoints = self.room3waypoints)
        self.__room3NPC.setPos(210, 0, 10)
        self.__room3NPC.setPlayer(self.__mainAgent)
        self.__room3NPC.reparentTo(render)
        npcCollisionNP = self.__room3NPC.find("* collision node")
        npcCollisionNP.node().setIntoCollideMask(npcCollisionNP.node().getIntoCollideMask() & 
                                                ~playerCollisionNP.node().getIntoCollideMask())
        
    def __setupRandomClutter(self):
##        self.ball1 = loader.loadModel("models/ball")
##        #self.ball1.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
##        self.ball1.findTexture("hedge.jpg")
##        self.ball1.setTexScale(TextureStage.getDefault(), 0.1)
##        self.ball1.setPos(0,0,0)
##        self.ball1.reparentTo(render)
        pass
        

    
    def __setupTasks(self):
        """
        This function sets up all the tasks used in the world
        """
        taskMgr.add(taskTimer, "taskTimer")
        
        #for index, ralph in enumerate(self.__otherRalphs):


##            taskMgr.add(ralph.sense, "sense" + str(index))
##            taskMgr.add(ralph.think, "think" + str(index))
##            taskMgr.add(ralph.act,   "act"   + str(index))
            #taskMgr.add(ralph.wanderTask, "wander" + str(index))
##            taskMgr.add(ralph.seekTask, "seekTask" + str(index), extraArgs = [self.__agentToTargetMap[ralph]], appendTask = True)
            
        taskMgr.add(self.__printPositionAndHeading, "__printPositionAndHeading")
        
##        listOfTargets = [(target.getX(), target.getY()) for target in self.__targets]
##        agentList = [(ralph.getX(), ralph.getY()) for ralph in self.__otherRalphs]
##        taskMgr.add(self.neatEvaluateTask, "self.neatEvaluateTask", extraArgs = [listOfTargets, self.__otherRalphs], appendTask = True)
        
        self.__mainAgent.setKeymap()
        taskMgr.add(self.__mainAgent.processKey, "processKeyTask")

          #  taskMgr.add(self.__mainAgent.handleCollisionTask, "handleCollisionTask")
##        taskMgr.add(self.ralph.wanderTask, "wander")
        
        taskMgr.add(self.__room1NPC.sense, "senseTask")
        taskMgr.add(self.__room2NPC.sense, "senseTask")
        taskMgr.add(self.__room3NPC.sense, "senseTask")
##        taskMgr.add(self.ralph.think, "thinkTask")
        taskMgr.add(self.__room1NPC.act, "actTask")
        taskMgr.add(self.__room2NPC.act, "actTask")
        taskMgr.add(self.__room3NPC.act, "actTask")
        taskMgr.add(self.checkGameState, "gameStateTask")
        taskMgr.add(self.animateItems, "animateItemsTask")
        #taskMgr.add(self.processKey, "processKeyTask")

        # This is for path finding
        #taskMgr.add(self.__room1NPC.followPath, "followPathTask", extraArgs = [self.bestPath], appendTask = True)

    def __setupCamera(self):
        #This camera position shows the whole level
        base.camera.setPos(100,-100, 795) #This is debug camera position.
        base.camera.lookAt(100,-100,0)
        #This camera position shows room1
        #base.camera.setPos(0,0, 375) #This is debug camera position.
        #base.camera.lookAt(0,0,0)
        #This camera position shows room2
        #base.camera.setPos(0,-200, 375) #This is debug camera position.
        #base.camera.lookAt(0,-200,0)    
        #This camera position shows room3
        #base.camera.setPos(200,0, 375) #This is debug camera position.
        #base.camera.lookAt(200,0,0)    
        #base.oobeCull()
        #base.oobe()
        base.disableMouse()
        base.camera.reparentTo(self.__mainAgent.actor)
        base.camera.setPos(0, 60, 60)
        base.camera.lookAt(self.__mainAgent)
        base.camera.setP(base.camera.getP() + 10)
    
    def cameraRoom1Pos(self):
        base.camera.reparentTo(render)
        #This camera position shows room1
        base.camera.setPos(0,0, 375) #This is debug camera position.
        base.camera.lookAt(0,0,0)        
        
    def cameraRoom2Pos(self):
        base.camera.reparentTo(render)
        #This camera position shows room2
        base.camera.setPos(0,-200, 375) #This is debug camera position.
        base.camera.lookAt(0,-200,0)    
        
    def cameraRoom3Pos(self):
        base.camera.reparentTo(render)
        #This camera position shows room3
        base.camera.setPos(200,0, 375) #This is debug camera position.
        base.camera.lookAt(200,0,0)
        
    def cameraRegularPos(self):        
        base.camera.reparentTo(self.__mainAgent.actor)
        base.camera.setPos(0, 60, 60)
        base.camera.lookAt(self.__mainAgent)
        base.camera.setP(base.camera.getP() + 10)
        
    positionHeadingText = OnscreenText(text="", style=1, fg=(1,1,1,1),
                   pos=(-1.3,-0.95), align=TextNode.ALeft, scale = .05, mayChange = True)
                

    def __printPositionAndHeading(self, task):
        heading = self.__mainAgent.getH()
        heading %= 360.0
            
##        self.positionHeadingText.setText("Position: (" + 
##            str(self.__mainAgent.getX()) + ", " + 
##            str(self.__mainAgent.getY()) + ", " +
##            str(self.__mainAgent.getZ()) + ") at heading " + 
##            str(heading))
##        return Task.cont

    # Every generation, throw out the old brains and put in the new ones. At
    # this point we can start all over with new nodes.
    generationCount = 0
    generationLifetimeTicks = 500
    neatEvaluateTaskCallCount = 0
##    neuralNetwork = NeuralNetwork()
    def neatEvaluateTask(self, listOfTargets, agentList, task):
        self.neatEvaluateTaskCallCount += 1
        if self.generationLifetimeTicks == self.neatEvaluateTaskCallCount:
            self.neatEvaluateTaskCallCount = 0
            oldBrains = [agent.brain for agent in agentList]
            self.generationCount += 1
            listOfPositions = [(agent.getX(), agent.getY()) for agent in agentList]
            newBrains = self.neuralNetwork.nextGeneration(oldBrains, listOfTargets, listOfPositions)
            
            for agent, brain in zip(agentList, newBrains):
                agent.brain = brain
                agent.setPos(self.startingPositions[agent])

        return Task.cont
    
    __keyMap = {"enablePathSmoothening":False,
        "showWaypoints":False}

    def setKeymap(self):
        def toggleWaypoints(key):
            self.showWaypoints = not self.showWaypoints
            if(self.showWaypoints):
                print("Showing waypoints")
                for w in self.room1waypoints:
                    w.draw()
                for w in self.room2waypoints:
                    w.draw()
                for w in self.room3waypoints:
                    w.draw()
            else:
                print("Hiding waypoints")
                for w in self.room1waypoints:
                    w.erase()
                for w in self.room2waypoints:
                    w.erase()
                for w in self.room3waypoints:
                    w.erase()
        
        def togglePathSmoothening(key):
            self.__room1NPC.togglePathSmoothening()
            self.__room2NPC.togglePathSmoothening()
            self.__room3NPC.togglePathSmoothening()
            
        def toggleCollisions(key):
            if(self.showCollisions):
                base.cTrav.showCollisions(render)
            else:
                base.cTrav.hideCollisions()

            self.showCollisions = not self.showCollisions
            print("showCollisions = " + str(self.showCollisions))
            
        self.accept("p",              togglePathSmoothening, ["togglePathSmoothening"])
        self.accept("w",              toggleWaypoints, ["toggleWaypoints"])
        self.accept("c",              toggleCollisions, ["toggleCollisions"])
        self.accept("1", self.cameraRoom1Pos)
        self.accept("2", self.cameraRoom2Pos)
        self.accept("3", self.cameraRoom3Pos)
        self.accept("4", self.cameraRegularPos)
class World(DirectObject):     
    def __init__(self):
        DirectObject.__init__(self)
        
        self.pathSmoothening = False
        self.showWaypoints = True
        self.showCollisions = False
        
        self.accept("escape", sys.exit)
        
        self.__setupEnvironment()
        self.__setupCollisions()
        self.__setupGravity()
        self.__setupLevel()
        self.__setupTarget()
        self.__setupNPC()
        self.__setupCamera()
        self.__setupTasks()
        
        self.setKeymap()
        self.__NPC.pathSmoothening = self.pathSmoothening

        if(self.showWaypoints):
            print("Showing waypoints")
            for w in self.roomWaypoints:
                w.draw()
        

    def __setupCollisions(self):
        self.cTrav = CollisionTraverser("traverser")
        base.cTrav = self.cTrav
        
        self.physicsCollisionHandler = PhysicsCollisionHandler()
        self.physicsCollisionHandler.setDynamicFrictionCoef(0.5)
        self.physicsCollisionHandler.setStaticFrictionCoef(0.7)

    def __setupGravity(self):
        base.particlesEnabled = True
        base.enableParticles()
        
        gravityFN=ForceNode('world-forces')
        gravityFNP=render.attachNewNode(gravityFN)
        gravityForce=LinearVectorForce(0,0,-6) #gravity acceleration ft/s^2
        gravityFN.addForce(gravityForce)

        base.physicsMgr.addLinearForce(gravityForce)

    def __setupEnvironment(self):
        cm = CardMaker("ground")
	size = 100
        cm.setFrame(-size, size, -size, size)
        environment = render.attachNewNode(cm.generate())
        environment.lookAt(0, 0, -1)
        environment.setPos(0, 0, 0)
        environment.setCollideMask(BitMask32.allOn())
        environment.reparentTo(render)
        
        texture = loader.loadTexture("textures/ground.png")
        
        # This is so the textures can look better from a distance
        texture.setMinfilter(Texture.FTLinearMipmapLinear)
        
        environment.setTexGen(TextureStage.getDefault(), TexGenAttrib.MWorldPosition) 
        environment.setTexScale(TextureStage.getDefault(), 0.02, 0.02)
        environment.setTexture(texture, 1)

            
    def __setupLevel(self):
        """
        Originally planned to have multiple levels, that never happened.
        """
        level1 = render.attachNewNode("level 1 node path")
        
        execfile("rooms/room.py")

        self.room = loader.loadModel("rooms/room")
        self.room.findTexture("*").setMinfilter(Texture.FTLinearMipmapLinear)
        self.room.setScale(10,10,5)
        self.room.setTexScale(TextureStage.getDefault(), 10)
        self.room.reparentTo(render)
        self.room.find("**/Cube;+h").setTag("Room", "1")
        
        gate = loader.loadModel("models/box")
        
        gateTo2 = self.room.attachNewNode("gateTo2")
        gate.instanceTo(gateTo2)
        gateTo2.setPos(8, -10, 0)
        gateTo2.hide()
        
        self.physicsCollisionHandler.addInPattern("%fn-into-%in")
        self.physicsCollisionHandler.addOutPattern("%fn-out-%in")

        #messenger.toggleVerbose()
        self.gate = gate
        

    __globalAgentList = []
    __mainTarget = None
    def __setupTarget(self):
        modelStanding = "models/ralph"
        modelRunning = "models/ralph-run"
        modelWalking = "models/ralph-walk"
        self.__mainTarget = NPC(modelStanding, 
                            {"run":modelRunning, "walk":modelWalking},
                            turnRate = 150, 
                            speed = 0,
                            agentList = self.__globalAgentList,
                            collisionMask = BitMask32.bit(1),
                            name="target",
                            massKg = 35.0,
                            collisionHandler = self.physicsCollisionHandler,
                            collisionTraverser = self.cTrav)
        # Make it visible
        self.__mainTarget.reparentTo(render)
        self.__mainTarget.setPos(-20, -10, 0)#-210
        self.gate.find("**/Cube;+h").setCollideMask(~self.__mainTarget.collisionMask)
        
    __targetCount = 0
    __targets = []
    __agentToTargetMap = {}
    def __setupNPC(self):
        # This is to support the collisions for each node. See the paragraph comment
        # above where we modify the npc's collision node
#        playerCollisionNP = self.__mainTarget.find("* collision node")

        modelStanding = "models/ralph"
        modelRunning = "models/ralph-run"
        modelWalking = "models/ralph-walk"
        self.__NPC = NPC(modelStanding, 
                                {"run":modelRunning, "walk":modelWalking},
                                turnRate = 150, 
                                speed = 15,
                                agentList = self.__globalAgentList,
                                name = "Ralph",
                                collisionMask = BitMask32.bit(3),
                                rangeFinderCount = 13,
                                adjacencySensorThreshold = 5,
                                radarSlices = 5,
                                radarLength = 0,
                                scale = 1.0,
                                massKg = 35.0,
                                collisionHandler = self.physicsCollisionHandler,
                                collisionTraverser = self.cTrav,
                                waypoints = self.roomWaypoints)
        self.__NPC.setFluidPos(render, 20, 10, 0)#-190
        self.__NPC.setScale(render, 1)
        self.__NPC.setTarget(self.__mainTarget)

        self.__NPC.reparentTo(render)
	self.__NPC.start()
    
    def __setupTasks(self):
        """
        This function sets up all the tasks used in the world
        """
        taskMgr.add(taskTimer, "taskTimer")
        taskMgr.add(self.__NPC.act, "actTask")

    def __setupCamera(self):
        #This camera position shows the whole level
        base.camera.setPos(100,-100, 795) #This is debug camera position.
        base.camera.lookAt(100,-100,0)
        base.disableMouse()
        base.camera.reparentTo(self.__NPC.actor)
        base.camera.setPos(0, 60, 200)
        base.camera.lookAt(self.__NPC)
        base.camera.setP(base.camera.getP() + 10)
    
    def cameraViewRoomPos(self):
        base.camera.reparentTo(render)
        #This camera position shows entire room at once
        base.camera.setPos(0,0, 300) #This is debug camera position.
        base.camera.lookAt(0,0,0)        

    def cameraRegularPos(self):        
        base.camera.reparentTo(self.__NPC.actor)
        base.camera.setPos(0, 60, 200)
        base.camera.lookAt(self.__NPC)
        base.camera.setP(base.camera.getP() + 10)
        
    positionHeadingText = OnscreenText(text="", style=1, fg=(1,1,1,1),
                   pos=(-1.3,-0.95), align=TextNode.ALeft, scale = .05, mayChange = True)
                
    __keyMap = {"enablePathSmoothening":False,
        "showWaypoints":False}

    def setKeymap(self):
        def toggleWaypoints(key):
            self.showWaypoints = not self.showWaypoints
            if(self.showWaypoints):
                print("Showing waypoints")
                for w in self.roomWaypoints:
                    w.draw()
            else:
                print("Hiding waypoints")
                for w in self.roomWaypoints:
                    w.erase()
        
        def togglePathSmoothening(key):
            self.__NPC.togglePathSmoothening()
            
        def toggleCollisions(key):
            if(self.showCollisions):
                base.cTrav.showCollisions(render)
            else:
                base.cTrav.hideCollisions()

            self.showCollisions = not self.showCollisions
            print("showCollisions = " + str(self.showCollisions))
            
        self.accept("p",              togglePathSmoothening, ["togglePathSmoothening"])
        self.accept("w",              toggleWaypoints, ["toggleWaypoints"])
        self.accept("c",              toggleCollisions, ["toggleCollisions"])
        self.accept("1", self.cameraRegularPos)
        self.accept("2", self.cameraViewRoomPos)