class CogdoExecutiveSuiteIntro(CogdoGameMovie):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'CogdoExecutiveSuiteIntro')
    introDuration = 7
    cameraMoveDuration = 3

    def __init__(self, shopOwner):
        CogdoGameMovie.__init__(self)
        self._shopOwner = shopOwner
        self._lookAtCamTarget = False
        self._camTarget = None
        self._camHelperNode = None
        self._toonDialogueSfx = None
        self.toonHead = None
        self.frame = None
        return

    def displayLine(self, text):
        self.notify.debug('displayLine')
        self._dialogueLabel.node().setText(text)
        self.toonHead.reparentTo(aspect2d)
        self._toonDialogueSfx.play()
        self.toonHead.setClipPlane(self.clipPlane)

    def makeSuit(self, suitType):
        self.notify.debug('makeSuit()')
        suit = Suit.Suit()
        dna = SuitDNA.SuitDNA()
        dna.newSuit(suitType)
        suit.setStyle(dna)
        suit.isDisguised = 1
        suit.generateSuit()
        suit.setScale(1, 1, 2)
        suit.setPos(0, 0, -4.4)
        suit.reparentTo(self.toonHead)
        for part in suit.getHeadParts():
            part.hide()

    def load(self):
        self.notify.debug('load()')
        CogdoGameMovie.load(self)
        backgroundGui = loader.loadModel(
            'phase_5/models/cogdominium/tt_m_gui_csa_flyThru')
        self.bg = backgroundGui.find('**/background')
        self.chatBubble = backgroundGui.find('**/chatBubble')
        self.chatBubble.setScale(6.5, 6.5, 7.3)
        self.chatBubble.setPos(0.32, 0, -0.78)
        self.bg.setScale(5.2)
        self.bg.setPos(0.14, 0, -0.6667)
        self.bg.reparentTo(aspect2d)
        self.chatBubble.reparentTo(aspect2d)
        self.frame = DirectFrame(geom=self.bg,
                                 relief=None,
                                 pos=(0.2, 0, -0.6667))
        self.bg.wrtReparentTo(self.frame)
        self.gameTitleText = DirectLabel(
            parent=self.frame,
            text=TTLocalizer.CogdoExecutiveSuiteTitle,
            scale=TTLocalizer.MRPgameTitleText * 0.8,
            text_align=TextNode.ACenter,
            text_font=getSignFont(),
            text_fg=(1.0, 0.33, 0.33, 1.0),
            pos=TTLocalizer.MRgameTitleTextPos,
            relief=None)
        self.chatBubble.wrtReparentTo(self.frame)
        self.frame.hide()
        backgroundGui.removeNode()
        self.toonDNA = ToonDNA.ToonDNA()
        self.toonDNA.newToonFromProperties('dss', 'ss', 'm', 'm', 2, 0, 2, 2,
                                           1, 8, 1, 8, 1, 14)
        self.toonHead = Toon.Toon()
        self.toonHead.setDNA(self.toonDNA)
        self.makeSuit('sc')
        self.toonHead.getGeomNode().setDepthWrite(1)
        self.toonHead.getGeomNode().setDepthTest(1)
        self.toonHead.loop('neutral')
        self.toonHead.setPosHprScale(-0.73, 0, -1.27, 180, 0, 0, 0.18, 0.18,
                                     0.18)
        self.toonHead.reparentTo(hidden)
        self.toonHead.startBlink()
        self.clipPlane = self.toonHead.attachNewNode(PlaneNode('clip'))
        self.clipPlane.node().setPlane(Plane(0, 0, 1, 0))
        self.clipPlane.setPos(0, 0, 2.45)
        self._toonDialogueSfx = loader.loadSfx(
            'phase_3.5/audio/dial/AV_dog_long.ogg')
        self._camHelperNode = NodePath('CamHelperNode')
        self._camHelperNode.reparentTo(render)
        dialogue = TTLocalizer.CogdoExecutiveSuiteIntroMessage

        def start():
            self.frame.show()
            base.setCellsAvailable(
                base.bottomCells + base.leftCells + base.rightCells, 0)

        def showShopOwner():
            self._setCamTarget(self._shopOwner, -10, offset=Point3(0, 0, 5))

        def end():
            self._dialogueLabel.reparentTo(hidden)
            self.toonHead.reparentTo(hidden)
            self.frame.hide()
            base.setCellsAvailable(
                base.bottomCells + base.leftCells + base.rightCells, 1)
            self._stopUpdateTask()

        self._ival = Sequence(
            Func(start), Func(self.displayLine, dialogue), Func(showShopOwner),
            ParallelEndTogether(
                camera.posInterval(self.cameraMoveDuration,
                                   Point3(8, 0, 13),
                                   blendType='easeInOut'),
                camera.hprInterval(0.5,
                                   self._camHelperNode.getHpr(),
                                   blendType='easeInOut')),
            Wait(self.introDuration), Func(end))
        self._startUpdateTask()
        return

    def _setCamTarget(self,
                      targetNP,
                      distance,
                      offset=Point3(0, 0, 0),
                      angle=Point3(0, 0, 0)):
        camera.wrtReparentTo(render)
        self._camTarget = targetNP
        self._camOffset = offset
        self._camAngle = angle
        self._camDistance = distance
        self._camHelperNode.setPos(self._camTarget, self._camOffset)
        self._camHelperNode.setHpr(self._camTarget, 180 + self._camAngle[0],
                                   self._camAngle[1], self._camAngle[2])
        self._camHelperNode.setPos(self._camHelperNode, 0, self._camDistance,
                                   0)

    def _updateTask(self, task):
        dt = globalClock.getDt()
        return task.cont

    def unload(self):
        self._shopOwner = None
        self._camTarget = None
        if hasattr(self, '_camHelperNode') and self._camHelperNode:
            self._camHelperNode.removeNode()
            del self._camHelperNode
        self.frame.destroy()
        del self.frame
        self.bg.removeNode()
        del self.bg
        self.chatBubble.removeNode()
        del self.chatBubble
        self.toonHead.stopBlink()
        self.toonHead.stop()
        self.toonHead.removeNode()
        self.toonHead.delete()
        del self.toonHead
        CogdoGameMovie.unload(self)
        return
class DistributedButterfly(DistributedObject.DistributedObject):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'DistributedButterfly')
    id = 0
    wingTypes = ('wings_1', 'wings_2', 'wings_3', 'wings_4', 'wings_5',
                 'wings_6')
    yellowColors = (Vec4(1, 1, 1, 1), Vec4(0.2, 0, 1, 1), Vec4(0.8, 0, 1, 1))
    whiteColors = (Vec4(0.8, 0, 0.8, 1), Vec4(0, 0.8, 0.8,
                                              1), Vec4(0.9, 0.4, 0.6, 1),
                   Vec4(0.9, 0.4, 0.4, 1), Vec4(0.8, 0.5, 0.9,
                                                1), Vec4(0.4, 0.1, 0.7, 1))
    paleYellowColors = (Vec4(0.8, 0, 0.8, 1), Vec4(0.6, 0.6, 0.9,
                                                   1), Vec4(0.7, 0.6, 0.9, 1),
                        Vec4(0.8, 0.6, 0.9, 1), Vec4(0.9, 0.6, 0.9,
                                                     1), Vec4(1, 0.6, 0.9, 1))
    shadowScaleBig = Point3(0.07, 0.07, 0.07)
    shadowScaleSmall = Point3(0.01, 0.01, 0.01)

    def __init__(self, cr):
        DistributedObject.DistributedObject.__init__(self, cr)
        self.fsm = ClassicFSM.ClassicFSM('DistributedButterfly', [
            State.State('off', self.enterOff, self.exitOff,
                        ['Flying', 'Landed']),
            State.State('Flying', self.enterFlying, self.exitFlying,
                        ['Landed']),
            State.State('Landed', self.enterLanded, self.exitLanded,
                        ['Flying'])
        ], 'off', 'off')
        self.butterfly = None
        self.butterflyNode = None
        self.curIndex = 0
        self.destIndex = 0
        self.time = 0.0
        self.ival = None
        self.fsm.enterInitialState()
        return

    def generate(self):
        DistributedObject.DistributedObject.generate(self)
        if self.butterfly:
            return
        self.butterfly = Actor.Actor()
        self.butterfly.loadModel('phase_4/models/props/SZ_butterfly-mod')
        self.butterfly.loadAnims({
            'flutter':
            'phase_4/models/props/SZ_butterfly-flutter',
            'glide':
            'phase_4/models/props/SZ_butterfly-glide',
            'land':
            'phase_4/models/props/SZ_butterfly-land'
        })
        index = self.doId % len(self.wingTypes)
        chosenType = self.wingTypes[index]
        node = self.butterfly.getGeomNode()
        for type in self.wingTypes:
            wing = node.find('**/' + type)
            if type != chosenType:
                wing.removeNode()
            else:
                if index == 0 or index == 1:
                    color = self.yellowColors[self.doId %
                                              len(self.yellowColors)]
                elif index == 2 or index == 3:
                    color = self.whiteColors[self.doId % len(self.whiteColors)]
                elif index == 4:
                    color = self.paleYellowColors[self.doId %
                                                  len(self.paleYellowColors)]
                else:
                    color = Vec4(1, 1, 1, 1)
                wing.setColor(color)

        self.butterfly2 = Actor.Actor(other=self.butterfly)
        self.butterfly.enableBlend(blendType=PartBundle.BTLinear)
        self.butterfly.loop('flutter')
        self.butterfly.loop('land')
        self.butterfly.loop('glide')
        rng = RandomNumGen.RandomNumGen(self.doId)
        playRate = 0.6 + 0.8 * rng.random()
        self.butterfly.setPlayRate(playRate, 'flutter')
        self.butterfly.setPlayRate(playRate, 'land')
        self.butterfly.setPlayRate(playRate, 'glide')
        self.butterfly2.setPlayRate(playRate, 'flutter')
        self.butterfly2.setPlayRate(playRate, 'land')
        self.butterfly2.setPlayRate(playRate, 'glide')
        self.glideWeight = rng.random() * 2
        lodNode = LODNode('butterfly-node')
        lodNode.addSwitch(100, 40)
        lodNode.addSwitch(40, 0)
        self.butterflyNode = NodePath(lodNode)
        self.butterfly2.setH(180.0)
        self.butterfly2.reparentTo(self.butterflyNode)
        self.butterfly.setH(180.0)
        self.butterfly.reparentTo(self.butterflyNode)
        self.__initCollisions()
        self.dropShadow = loader.loadModel('phase_3/models/props/drop_shadow')
        self.dropShadow.setColor(0, 0, 0, 0.3)
        self.dropShadow.setPos(0, 0.1, -0.05)
        self.dropShadow.setScale(self.shadowScaleBig)
        self.dropShadow.reparentTo(self.butterfly)

    def disable(self):
        self.butterflyNode.reparentTo(hidden)
        if self.ival != None:
            self.ival.finish()
        self.__ignoreAvatars()
        DistributedObject.DistributedObject.disable(self)
        return

    def delete(self):
        self.butterfly.cleanup()
        self.butterfly = None
        self.butterfly2.cleanup()
        self.butterfly2 = None
        self.butterflyNode.removeNode()
        self.__deleteCollisions()
        self.ival = None
        del self.fsm
        DistributedObject.DistributedObject.delete(self)
        return

    def uniqueButterflyName(self, name):
        DistributedButterfly.id += 1
        return name + '-%d' % DistributedButterfly.id

    def __detectAvatars(self):
        self.accept('enter' + self.cSphereNode.getName(),
                    self.__handleCollisionSphereEnter)

    def __ignoreAvatars(self):
        self.ignore('enter' + self.cSphereNode.getName())

    def __initCollisions(self):
        self.cSphere = CollisionSphere(0.0, 1.0, 0.0, 3.0)
        self.cSphere.setTangible(0)
        self.cSphereNode = CollisionNode(
            self.uniqueButterflyName('cSphereNode'))
        self.cSphereNode.addSolid(self.cSphere)
        self.cSphereNodePath = self.butterflyNode.attachNewNode(
            self.cSphereNode)
        self.cSphereNodePath.hide()
        self.cSphereNode.setCollideMask(ToontownGlobals.WallBitmask)

    def __deleteCollisions(self):
        del self.cSphere
        del self.cSphereNode
        self.cSphereNodePath.removeNode()
        del self.cSphereNodePath

    def __handleCollisionSphereEnter(self, collEntry):
        self.sendUpdate('avatarEnter', [])

    def setArea(self, playground, area):
        self.playground = playground
        self.area = area

    def setState(self, stateIndex, curIndex, destIndex, time, timestamp):
        self.curIndex = curIndex
        self.destIndex = destIndex
        self.time = time
        self.fsm.request(ButterflyGlobals.states[stateIndex],
                         [globalClockDelta.localElapsedTime(timestamp)])

    def enterOff(self, ts=0.0):
        if self.butterflyNode != None:
            self.butterflyNode.reparentTo(hidden)
        return

    def exitOff(self):
        if self.butterflyNode != None:
            self.butterflyNode.reparentTo(render)
        return

    def enterFlying(self, ts):
        self.__detectAvatars()
        curPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][
            self.curIndex]
        destPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][
            self.destIndex]
        flyHeight = max(
            curPos[2],
            destPos[2]) + ButterflyGlobals.BUTTERFLY_HEIGHT[self.playground]
        curPosHigh = Point3(curPos[0], curPos[1], flyHeight)
        destPosHigh = Point3(destPos[0], destPos[1], flyHeight)
        if ts <= self.time:
            flyTime = self.time - (
                ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground] +
                ButterflyGlobals.BUTTERFLY_LANDING[self.playground])
            self.butterflyNode.setPos(curPos)
            self.dropShadow.show()
            self.dropShadow.setScale(self.shadowScaleBig)
            oldHpr = self.butterflyNode.getHpr()
            self.butterflyNode.headsUp(destPos)
            newHpr = self.butterflyNode.getHpr()
            self.butterflyNode.setHpr(oldHpr)
            takeoffShadowT = 0.2 * ButterflyGlobals.BUTTERFLY_TAKEOFF[
                self.playground]
            landShadowT = 0.2 * ButterflyGlobals.BUTTERFLY_LANDING[
                self.playground]
            self.butterfly2.loop('flutter')
            self.ival = Sequence(
                Parallel(
                    LerpPosHprInterval(
                        self.butterflyNode,
                        ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground],
                        curPosHigh, newHpr),
                    LerpAnimInterval(
                        self.butterfly,
                        ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground],
                        'land', 'flutter'),
                    LerpAnimInterval(
                        self.butterfly,
                        ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground],
                        None,
                        'glide',
                        startWeight=0,
                        endWeight=self.glideWeight),
                    Sequence(
                        LerpScaleInterval(self.dropShadow,
                                          takeoffShadowT,
                                          self.shadowScaleSmall,
                                          startScale=self.shadowScaleBig),
                        HideInterval(self.dropShadow))),
                LerpPosInterval(self.butterflyNode, flyTime, destPosHigh),
                Parallel(
                    LerpPosInterval(
                        self.butterflyNode,
                        ButterflyGlobals.BUTTERFLY_LANDING[self.playground],
                        destPos),
                    LerpAnimInterval(
                        self.butterfly,
                        ButterflyGlobals.BUTTERFLY_LANDING[self.playground],
                        'flutter', 'land'),
                    LerpAnimInterval(
                        self.butterfly,
                        ButterflyGlobals.BUTTERFLY_LANDING[self.playground],
                        None,
                        'glide',
                        startWeight=self.glideWeight,
                        endWeight=0),
                    Sequence(
                        Wait(ButterflyGlobals.BUTTERFLY_LANDING[
                            self.playground] - landShadowT),
                        ShowInterval(self.dropShadow),
                        LerpScaleInterval(self.dropShadow,
                                          landShadowT,
                                          self.shadowScaleBig,
                                          startScale=self.shadowScaleSmall))),
                name=self.uniqueName('Butterfly'))
            self.ival.start(ts)
        else:
            self.ival = None
            self.butterflyNode.setPos(destPos)
            self.butterfly.setControlEffect('land', 1.0)
            self.butterfly.setControlEffect('flutter', 0.0)
            self.butterfly.setControlEffect('glide', 0.0)
            self.butterfly2.loop('land')
        return

    def exitFlying(self):
        self.__ignoreAvatars()
        if self.ival != None:
            self.ival.finish()
            self.ival = None
        return

    def enterLanded(self, ts):
        self.__detectAvatars()
        curPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][
            self.curIndex]
        self.butterflyNode.setPos(curPos)
        self.dropShadow.show()
        self.dropShadow.setScale(self.shadowScaleBig)
        self.butterfly.setControlEffect('land', 1.0)
        self.butterfly.setControlEffect('flutter', 0.0)
        self.butterfly.setControlEffect('glide', 0.0)
        self.butterfly2.pose(
            'land', random.randrange(self.butterfly2.getNumFrames('land')))
        return None

    def exitLanded(self):
        self.__ignoreAvatars()
        return None
class DistributedButterfly(DistributedObject.DistributedObject):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedButterfly')
    id = 0
    wingTypes = ('wings_1', 'wings_2', 'wings_3', 'wings_4', 'wings_5', 'wings_6')
    yellowColors = (Vec4(1, 1, 1, 1), Vec4(0.2, 0, 1, 1), Vec4(0.8, 0, 1, 1))
    whiteColors = (Vec4(0.8, 0, 0.8, 1),
     Vec4(0, 0.8, 0.8, 1),
     Vec4(0.9, 0.4, 0.6, 1),
     Vec4(0.9, 0.4, 0.4, 1),
     Vec4(0.8, 0.5, 0.9, 1),
     Vec4(0.4, 0.1, 0.7, 1))
    paleYellowColors = (Vec4(0.8, 0, 0.8, 1),
     Vec4(0.6, 0.6, 0.9, 1),
     Vec4(0.7, 0.6, 0.9, 1),
     Vec4(0.8, 0.6, 0.9, 1),
     Vec4(0.9, 0.6, 0.9, 1),
     Vec4(1, 0.6, 0.9, 1))
    shadowScaleBig = Point3(0.07, 0.07, 0.07)
    shadowScaleSmall = Point3(0.01, 0.01, 0.01)

    def __init__(self, cr):
        DistributedObject.DistributedObject.__init__(self, cr)
        self.fsm = ClassicFSM.ClassicFSM('DistributedButterfly', [State.State('off', self.enterOff, self.exitOff, ['Flying', 'Landed']), State.State('Flying', self.enterFlying, self.exitFlying, ['Landed']), State.State('Landed', self.enterLanded, self.exitLanded, ['Flying'])], 'off', 'off')
        self.butterfly = None
        self.butterflyNode = None
        self.curIndex = 0
        self.destIndex = 0
        self.time = 0.0
        self.ival = None
        self.fsm.enterInitialState()
        return

    def generate(self):
        DistributedObject.DistributedObject.generate(self)
        if self.butterfly:
            return
        self.butterfly = Actor.Actor()
        self.butterfly.loadModel('phase_4/models/props/SZ_butterfly-mod')
        self.butterfly.loadAnims({'flutter': 'phase_4/models/props/SZ_butterfly-flutter',
         'glide': 'phase_4/models/props/SZ_butterfly-glide',
         'land': 'phase_4/models/props/SZ_butterfly-land'})
        index = self.doId % len(self.wingTypes)
        chosenType = self.wingTypes[index]
        node = self.butterfly.getGeomNode()
        for type in self.wingTypes:
            wing = node.find('**/' + type)
            if type != chosenType:
                wing.removeNode()
            else:
                if index == 0 or index == 1:
                    color = self.yellowColors[self.doId % len(self.yellowColors)]
                elif index == 2 or index == 3:
                    color = self.whiteColors[self.doId % len(self.whiteColors)]
                elif index == 4:
                    color = self.paleYellowColors[self.doId % len(self.paleYellowColors)]
                else:
                    color = Vec4(1, 1, 1, 1)
                wing.setColor(color)

        self.butterfly2 = Actor.Actor(other=self.butterfly)
        self.butterfly.enableBlend(blendType=PartBundle.BTLinear)
        self.butterfly.loop('flutter')
        self.butterfly.loop('land')
        self.butterfly.loop('glide')
        rng = RandomNumGen.RandomNumGen(self.doId)
        playRate = 0.6 + 0.8 * rng.random()
        self.butterfly.setPlayRate(playRate, 'flutter')
        self.butterfly.setPlayRate(playRate, 'land')
        self.butterfly.setPlayRate(playRate, 'glide')
        self.butterfly2.setPlayRate(playRate, 'flutter')
        self.butterfly2.setPlayRate(playRate, 'land')
        self.butterfly2.setPlayRate(playRate, 'glide')
        self.glideWeight = rng.random() * 2
        lodNode = LODNode('butterfly-node')
        lodNode.addSwitch(100, 40)
        lodNode.addSwitch(40, 0)
        self.butterflyNode = NodePath(lodNode)
        self.butterfly2.setH(180.0)
        self.butterfly2.reparentTo(self.butterflyNode)
        self.butterfly.setH(180.0)
        self.butterfly.reparentTo(self.butterflyNode)
        self.__initCollisions()
        self.dropShadow = loader.loadModel('phase_3/models/props/drop_shadow')
        self.dropShadow.setColor(0, 0, 0, 0.3)
        self.dropShadow.setPos(0, 0.1, -0.05)
        self.dropShadow.setScale(self.shadowScaleBig)
        self.dropShadow.reparentTo(self.butterfly)

    def disable(self):
        self.butterflyNode.reparentTo(hidden)
        if self.ival != None:
            self.ival.finish()
        self.__ignoreAvatars()
        DistributedObject.DistributedObject.disable(self)
        return

    def delete(self):
        self.butterfly.cleanup()
        self.butterfly = None
        self.butterfly2.cleanup()
        self.butterfly2 = None
        self.butterflyNode.removeNode()
        self.__deleteCollisions()
        self.ival = None
        del self.fsm
        DistributedObject.DistributedObject.delete(self)
        return

    def uniqueButterflyName(self, name):
        DistributedButterfly.id += 1
        return name + '-%d' % DistributedButterfly.id

    def __detectAvatars(self):
        self.accept('enter' + self.cSphereNode.getName(), self.__handleCollisionSphereEnter)

    def __ignoreAvatars(self):
        self.ignore('enter' + self.cSphereNode.getName())

    def __initCollisions(self):
        self.cSphere = CollisionSphere(0.0, 1.0, 0.0, 3.0)
        self.cSphere.setTangible(0)
        self.cSphereNode = CollisionNode(self.uniqueButterflyName('cSphereNode'))
        self.cSphereNode.addSolid(self.cSphere)
        self.cSphereNodePath = self.butterflyNode.attachNewNode(self.cSphereNode)
        self.cSphereNodePath.hide()
        self.cSphereNode.setCollideMask(ToontownGlobals.WallBitmask)

    def __deleteCollisions(self):
        del self.cSphere
        del self.cSphereNode
        self.cSphereNodePath.removeNode()
        del self.cSphereNodePath

    def __handleCollisionSphereEnter(self, collEntry):
        self.sendUpdate('avatarEnter', [])

    def setArea(self, playground, area):
        self.playground = playground
        self.area = area

    def setState(self, stateIndex, curIndex, destIndex, time, timestamp):
        self.curIndex = curIndex
        self.destIndex = destIndex
        self.time = time
        self.fsm.request(ButterflyGlobals.states[stateIndex], [globalClockDelta.localElapsedTime(timestamp)])

    def enterOff(self, ts = 0.0):
        if self.butterflyNode != None:
            self.butterflyNode.reparentTo(hidden)
        return

    def exitOff(self):
        if self.butterflyNode != None:
            self.butterflyNode.reparentTo(render)
        return

    def enterFlying(self, ts):
        self.__detectAvatars()
        curPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][self.curIndex]
        destPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][self.destIndex]
        flyHeight = max(curPos[2], destPos[2]) + ButterflyGlobals.BUTTERFLY_HEIGHT[self.playground]
        curPosHigh = Point3(curPos[0], curPos[1], flyHeight)
        destPosHigh = Point3(destPos[0], destPos[1], flyHeight)
        if ts <= self.time:
            flyTime = self.time - (ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground] + ButterflyGlobals.BUTTERFLY_LANDING[self.playground])
            self.butterflyNode.setPos(curPos)
            self.dropShadow.show()
            self.dropShadow.setScale(self.shadowScaleBig)
            oldHpr = self.butterflyNode.getHpr()
            self.butterflyNode.headsUp(destPos)
            newHpr = self.butterflyNode.getHpr()
            self.butterflyNode.setHpr(oldHpr)
            takeoffShadowT = 0.2 * ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground]
            landShadowT = 0.2 * ButterflyGlobals.BUTTERFLY_LANDING[self.playground]
            self.butterfly2.loop('flutter')
            self.ival = Sequence(Parallel(LerpPosHprInterval(self.butterflyNode, ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground], curPosHigh, newHpr), LerpAnimInterval(self.butterfly, ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground], 'land', 'flutter'), LerpAnimInterval(self.butterfly, ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground], None, 'glide', startWeight=0, endWeight=self.glideWeight), Sequence(LerpScaleInterval(self.dropShadow, takeoffShadowT, self.shadowScaleSmall, startScale=self.shadowScaleBig), HideInterval(self.dropShadow))), LerpPosInterval(self.butterflyNode, flyTime, destPosHigh), Parallel(LerpPosInterval(self.butterflyNode, ButterflyGlobals.BUTTERFLY_LANDING[self.playground], destPos), LerpAnimInterval(self.butterfly, ButterflyGlobals.BUTTERFLY_LANDING[self.playground], 'flutter', 'land'), LerpAnimInterval(self.butterfly, ButterflyGlobals.BUTTERFLY_LANDING[self.playground], None, 'glide', startWeight=self.glideWeight, endWeight=0), Sequence(Wait(ButterflyGlobals.BUTTERFLY_LANDING[self.playground] - landShadowT), ShowInterval(self.dropShadow), LerpScaleInterval(self.dropShadow, landShadowT, self.shadowScaleBig, startScale=self.shadowScaleSmall))), name=self.uniqueName('Butterfly'))
            self.ival.start(ts)
        else:
            self.ival = None
            self.butterflyNode.setPos(destPos)
            self.butterfly.setControlEffect('land', 1.0)
            self.butterfly.setControlEffect('flutter', 0.0)
            self.butterfly.setControlEffect('glide', 0.0)
            self.butterfly2.loop('land')
        return

    def exitFlying(self):
        self.__ignoreAvatars()
        if self.ival != None:
            self.ival.finish()
            self.ival = None
        return

    def enterLanded(self, ts):
        self.__detectAvatars()
        curPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][self.curIndex]
        self.butterflyNode.setPos(curPos)
        self.dropShadow.show()
        self.dropShadow.setScale(self.shadowScaleBig)
        self.butterfly.setControlEffect('land', 1.0)
        self.butterfly.setControlEffect('flutter', 0.0)
        self.butterfly.setControlEffect('glide', 0.0)
        self.butterfly2.pose('land', random.randrange(self.butterfly2.getNumFrames('land')))
        return None

    def exitLanded(self):
        self.__ignoreAvatars()
        return None
class CogdoExecutiveSuiteIntro(CogdoGameMovie):
    notify = DirectNotifyGlobal.directNotify.newCategory('CogdoExecutiveSuiteIntro')
    introDuration = 7
    cameraMoveDuration = 3

    def __init__(self, shopOwner):
        CogdoGameMovie.__init__(self)
        self._shopOwner = shopOwner
        self._lookAtCamTarget = False
        self._camTarget = None
        self._camHelperNode = None
        self._toonDialogueSfx = None
        self.toonHead = None
        self.frame = None
        return

    def displayLine(self, text):
        self.notify.debug('displayLine')
        self._dialogueLabel.node().setText(text)
        self.toonHead.reparentTo(aspect2d)
        self._toonDialogueSfx.play()
        self.toonHead.setClipPlane(self.clipPlane)

    def makeSuit(self, suitType):
        self.notify.debug('makeSuit()')
        suit = Suit.Suit()
        dna = SuitDNA.SuitDNA()
        dna.newSuit(suitType)
        suit.setStyle(dna)
        suit.isDisguised = 1
        suit.generateSuit()
        suit.setScale(1.05, 1.05, 2.05)
        suit.setPos(0, 0, -4.4)
        suit.reparentTo(self.toonHead)
        for part in suit.getHeadParts():
            part.hide()

        suit.loop('neutral')

    def load(self):
        self.notify.debug('load()')
        CogdoGameMovie.load(self)
        backgroundGui = loader.loadModel('phase_5/models/cogdominium/tt_m_gui_csa_flyThru')
        self.bg = backgroundGui.find('**/background')
        self.chatBubble = backgroundGui.find('**/chatBubble')
        self.chatBubble.setScale(6.5, 6.5, 7.3)
        self.chatBubble.setPos(0.32, 0, -0.78)
        self.bg.setScale(5.2)
        self.bg.setPos(0.14, 0, -0.6667)
        self.bg.reparentTo(aspect2d)
        self.chatBubble.reparentTo(aspect2d)
        self.frame = DirectFrame(geom=self.bg, relief=None, pos=(0.2, 0, -0.6667))
        self.bg.wrtReparentTo(self.frame)
        self.gameTitleText = DirectLabel(parent=self.frame, text=TTLocalizer.CogdoExecutiveSuiteTitle, scale=TTLocalizer.MRPgameTitleText * 0.8, text_align=TextNode.ACenter, text_font=getSignFont(), text_fg=(1.0, 0.33, 0.33, 1.0), pos=TTLocalizer.MRgameTitleTextPos, relief=None)
        self.chatBubble.wrtReparentTo(self.frame)
        self.frame.hide()
        backgroundGui.removeNode()
        self.toonDNA = ToonDNA.ToonDNA()
        self.toonDNA.newToonFromProperties('dss', 'ss', 'm', 'm', 2, 0, 2, 2, 1, 8, 1, 8, 1, 14, 0)
        self.toonHead = Toon.Toon()
        self.toonHead.setDNA(self.toonDNA)
        self.makeSuit('sc')
        self.toonHead.getGeomNode().setDepthWrite(1)
        self.toonHead.getGeomNode().setDepthTest(1)
        self.toonHead.loop('neutral')
        self.toonHead.setPosHprScale(-0.73, 0, -1.27, 180, 0, 0, 0.18, 0.18, 0.18)
        self.toonHead.reparentTo(hidden)
        self.toonHead.startBlink()
        self.clipPlane = self.toonHead.attachNewNode(PlaneNode('clip'))
        self.clipPlane.node().setPlane(Plane(0, 0, 1, 0))
        self.clipPlane.setPos(0, 0, 2.45)
        self._toonDialogueSfx = loader.loadSfx('phase_3.5/audio/dial/AV_dog_long.ogg')
        self._camHelperNode = NodePath('CamHelperNode')
        self._camHelperNode.reparentTo(render)
        dialogue = TTLocalizer.CogdoExecutiveSuiteIntroMessage

        def start():
            self.frame.show()
            base.setCellsActive(base.bottomCells + base.leftCells + base.rightCells, 0)

        def showShopOwner():
            self._setCamTarget(self._shopOwner, -10, offset=Point3(0, 0, 5))

        def end():
            self._dialogueLabel.reparentTo(hidden)
            self.toonHead.reparentTo(hidden)
            self.frame.hide()
            base.setCellsActive(base.bottomCells + base.leftCells + base.rightCells, 1)
            self._stopUpdateTask()

        self._ival = Sequence(Func(start), Func(self.displayLine, dialogue), Func(showShopOwner), ParallelEndTogether(camera.posInterval(self.cameraMoveDuration, Point3(8, 0, 13), blendType='easeInOut'), camera.hprInterval(0.5, self._camHelperNode.getHpr(), blendType='easeInOut')), Wait(self.introDuration), Func(end))
        self._startUpdateTask()
        return

    def _setCamTarget(self, targetNP, distance, offset = Point3(0, 0, 0), angle = Point3(0, 0, 0)):
        camera.wrtReparentTo(render)
        self._camTarget = targetNP
        self._camOffset = offset
        self._camAngle = angle
        self._camDistance = distance
        self._camHelperNode.setPos(self._camTarget, self._camOffset)
        self._camHelperNode.setHpr(self._camTarget, 180 + self._camAngle[0], self._camAngle[1], self._camAngle[2])
        self._camHelperNode.setPos(self._camHelperNode, 0, self._camDistance, 0)

    def _updateTask(self, task):
        dt = globalClock.getDt()
        return task.cont

    def unload(self):
        self._shopOwner = None
        self._camTarget = None
        if hasattr(self, '_camHelperNode') and self._camHelperNode:
            self._camHelperNode.removeNode()
            del self._camHelperNode
        self.frame.destroy()
        del self.frame
        self.bg.removeNode()
        del self.bg
        self.chatBubble.removeNode()
        del self.chatBubble
        self.toonHead.stopBlink()
        self.toonHead.stop()
        self.toonHead.removeNode()
        self.toonHead.delete()
        del self.toonHead
        CogdoGameMovie.unload(self)
        return
class CogdoFlyingCameraManager:
    def __init__(self, cam, parent, player, level):
        self._toon = player.toon
        self._camera = cam
        self._parent = parent
        self._player = player
        self._level = level
        self._enabled = False

    def enable(self):
        if self._enabled:
            return
        self._toon.detachCamera()
        self._prevToonY = 0.0
        levelBounds = self._level.getBounds()
        l = Globals.Camera.LevelBoundsFactor
        self._bounds = (
            (levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]),
            (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]),
            (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]),
        )
        self._lookAtZ = self._toon.getHeight() + Globals.Camera.LookAtToonHeightOffset
        self._camParent = NodePath("CamParent")
        self._camParent.reparentTo(self._parent)
        self._camParent.setPos(self._toon, 0, 0, 0)
        self._camParent.setHpr(180, Globals.Camera.Angle, 0)
        self._camera.reparentTo(self._camParent)
        self._camera.setPos(0, Globals.Camera.Distance, 0)
        self._camera.lookAt(self._toon, 0, 0, self._lookAtZ)
        self._cameraLookAtNP = NodePath("CameraLookAt")
        self._cameraLookAtNP.reparentTo(self._camera.getParent())
        self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr())
        self._levelBounds = self._level.getBounds()
        self._enabled = True
        self._frozen = False
        self._initCollisions()

    def _initCollisions(self):
        self._camCollRay = CollisionRay()
        camCollNode = CollisionNode("CameraToonRay")
        camCollNode.addSolid(self._camCollRay)
        camCollNode.setFromCollideMask(
            OTPGlobals.WallBitmask
            | OTPGlobals.CameraBitmask
            | ToontownGlobals.FloorEventBitmask
            | ToontownGlobals.CeilingBitmask
        )
        camCollNode.setIntoCollideMask(0)
        self._camCollNP = self._camera.attachNewNode(camCollNode)
        self._camCollNP.show()
        self._collOffset = Vec3(0, 0, 0.5)
        self._collHandler = CollisionHandlerQueue()
        self._collTrav = CollisionTraverser()
        self._collTrav.addCollider(self._camCollNP, self._collHandler)
        self._betweenCamAndToon = {}
        self._transNP = NodePath("trans")
        self._transNP.reparentTo(render)
        self._transNP.setTransparency(True)
        self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon)
        self._transNP.setBin("fixed", 10000)

    def _destroyCollisions(self):
        self._collTrav.removeCollider(self._camCollNP)
        self._camCollNP.removeNode()
        del self._camCollNP
        del self._camCollRay
        del self._collHandler
        del self._collOffset
        del self._betweenCamAndToon
        self._transNP.removeNode()
        del self._transNP

    def freeze(self):
        self._frozen = True

    def unfreeze(self):
        self._frozen = False

    def disable(self):
        if not self._enabled:
            return
        self._destroyCollisions()
        self._camera.wrtReparentTo(render)
        self._cameraLookAtNP.removeNode()
        del self._cameraLookAtNP
        self._camParent.removeNode()
        del self._camParent
        del self._prevToonY
        del self._lookAtZ
        del self._bounds
        del self._frozen
        self._enabled = False

    def update(self, dt=0.0):
        self._updateCam(dt)
        self._updateCollisions()

    def _updateCam(self, dt):
        toonPos = self._toon.getPos()
        camPos = self._camParent.getPos()
        x = camPos[0]
        z = camPos[2]
        toonWorldX = self._toon.getX(render)
        maxX = Globals.Camera.MaxSpinX
        toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX)
        spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (maxX * maxX)
        newH = 180.0 + spinAngle
        self._camParent.setH(newH)
        spinAngle = spinAngle * (pi / 180.0)
        distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle)
        distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle)
        d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0])
        if abs(d) > Globals.Camera.LeewayX:
            if d > Globals.Camera.LeewayX:
                x = toonPos[0] + Globals.Camera.LeewayX
            else:
                x = toonPos[0] - Globals.Camera.LeewayX
        x = self._toon.getX(render) + distToRightOfToon
        boundToonZ = min(toonPos[2], self._bounds[2][1])
        d = z - boundToonZ
        if d > Globals.Camera.MinLeewayZ:
            if self._player.velocity[2] >= 0 and toonPos[1] != self._prevToonY or self._player.velocity[2] > 0:
                z = boundToonZ + d * INVERSE_E ** (dt * Globals.Camera.CatchUpRateZ)
            elif d > Globals.Camera.MaxLeewayZ:
                z = boundToonZ + Globals.Camera.MaxLeewayZ
        elif d < -Globals.Camera.MinLeewayZ:
            z = boundToonZ - Globals.Camera.MinLeewayZ
        if self._frozen:
            y = camPos[1]
        else:
            y = self._toon.getY(render) - distBehindToon
        self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z))
        if toonPos[2] < self._bounds[2][1]:
            h = self._cameraLookAtNP.getH()
            if d >= Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ)
            elif d <= -Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ)
            self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0)
            self._camera.setHpr(smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr()))
        self._prevToonY = toonPos[1]

    def _updateCollisions(self):
        pos = self._toon.getPos(self._camera) + self._collOffset
        self._camCollRay.setOrigin(pos)
        direction = -Vec3(pos)
        direction.normalize()
        self._camCollRay.setDirection(direction)
        self._collTrav.traverse(render)
        nodesInBetween = {}
        if self._collHandler.getNumEntries() > 0:
            self._collHandler.sortEntries()
            for entry in self._collHandler.getEntries():
                name = entry.getIntoNode().getName()
                if name.find("col_") >= 0:
                    np = entry.getIntoNodePath().getParent()
                    if not nodesInBetween.has_key(np):
                        nodesInBetween[np] = np.getParent()

        for np in nodesInBetween.keys():
            if self._betweenCamAndToon.has_key(np):
                del self._betweenCamAndToon[np]
            else:
                np.setTransparency(True)
                np.wrtReparentTo(self._transNP)
                if np.getName().find("lightFixture") >= 0:
                    if not np.find("**/*floor_mesh").isEmpty():
                        np.find("**/*floor_mesh").hide()
                elif np.getName().find("platform") >= 0:
                    if not np.find("**/*Floor").isEmpty():
                        np.find("**/*Floor").hide()

        for np, parent in self._betweenCamAndToon.items():
            np.wrtReparentTo(parent)
            np.setTransparency(False)
            if np.getName().find("lightFixture") >= 0:
                if not np.find("**/*floor_mesh").isEmpty():
                    np.find("**/*floor_mesh").show()
            elif np.getName().find("platform") >= 0:
                if not np.find("**/*Floor").isEmpty():
                    np.find("**/*Floor").show()

        self._betweenCamAndToon = nodesInBetween
Beispiel #6
0
class CogdoFlyingCameraManager:
    def __init__(self, cam, parent, player, level):
        self._toon = player.toon
        self._camera = cam
        self._parent = parent
        self._player = player
        self._level = level
        self._enabled = False

    def enable(self):
        if self._enabled:
            return
        self._toon.detachCamera()
        self._prevToonY = 0.0
        levelBounds = self._level.getBounds()
        l = Globals.Camera.LevelBoundsFactor
        self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]),
                        (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]),
                        (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2]))
        self._lookAtZ = self._toon.getHeight(
        ) + Globals.Camera.LookAtToonHeightOffset
        self._camParent = NodePath('CamParent')
        self._camParent.reparentTo(self._parent)
        self._camParent.setPos(self._toon, 0, 0, 0)
        self._camParent.setHpr(180, Globals.Camera.Angle, 0)
        self._camera.reparentTo(self._camParent)
        self._camera.setPos(0, Globals.Camera.Distance, 0)
        self._camera.lookAt(self._toon, 0, 0, self._lookAtZ)
        self._cameraLookAtNP = NodePath('CameraLookAt')
        self._cameraLookAtNP.reparentTo(self._camera.getParent())
        self._cameraLookAtNP.setPosHpr(self._camera.getPos(),
                                       self._camera.getHpr())
        self._levelBounds = self._level.getBounds()
        self._enabled = True
        self._frozen = False
        self._initCollisions()

    def _initCollisions(self):
        self._camCollRay = CollisionRay()
        camCollNode = CollisionNode('CameraToonRay')
        camCollNode.addSolid(self._camCollRay)
        camCollNode.setFromCollideMask(OTPGlobals.WallBitmask
                                       | OTPGlobals.CameraBitmask
                                       | ToontownGlobals.FloorEventBitmask
                                       | ToontownGlobals.CeilingBitmask)
        camCollNode.setIntoCollideMask(0)
        self._camCollNP = self._camera.attachNewNode(camCollNode)
        self._camCollNP.show()
        self._collOffset = Vec3(0, 0, 0.5)
        self._collHandler = CollisionHandlerQueue()
        self._collTrav = CollisionTraverser()
        self._collTrav.addCollider(self._camCollNP, self._collHandler)
        self._betweenCamAndToon = {}
        self._transNP = NodePath('trans')
        self._transNP.reparentTo(render)
        self._transNP.setTransparency(True)
        self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon)
        self._transNP.setBin('fixed', 10000)

    def _destroyCollisions(self):
        self._collTrav.removeCollider(self._camCollNP)
        self._camCollNP.removeNode()
        del self._camCollNP
        del self._camCollRay
        del self._collHandler
        del self._collOffset
        del self._betweenCamAndToon
        self._transNP.removeNode()
        del self._transNP

    def freeze(self):
        self._frozen = True

    def unfreeze(self):
        self._frozen = False

    def disable(self):
        if not self._enabled:
            return
        self._destroyCollisions()
        self._camera.wrtReparentTo(render)
        self._cameraLookAtNP.removeNode()
        del self._cameraLookAtNP
        self._camParent.removeNode()
        del self._camParent
        del self._prevToonY
        del self._lookAtZ
        del self._bounds
        del self._frozen
        self._enabled = False

    def update(self, dt=0.0):
        self._updateCam(dt)
        self._updateCollisions()

    def _updateCam(self, dt):
        toonPos = self._toon.getPos()
        camPos = self._camParent.getPos()
        x = camPos[0]
        z = camPos[2]
        toonWorldX = self._toon.getX(render)
        maxX = Globals.Camera.MaxSpinX
        toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX)
        spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (
            maxX * maxX)
        newH = 180.0 + spinAngle
        self._camParent.setH(newH)
        spinAngle = spinAngle * (pi / 180.0)
        distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle)
        distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle)
        d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0])
        if abs(d) > Globals.Camera.LeewayX:
            if d > Globals.Camera.LeewayX:
                x = toonPos[0] + Globals.Camera.LeewayX
            else:
                x = toonPos[0] - Globals.Camera.LeewayX
        x = self._toon.getX(render) + distToRightOfToon
        boundToonZ = min(toonPos[2], self._bounds[2][1])
        d = z - boundToonZ
        if d > Globals.Camera.MinLeewayZ:
            if self._player.velocity[2] >= 0 and toonPos[
                    1] != self._prevToonY or self._player.velocity[2] > 0:
                z = boundToonZ + d * INVERSE_E**(dt *
                                                 Globals.Camera.CatchUpRateZ)
            elif d > Globals.Camera.MaxLeewayZ:
                z = boundToonZ + Globals.Camera.MaxLeewayZ
        elif d < -Globals.Camera.MinLeewayZ:
            z = boundToonZ - Globals.Camera.MinLeewayZ
        if self._frozen:
            y = camPos[1]
        else:
            y = self._toon.getY(render) - distBehindToon
        self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z))
        if toonPos[2] < self._bounds[2][1]:
            h = self._cameraLookAtNP.getH()
            if d >= Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ)
            elif d <= -Globals.Camera.MinLeewayZ:
                self._cameraLookAtNP.lookAt(self._camParent, 0, 0,
                                            self._lookAtZ)
            self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0)
            self._camera.setHpr(
                smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr()))
        self._prevToonY = toonPos[1]

    def _updateCollisions(self):
        pos = self._toon.getPos(self._camera) + self._collOffset
        self._camCollRay.setOrigin(pos)
        direction = -Vec3(pos)
        direction.normalize()
        self._camCollRay.setDirection(direction)
        self._collTrav.traverse(render)
        nodesInBetween = {}
        if self._collHandler.getNumEntries() > 0:
            self._collHandler.sortEntries()
            for entry in self._collHandler.getEntries():
                name = entry.getIntoNode().getName()
                if name.find('col_') >= 0:
                    np = entry.getIntoNodePath().getParent()
                    if not np in nodesInBetween:
                        nodesInBetween[np] = np.getParent()

        for np in nodesInBetween.keys():
            if np in self._betweenCamAndToon:
                del self._betweenCamAndToon[np]
            else:
                np.setTransparency(True)
                np.wrtReparentTo(self._transNP)
                if np.getName().find('lightFixture') >= 0:
                    if not np.find('**/*floor_mesh').isEmpty():
                        np.find('**/*floor_mesh').hide()
                elif np.getName().find('platform') >= 0:
                    if not np.find('**/*Floor').isEmpty():
                        np.find('**/*Floor').hide()

        for np, parent in self._betweenCamAndToon.items():
            np.wrtReparentTo(parent)
            np.setTransparency(False)
            if np.getName().find('lightFixture') >= 0:
                if not np.find('**/*floor_mesh').isEmpty():
                    np.find('**/*floor_mesh').show()
            elif np.getName().find('platform') >= 0:
                if not np.find('**/*Floor').isEmpty():
                    np.find('**/*Floor').show()

        self._betweenCamAndToon = nodesInBetween
Beispiel #7
0
    def test_door_setup(self):
        parent_np = NodePath('parent_np')
        parent_np.setPosHpr(0, 10, .5, 180, 0, 0)

        door_origin = parent_np.attachNewNode('door_origin')
        door_origin.setPos(10, -25, .5)

        block = 4
        color = Vec4(.842, .167, .361, 1)

        # Set up door_np nodes
        door_np = NodePath('door_np')

        left_hole = door_np.attachNewNode('door_0_hole_left')
        right_hole = door_np.attachNewNode('door_0_hole_right')

        left_door = door_np.attachNewNode('door_0_left')
        right_door = door_np.attachNewNode('door_0_right')

        door_flat = door_np.attachNewNode('door_0_flat')
        door_trigger = door_np.attachNewNode('door_0_trigger')

        DNADoor.setupDoor(door_np, parent_np, door_origin, self.store, block, color)

        # Check if the nodes attributes and parents are correct
        self.assertEqual(door_np.getPos(door_origin), Point3(0, 0, 0))
        self.assertEqual(door_np.getHpr(door_origin), Point3(0, 0, 0))
        self.assertEqual(door_np.getScale(door_origin), Point3(1, 1, 1))

        def verify_color(color1, color2):
            self.assertAlmostEqual(color1.getX(), color2.getX(), places=4)
            self.assertAlmostEqual(color1.getY(), color2.getY(), places=4)
            self.assertAlmostEqual(color1.getZ(), color2.getZ(), places=4)
            self.assertAlmostEqual(color1.getW(), color2.getW(), places=4)

        verify_color(color, door_np.getColor())

        self.assertEqual(left_hole.getParent(), door_flat)
        self.assertEqual(left_hole.getName(), 'doorFrameHoleLeft')

        self.assertEqual(right_hole.getParent(), door_flat)
        self.assertEqual(right_hole.getName(), 'doorFrameHoleRight')

        self.assertEqual(left_door.getParent(), parent_np)
        self.assertEqual(left_door.getName(), 'leftDoor')
        verify_color(color, right_door.getColor())

        self.assertEqual(right_door.getParent(), parent_np)
        self.assertEqual(right_door.getName(), 'rightDoor')
        verify_color(color, right_door.getColor())

        self.assertEqual(door_trigger.getParent(), parent_np)
        self.assertEqual(door_trigger.getName(), 'door_trigger_%d' % block)

        store_np = self.store.getDoorPosHprFromBlockNumber(block)
        self.assertFalse(store_np.isEmpty())

        # Testing the pos is a pain because of decimal precision
        pos = store_np.getPos()
        self.assertAlmostEqual(pos.getX(), -10, places=2)
        self.assertAlmostEqual(pos.getY(), 35, places=2)
        self.assertAlmostEqual(pos.getZ(), 1, places=2)

        # Sometimes getH() returns -180 and others 180
        # Test the modulus (better than abs I guess)
        self.assertEqual(store_np.getH() % 180, 0)
Beispiel #8
0
class Game(ShowBase):
    '''
    '''
    def __init__(self):
        '''
        '''
        # loadPrcFileData("", "want-pstats 1\n pstats-host 127.0.0.1\n pstats-tasks 1\n task-timer-verbose 1")
        # loadPrcFileData("", "pstatshost 192.168.220.121")
        ShowBase.__init__(self)

        # PStatClient.connect() #activate to start performance measuring with pstats
        base.setFrameRateMeter(True)  # Show the Framerate
        # base.toggleWireframe()
        self.accept("space", self.onSpace)
        self.accept("tab", self.onTab)
        self.startGame()
        self.cam_on = True
        # -----------------------------------------------------------------

    # -----------------------------------------------------------------

    def onSpace(self, evt=None):
        '''
        '''
        if self.trackmesh2.getParent() == render:
            self.trackmesh.reparentTo(render)
            self.trackmesh2.detachNode()
        else:
            self.trackmesh.detachNode()
            self.trackmesh2.reparentTo(render)
        # base.toggleWireframe()

    # -----------------------------------------------------------------

    def startGame(self):
        '''
        Start the game
        '''
        # Create the Track

        self.track = trackgen3d.Track3d(1000, 800, 600, 200, 5)

        self.trackmesh = NodePath(self.track.createRoadMesh())
        tex = loader.loadTexture('data/textures/street.png')
        self.trackmesh.setTexture(tex)

        self.trackmesh2 = NodePath(self.track.createUninterpolatedRoadMesh())
        self.trackmesh2.setTexture(tex)
        # nodePath.setTwoSided(True)

        self.trackmesh.reparentTo(render)

        # LICHT
        self.plight = PointLight('kkkplight')
        self.plight.setColor(VBase4(21, 0, 0, 1))
        self.plnp = NodePath(self.plight)
        self.plnp.reparentTo(render)
        self.plnp.setPos(0, 0, 2000)
        self.plnp.node().setAttenuation(Point3(0, 0, 1))
        self.plnp.setScale(.5, .5, .5)

        # self.plnp.setHpr(0,-90,0)
        # print plight.getAttenuation()
        # plnp.setPos(-10, -800, 20)
        render.setLight(self.plnp)

        self.accept("w", self.setA, [100])
        self.accept("s", self.setA, [-10])
        self.accept("e", self.setB, [10])
        self.accept("d", self.setB, [-10])
        self.accept("r", self.setC, [100])
        self.accept("f", self.setC, [-100])

        self.accept("z", self.setRotation, [0, 10])
        self.accept("h", self.setRotation, [0, -10])
        self.accept("u", self.setRotation, [1, 10])
        self.accept("j", self.setRotation, [1, -10])
        self.accept("i", self.setRotation, [2, 10])
        self.accept("k", self.setRotation, [2, -10])

        self.accept("n", self.setExponent, [-50])
        self.accept("m", self.setExponent, [50])

        # load our model
        tron = loader.loadModel("data/models/vehicles/vehicle02")
        self.tron = tron
        # self.tron.loadAnims({"running":"models/tron_anim"})
        tron.reparentTo(render)
        tron.setPos(0, 0, 15)
        tron.setHpr(0, -90, 0)
        # nodePath2 = self.render.attachNewNode(self.track.createBorderLeftMesh())
        # tex2 = loader.loadTexture('data/textures/border.png')
        # nodePath2.setTexture(tex2)
        #
        # nodePath3 = self.render.attachNewNode(self.track.createBorderRightMesh())
        # tex2 = loader.loadTexture('data/textures/border.png')
        # nodePath3.setTexture(tex2)
        ring = loader.loadModel("data/models/ring.egg")
        ring.setScale(24)
        ring.setZ(-25)
        ring.setY(100)
        ring.setTransparency(TransparencyAttrib.MAlpha)
        ring.reparentTo(render)

        # Load the Lights
        ambilight = AmbientLight('ambilight')
        ambilight.setColor(VBase4(0.8, 0.8, 0.8, 1))
        render.setLight(render.attachNewNode(ambilight))

    # -----------------------------------------------------------------

    def setA(self, val):
        '''
        '''
        tpos = self.tron.getPos()
        tpos[0] += val
        self.tron.setPos(tpos)
        pos = self.plnp.getPos()
        pos[0] += val
        print(pos)
        self.plnp.setPos(pos)

    def setB(self, val):
        '''
        '''
        tpos = self.tron.getPos()
        tpos[1] += val
        self.tron.setPos(tpos)
        pos = self.plnp.getPos()
        pos[1] += val
        print(pos)
        self.plnp.setPos(pos)

    def setC(self, val):
        '''
        '''
        tpos = self.tron.getPos()
        tpos[2] += val
        self.tron.setPos(tpos)
        pos = self.plnp.getPos()
        pos[2] += val
        print(pos)
        self.plnp.setPos(pos)

    def setRotation(self, var, val):
        '''
        '''
        hpr = self.plnp.getHpr()
        hpr[var] += val
        print(("hpr", hpr))
        self.plnp.setHpr(hpr)

    def setExponent(self, val):
        '''
        '''
        val = self.plight.getExponent() + val
        print(val)
        self.plight.setExponent(val)

    def onTab(self):
        '''
        '''
        if self.cam_on:
            base.disableMouse()
            base.camera.setPos(-293.807, 91.2993, 3984.4)
            base.camera.setHpr(-76.0078, -85.4581, -71.7315)

            # base.camera.setPos(39.3053, -376.205, -3939.89)
            # base.camera.setHpr(5.33686, -82.7432, 8.26239)

            # print base.camera.getPos(), base.camera.getHpr()
            self.cam_on = False
        else:
            base.enableMouse()
            self.cam_on = True
class DistributedButterfly(DistributedObject.DistributedObject):

    notify = DirectNotifyGlobal.directNotify.newCategory(
        'DistributedButterfly')

    id = 0
    # wings_1 (solid yellow)
    # wings_2 (yellow w/ dots) (1, 1, 1), (0.2, 0, 1), (1, 0, 1), (0.8, 0, 1)
    # wings_3 (solid white) (0.8, 0, 0.8), (0, 0.8, 0.8), (0.9, 0.4, 0.6)
    #           (0.9, 0.4, 0.4), (0.8, 0.5, 0.9), (0.4, 0.1, 0.7)
    # wings_4 (white w/ dots)
    # wings_5 (pale yellow w/ lines) (0.8, 0, 0.8), (0.6, 0.6, 0.9)
    #           (0.7, 0.6, 0.9), (0.8, 0.6, 0.9), (0.9, 0.6, 0.9),
    #           (1, 0.6, 0.9)
    # wings_6 (blue & yellow)
    wingTypes = ('wings_1', 'wings_2', 'wings_3', 'wings_4', 'wings_5',
                 'wings_6')
    yellowColors = (Vec4(1, 1, 1, 1), Vec4(0.2, 0, 1, 1), Vec4(0.8, 0, 1, 1))
    whiteColors = (Vec4(0.8, 0, 0.8, 1), Vec4(0, 0.8, 0.8,
                                              1), Vec4(0.9, 0.4, 0.6, 1),
                   Vec4(0.9, 0.4, 0.4, 1), Vec4(0.8, 0.5, 0.9,
                                                1), Vec4(0.4, 0.1, 0.7, 1))
    paleYellowColors = (Vec4(0.8, 0, 0.8, 1), Vec4(0.6, 0.6, 0.9,
                                                   1), Vec4(0.7, 0.6, 0.9, 1),
                        Vec4(0.8, 0.6, 0.9, 1), Vec4(0.9, 0.6, 0.9,
                                                     1), Vec4(1, 0.6, 0.9, 1))
    shadowScaleBig = Point3(0.07, 0.07, 0.07)
    shadowScaleSmall = Point3(0.01, 0.01, 0.01)

    def __init__(self, cr):
        """__init__(cr)
        """
        DistributedObject.DistributedObject.__init__(self, cr)

        self.fsm = ClassicFSM.ClassicFSM(
            'DistributedButterfly',
            [
                State.State('off', self.enterOff, self.exitOff,
                            ['Flying', 'Landed']),
                State.State('Flying', self.enterFlying, self.exitFlying,
                            ['Landed']),
                State.State('Landed', self.enterLanded, self.exitLanded,
                            ['Flying'])
            ],
            # Initial State
            'off',
            # Final State
            'off',
        )
        self.butterfly = None
        self.butterflyNode = None
        self.curIndex = 0
        self.destIndex = 0
        self.time = 0.0
        self.ival = None
        self.fsm.enterInitialState()

    def generate(self):
        """generate(self)
        This method is called when the DistributedObject is reintroduced
        to the world, either for the first time or from the cache.
        """
        DistributedObject.DistributedObject.generate(self)
        if self.butterfly:
            return

        self.butterfly = Actor.Actor()
        self.butterfly.loadModel('phase_4/models/props/SZ_butterfly-mod.bam')
        self.butterfly.loadAnims({
            'flutter':
            'phase_4/models/props/SZ_butterfly-flutter.bam',
            'glide':
            'phase_4/models/props/SZ_butterfly-glide.bam',
            'land':
            'phase_4/models/props/SZ_butterfly-land.bam'
        })

        # Randomly choose one of the butterfly wing patterns
        index = self.doId % len(self.wingTypes)
        chosenType = self.wingTypes[index]
        node = self.butterfly.getGeomNode()
        for type in self.wingTypes:
            wing = node.find('**/' + type)
            if (type != chosenType):
                wing.removeNode()
            else:
                # Choose an appropriate blend color
                if (index == 0 or index == 1):
                    color = self.yellowColors[self.doId %
                                              len(self.yellowColors)]
                elif (index == 2 or index == 3):
                    color = self.whiteColors[self.doId % len(self.whiteColors)]
                elif (index == 4):
                    color = self.paleYellowColors[self.doId %
                                                  len(self.paleYellowColors)]
                else:
                    color = Vec4(1, 1, 1, 1)
                wing.setColor(color)

        # Make another copy of the butterfly model so we can LOD the
        # blending.  Butterflies that are far away won't bother to
        # blend animations; nearby butterflies will use dynamic
        # blending to combine two or more animations at once on
        # playback for a nice fluttering and landing effect.
        self.butterfly2 = Actor.Actor(other=self.butterfly)

        # Allow the nearby butterfly to blend between its three
        # animations.  All animations will be playing all the time;
        # we'll control which one is visible by varying the control
        # effect.
        self.butterfly.enableBlend(blendType=PartBundle.BTLinear)
        self.butterfly.loop('flutter')
        self.butterfly.loop('land')
        self.butterfly.loop('glide')

        # Make a random play rate so all the butterflies will be
        # flapping at slightly different rates.  This doesn't affect
        # the rate at which the butterfly moves, just the rate at
        # which the animation plays on the butterfly.
        rng = RandomNumGen.RandomNumGen(self.doId)
        playRate = 0.6 + 0.8 * rng.random()
        self.butterfly.setPlayRate(playRate, 'flutter')
        self.butterfly.setPlayRate(playRate, 'land')
        self.butterfly.setPlayRate(playRate, 'glide')
        self.butterfly2.setPlayRate(playRate, 'flutter')
        self.butterfly2.setPlayRate(playRate, 'land')
        self.butterfly2.setPlayRate(playRate, 'glide')

        # Also, a random glide contribution ratio.  We'll blend a bit
        # of the glide animation in with the flutter animation to
        # dampen the effect of flutter.  The larger the number here,
        # the greater the dampening effect.  Some butterflies will be
        # more active than others.  (Except when seen from a long way
        # off, because of the LODNode, below.)
        self.glideWeight = rng.random() * 2

        lodNode = LODNode('butterfly-node')
        lodNode.addSwitch(100, 40)  # self.butterfly2
        lodNode.addSwitch(40, 0)  # self.butterfly

        self.butterflyNode = NodePath(lodNode)
        self.butterfly2.setH(180.0)
        self.butterfly2.reparentTo(self.butterflyNode)
        self.butterfly.setH(180.0)
        self.butterfly.reparentTo(self.butterflyNode)
        self.__initCollisions()

        # Set up the drop shadow
        self.dropShadow = loader.loadModel('phase_3/models/props/drop_shadow')
        self.dropShadow.setColor(0, 0, 0, 0.3)
        self.dropShadow.setPos(0, 0.1, -0.05)
        self.dropShadow.setScale(self.shadowScaleBig)
        self.dropShadow.reparentTo(self.butterfly)

    def disable(self):
        """disable(self)
        This method is called when the DistributedObject is removed from
        active duty and stored in a cache.
        """
        self.butterflyNode.reparentTo(hidden)
        if (self.ival != None):
            self.ival.finish()
        self.__ignoreAvatars()
        DistributedObject.DistributedObject.disable(self)

    def delete(self):
        """delete(self)
        This method is called when the DistributedObject is permanently
        removed from the world and deleted from the cache.
        """
        self.butterfly.cleanup()
        self.butterfly = None
        self.butterfly2.cleanup()
        self.butterfly2 = None
        self.butterflyNode.removeNode()
        self.__deleteCollisions()
        self.ival = None
        del self.fsm
        DistributedObject.DistributedObject.delete(self)

    def uniqueButterflyName(self, name):
        DistributedButterfly.id += 1
        return (name + '-%d' % DistributedButterfly.id)

    def __detectAvatars(self):
        self.accept('enter' + self.cSphereNode.getName(),
                    self.__handleCollisionSphereEnter)

    def __ignoreAvatars(self):
        self.ignore('enter' + self.cSphereNode.getName())

    def __initCollisions(self):
        self.cSphere = CollisionSphere(0., 1., 0., 3.)
        self.cSphere.setTangible(0)
        self.cSphereNode = CollisionNode(
            self.uniqueButterflyName('cSphereNode'))
        self.cSphereNode.addSolid(self.cSphere)
        self.cSphereNodePath = self.butterflyNode.attachNewNode(
            self.cSphereNode)
        self.cSphereNodePath.hide()
        self.cSphereNode.setCollideMask(ToontownGlobals.WallBitmask)

    def __deleteCollisions(self):
        del self.cSphere
        del self.cSphereNode
        self.cSphereNodePath.removeNode()
        del self.cSphereNodePath

    def __handleCollisionSphereEnter(self, collEntry):
        """ Response for a toon walking up to this NPC
        """
        assert (self.notify.debug("Entering collision sphere..."))
        # Tell the server
        self.sendUpdate('avatarEnter', [])

    def setArea(self, playground, area):
        self.playground = playground
        self.area = area

    def setState(self, stateIndex, curIndex, destIndex, time, timestamp):
        self.curIndex = curIndex
        self.destIndex = destIndex
        self.time = time
        self.fsm.request(ButterflyGlobals.states[stateIndex],
                         [globalClockDelta.localElapsedTime(timestamp)])

    ##### Off state #####

    def enterOff(self, ts=0.0):
        if (self.butterflyNode != None):
            self.butterflyNode.reparentTo(hidden)
        return None

    def exitOff(self):
        if (self.butterflyNode != None):
            self.butterflyNode.reparentTo(render)
        return None

    ##### Flying state #####

    def enterFlying(self, ts):
        self.__detectAvatars()
        curPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][
            self.curIndex]
        destPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][
            self.destIndex]
        # We'll hit the ground if we go straight from curPos to destPos
        flyHeight = max(
            curPos[2],
            destPos[2]) + ButterflyGlobals.BUTTERFLY_HEIGHT[self.playground]
        curPosHigh = Point3(curPos[0], curPos[1], flyHeight)
        destPosHigh = Point3(destPos[0], destPos[1], flyHeight)

        if (ts <= self.time):
            flyTime = self.time - (
                ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground] +
                ButterflyGlobals.BUTTERFLY_LANDING[self.playground])
            self.butterflyNode.setPos(curPos)
            self.dropShadow.show()
            self.dropShadow.setScale(self.shadowScaleBig)
            oldHpr = self.butterflyNode.getHpr()
            self.butterflyNode.headsUp(destPos)
            newHpr = self.butterflyNode.getHpr()
            self.butterflyNode.setHpr(oldHpr)
            takeoffShadowT = 0.2 * ButterflyGlobals.BUTTERFLY_TAKEOFF[
                self.playground]
            landShadowT = 0.2 * ButterflyGlobals.BUTTERFLY_LANDING[
                self.playground]
            self.butterfly2.loop('flutter')
            self.ival = Sequence(
                Parallel(
                    LerpPosHprInterval(
                        self.butterflyNode,
                        ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground],
                        curPosHigh, newHpr),
                    LerpAnimInterval(
                        self.butterfly,
                        ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground],
                        'land', 'flutter'),
                    LerpAnimInterval(
                        self.butterfly,
                        ButterflyGlobals.BUTTERFLY_TAKEOFF[self.playground],
                        None,
                        'glide',
                        startWeight=0,
                        endWeight=self.glideWeight),
                    Sequence(
                        LerpScaleInterval(self.dropShadow,
                                          takeoffShadowT,
                                          self.shadowScaleSmall,
                                          startScale=self.shadowScaleBig),
                        HideInterval(self.dropShadow)),
                ),
                LerpPosInterval(self.butterflyNode, flyTime, destPosHigh),
                Parallel(
                    LerpPosInterval(
                        self.butterflyNode,
                        ButterflyGlobals.BUTTERFLY_LANDING[self.playground],
                        destPos),
                    LerpAnimInterval(
                        self.butterfly,
                        ButterflyGlobals.BUTTERFLY_LANDING[self.playground],
                        'flutter', 'land'),
                    LerpAnimInterval(
                        self.butterfly,
                        ButterflyGlobals.BUTTERFLY_LANDING[self.playground],
                        None,
                        'glide',
                        startWeight=self.glideWeight,
                        endWeight=0),
                    Sequence(
                        Wait(ButterflyGlobals.BUTTERFLY_LANDING[
                            self.playground] - landShadowT),
                        ShowInterval(self.dropShadow),
                        LerpScaleInterval(self.dropShadow,
                                          landShadowT,
                                          self.shadowScaleBig,
                                          startScale=self.shadowScaleSmall)),
                ),
                name=self.uniqueName("Butterfly"))
            self.ival.start(ts)
        else:
            self.ival = None
            self.butterflyNode.setPos(destPos)
            self.butterfly.setControlEffect('land', 1.0)
            self.butterfly.setControlEffect('flutter', 0.0)
            self.butterfly.setControlEffect('glide', 0.0)
            self.butterfly2.loop('land')
        return None

    def exitFlying(self):
        self.__ignoreAvatars()
        if (self.ival != None):
            self.ival.finish()
            self.ival = None
        return None

    ##### Landed state #####

    def enterLanded(self, ts):
        self.__detectAvatars()
        curPos = ButterflyGlobals.ButterflyPoints[self.playground][self.area][
            self.curIndex]
        self.butterflyNode.setPos(curPos)
        self.dropShadow.show()
        self.dropShadow.setScale(self.shadowScaleBig)
        self.butterfly.setControlEffect('land', 1.0)
        self.butterfly.setControlEffect('flutter', 0.0)
        self.butterfly.setControlEffect('glide', 0.0)
        self.butterfly2.pose(
            'land', random.randrange(self.butterfly2.getNumFrames('land')))
        return None

    def exitLanded(self):
        self.__ignoreAvatars()
        return None
Beispiel #10
0
class Entity(DirectObject, object):
  def __init__(self, model = None):
    self.prime = None
    if model != None:
      self.set_model(model)

  def get_model(self):
    return self.prime

  def set_model(self, model):
    if model != None:
      if isinstance(model, PandaNode):
        self.prime = NodePath(model)
      elif isinstance(model, NodePath):
        self.prime = model
      else:
        if Filename(model).exists():
          self.model = Filename(model).getBasenameWoExtension()
          path = model
        else:
          if isinstance(model, Filename):
            self.model = model.getBasenameWoExtension()
            path = model.getFullpath()
          else:
            path = APP_PATH + model

          print "path: ", path
          if Filename(path).exists():
            pass
          elif Filename(path + ".bam").exists():
            path += ".bam"
          elif Filename(path + ".bam.pz").exists():
            path += ".bam.pz"
          elif Filename(path + ".egg").exists():
            path += ".egg"
          elif Filename(path + ".egg.pz").exists():
            path += ".egg.pz"
          elif Filename(path + ".x").exists():
            path += ".x"
          else:
            print ":object(error): can't find model", model, "!"
            # Probably shouldn't exit because of this
            sys.exit(1)
          self.model = model
        self.prime = base.loader.loadModel(path)
        if self.prime == None:
          print ":object(error): can't load model", model, "!"
          # Probably shouldn't exit because of this
          sys.exit(1)

  def getX(self):
    return self.prime.getX(base.render)

  def getY(self):
    return self.prime.getY(base.render)

  def getZ(self):
    return self.prime.getZ(base.render)

  def getH(self):
    return self.prime.getH(base.render)

  def getP(self):
    return self.prime.getP(base.render)

  def getR(self):
    return self.prime.getR(base.render)

  def getSx(self):
    return self.prime.getSx(base.render)

  def getSy(self):
    return self.prime.getSy(base.render)

  def getSz(self):
    return self.prime.getSz(base.render)

  def getPos(self):
    return self.prime.getPos(base.render)

  def getHpr(self):
    return self.prime.getHpr(base.render)

  def getScale(self):
    return self.prime.getScale(base.render)

  def getCollideMask(self):
    return self.prime.getCollideMask()

  def getTransparency(self):
    return self.prime.getTransparency()

  def getTwoSided(self):
    return self.prime.getTwoSided()

  def getParent(self):
    return self.prime.getParent()

  def setX(self, *v):
    self.prime.setX(*v)

  def setY(self, *v):
    self.prime.setY(*v)

  def setZ(self, *v):
    self.prime.setZ(*v)

  def setH(self, *v):
    self.prime.setH(*v)

  def setP(self, *v):
    self.prime.setP(*v)

  def setR(self, *v):
    self.prime.setR(*v)

  def setSx(self, *v):
    self.prime.setSx(*v)

  def setSy(self, *v):
    self.prime.setSy(*v)

  def setSz(self, *v):
    self.prime.setSz(*v)

  def setPos(self, *v):
    self.prime.setPos(*v)

  def setHpr(self, *v):
    self.prime.setHpr(*v)

  def setScale(self, *v):
    self.prime.setScale(*v)

  def setCollideMask(self, *v):
    self.prime.setCollideMask(*v)

  def setTransparency(self, *v):
    self.prime.setTransparency(*v)

  def setTwoSided(self, *v):
    self.prime.setTwoSided(*v)

  def removeNode(self):
    self.prime.removeNode()

  def reparentTo(self, parent):
    if isinstance(parent, Entity):
      parent = parent.prime
    if isinstance(parent, str):
      if parent.startswith("render/"):
        parent = parent[7:]
        tv = parent
        parent = base.render.find(tv)
        if parent == NodePath():
          parent = base.render.find("**/" + tv)
    if parent != NodePath() and parent != None:
      self.prime.reparentTo(parent)

  def wrtReparentTo(self, parent):
    if isinstance(parent, Entity):
      parent = parent.prime
    if isinstance(parent, str):
      if parent.startswith("render/"):
        parent = parent[7:]
        tv = parent
        parent = base.render.find(tv)
        if parent == NodePath():
          parent = base.render.find("**/" + tv)
    if parent != NodePath():
      self.prime.reparentTo(parent)

  def attachTo(self, parent):
    """This attaches the object to another object/nodepath. The caller object stays at the same place, with the same scale and rotation,
    but they become relative to the other object/nodepath. This is useful with for example a character that steps onto a moving ship or so."""
    if isinstance(parent, Entity):
      parent = parent.prime
    if isinstance(parent, str):
      if(parent.startswith("render/")): parent = parent[7:]
      tv = parent
      parent = base.render.find(tv)
      if(parent == NodePath()):
        parent = base.render.find("**/" + tv)
    if(parent != NodePath()):
      self.prime.setPos(self.prime.getPos(parent))
      self.prime.setHpr(self.prime.getHpr(parent))
      self.prime.setScale(self.prime.getScale(parent))
      self.prime.reparentTo(parent)

  def hide(self):
    self.prime.hide()

  def show(self):
    self.prime.show()

  def __del__(self):
    try:
      if isinstance(self.prime, NodePath):
        self.prime.removeNode()
    except AttributeError: pass

  def __getstate__(self):
    return [self.model, self.getX(), self.getY(), self.getZ(), self.getH(),
            self.getP(), self.getR(), self.getSx(), self.getSy(),
            self.getSz(), self.getCollideMask().getWord(),
            self.getTransparency(), self.getTwoSided(), str(self.getParent())]

  def __setstate__(self, p):
    if len(p) < 14:
      print ":object(error): This state is not compatible with this version!"
      sys.exit(1)

    self.setModel(p[0])
    self.setX(p[1])
    self.setY(p[2])
    self.setZ(p[3])
    self.setH(p[4])
    self.setP(p[5])
    self.setR(p[6])
    self.setSx(p[7])
    self.setSy(p[8])
    self.setSz(p[9])
    self.setCollideMask(BitMask32(p[10]))
    self.setTransparency(p[11])
    self.setTwoSided(p[12])
    self.reparentTo(p[13])
    def test_door_setup(self):
        parent_np = NodePath('parent_np')
        parent_np.setPosHpr(0, 10, .5, 180, 0, 0)

        door_origin = parent_np.attachNewNode('door_origin')
        door_origin.setPos(10, -25, .5)

        block = 4
        color = Vec4(.842, .167, .361, 1)

        # Set up door_np nodes
        door_np = NodePath('door_np')

        left_hole = door_np.attachNewNode('door_0_hole_left')
        right_hole = door_np.attachNewNode('door_0_hole_right')

        left_door = door_np.attachNewNode('door_0_left')
        right_door = door_np.attachNewNode('door_0_right')

        door_flat = door_np.attachNewNode('door_0_flat')
        door_trigger = door_np.attachNewNode('door_0_trigger')

        DNADoor.setupDoor(door_np, parent_np, door_origin, self.store, block, color)

        # Check if the nodes attributes and parents are correct
        self.assertEqual(door_np.getPos(door_origin), Point3(0, 0, 0))
        self.assertEqual(door_np.getHpr(door_origin), Point3(0, 0, 0))
        self.assertEqual(door_np.getScale(door_origin), Point3(1, 1, 1))

        def verify_color(color1, color2):
            self.assertAlmostEqual(color1.getX(), color2.getX(), places=4)
            self.assertAlmostEqual(color1.getY(), color2.getY(), places=4)
            self.assertAlmostEqual(color1.getZ(), color2.getZ(), places=4)
            self.assertAlmostEqual(color1.getW(), color2.getW(), places=4)

        verify_color(color, door_np.getColor())

        self.assertEqual(left_hole.getParent(), door_flat)
        self.assertEqual(left_hole.getName(), 'doorFrameHoleLeft')

        self.assertEqual(right_hole.getParent(), door_flat)
        self.assertEqual(right_hole.getName(), 'doorFrameHoleRight')

        self.assertEqual(left_door.getParent(), parent_np)
        self.assertEqual(left_door.getName(), 'leftDoor')
        verify_color(color, right_door.getColor())

        self.assertEqual(right_door.getParent(), parent_np)
        self.assertEqual(right_door.getName(), 'rightDoor')
        verify_color(color, right_door.getColor())

        self.assertEqual(door_trigger.getParent(), parent_np)
        self.assertEqual(door_trigger.getName(), 'door_trigger_%d' % block)

        store_np = self.store.getDoorPosHprFromBlockNumber(block)
        self.assertFalse(store_np.isEmpty())

        # Testing the pos is a pain because of decimal precision
        pos = store_np.getPos()
        self.assertAlmostEqual(pos.getX(), -10, places=2)
        self.assertAlmostEqual(pos.getY(), 35, places=2)
        self.assertAlmostEqual(pos.getZ(), 1, places=2)

        # Sometimes getH() returns -180 and others 180
        # Test the modulus (better than abs I guess)
        self.assertEqual(store_np.getH() % 180, 0)
Beispiel #12
0
class IsisAgent(kinematicCharacterController, DirectObject):
    @classmethod
    def setPhysics(cls, physics):
        """ This method is set in src.loader when the generators are loaded
        into the namespace.  This frees the environment definitions (in 
        scenario files) from having to pass around the physics parameter 
        that is required for all IsisObjects """
        cls.physics = physics

    def __init__(self, name, queueSize=100):

        # load the model and the different animations for the model into an Actor object.
        self.actor = Actor(
            "media/models/boxman", {"walk": "media/models/boxman-walk", "idle": "media/models/boxman-idle"}
        )
        self.actor.setScale(1.0)
        self.actor.setH(0)
        # self.actor.setLODAnimation(10,5,2) # slows animation framerate when actor is far from camera, if you can figure out reasonable params
        self.actor.setColorScale(random.random(), random.random(), random.random(), 1.0)
        self.actorNodePath = NodePath("agent-%s" % name)
        self.activeModel = self.actorNodePath

        self.actorNodePath.reparentTo(render)

        self.actor.reparentTo(self.actorNodePath)
        self.name = name
        self.isMoving = False

        # initialize ODE controller
        kinematicCharacterController.__init__(self, IsisAgent.physics, self.actorNodePath)
        self.setGeomPos(self.actorNodePath.getPos(render))
        """
        Additional Direct Object that I use for convenience.
        """
        self.specialDirectObject = DirectObject()

        """
        How high above the center of the capsule you want the camera to be
        when walking and when crouching. It's related to the values in KCC.
        """
        self.walkCamH = 0.7
        self.crouchCamH = 0.2
        self.camH = self.walkCamH

        """
        This tells the Player Controller what we're aiming at.
        """
        self.aimed = None

        self.isSitting = False
        self.isDisabled = False

        """
        The special direct object is used for trigger messages and the like.
        """
        # self.specialDirectObject.accept("ladder_trigger_enter", self.setFly, [True])
        # self.specialDirectObject.accept("ladder_trigger_exit", self.setFly, [False])

        self.actor.makeSubpart("arms", ["LeftShoulder", "RightShoulder"])

        # Expose agent's right hand joint to attach objects to
        self.player_right_hand = self.actor.exposeJoint(None, "modelRoot", "Hand.R")
        self.player_left_hand = self.actor.exposeJoint(None, "modelRoot", "Hand.L")

        self.right_hand_holding_object = None
        self.left_hand_holding_object = None

        # don't change the color of things you pick up
        self.player_right_hand.setColorScaleOff()
        self.player_left_hand.setColorScaleOff()

        self.player_head = self.actor.exposeJoint(None, "modelRoot", "Head")
        self.neck = self.actor.controlJoint(None, "modelRoot", "Head")

        self.controlMap = {
            "turn_left": 0,
            "turn_right": 0,
            "move_forward": 0,
            "move_backward": 0,
            "move_right": 0,
            "move_left": 0,
            "look_up": 0,
            "look_down": 0,
            "look_left": 0,
            "look_right": 0,
            "jump": 0,
        }
        # see update method for uses, indices are [turn left, turn right, move_forward, move_back, move_right, move_left, look_up, look_down, look_right, look_left]
        # turns are in degrees per second, moves are in units per second
        self.speeds = [270, 270, 5, 5, 5, 5, 60, 60, 60, 60]

        self.originalPos = self.actor.getPos()

        bubble = loader.loadTexture("media/textures/thought_bubble.png")
        # bubble.setTransparency(TransparencyAttrib.MAlpha)

        self.speech_bubble = DirectLabel(
            parent=self.actor,
            text="",
            text_wordwrap=10,
            pad=(3, 3),
            relief=None,
            text_scale=(0.3, 0.3),
            pos=(0, 0, 3.6),
            frameColor=(0.6, 0.2, 0.1, 0.5),
            textMayChange=1,
            text_frame=(0, 0, 0, 1),
            text_bg=(1, 1, 1, 1),
        )
        # self.myImage=
        self.speech_bubble.setTransparency(TransparencyAttrib.MAlpha)
        # stop the speech bubble from being colored like the agent
        self.speech_bubble.setColorScaleOff()
        self.speech_bubble.component("text0").textNode.setCardDecal(1)
        self.speech_bubble.setBillboardAxis()
        # hide the speech bubble from IsisAgent's own camera
        self.speech_bubble.hide(BitMask32.bit(1))

        self.thought_bubble = DirectLabel(
            parent=self.actor,
            text="",
            text_wordwrap=9,
            text_frame=(1, 0, -2, 1),
            text_pos=(0, 0.5),
            text_bg=(1, 1, 1, 0),
            relief=None,
            frameSize=(0, 1.5, -2, 3),
            text_scale=(0.18, 0.18),
            pos=(0, 0.2, 3.6),
            textMayChange=1,
            image=bubble,
            image_pos=(0, 0.1, 0),
            sortOrder=5,
        )
        self.thought_bubble.setTransparency(TransparencyAttrib.MAlpha)
        # stop the speech bubble from being colored like the agent
        self.thought_bubble.setColorScaleOff()
        self.thought_bubble.component("text0").textNode.setFrameColor(1, 1, 1, 0)
        self.thought_bubble.component("text0").textNode.setFrameAsMargin(0.1, 0.1, 0.1, 0.1)
        self.thought_bubble.component("text0").textNode.setCardDecal(1)
        self.thought_bubble.setBillboardAxis()
        # hide the thought bubble from IsisAgent's own camera
        self.thought_bubble.hide(BitMask32.bit(1))
        # disable by default
        self.thought_bubble.hide()
        self.thought_filter = {}  # only show thoughts whose values are in here
        self.last_spoke = 0  # timers to keep track of last thought/speech and
        self.last_thought = 0  # hide visualizations

        # put a camera on ralph
        self.fov = NodePath(Camera("RaphViz"))
        self.fov.node().setCameraMask(BitMask32.bit(1))

        # position the camera to be infront of Boxman's face.
        self.fov.reparentTo(self.player_head)
        # x,y,z are not in standard orientation when parented to player-Head
        self.fov.setPos(0, 0.2, 0)
        # if P=0, canrea is looking directly up. 90 is back of head. -90 is on face.
        self.fov.setHpr(0, -90, 0)

        lens = self.fov.node().getLens()
        lens.setFov(60)  #  degree field of view (expanded from 40)
        lens.setNear(0.2)
        # self.fov.node().showFrustum() # displays a box around his head
        # self.fov.place()

        self.prevtime = 0
        self.current_frame_count = 0

        self.isSitting = False
        self.isDisabled = False
        self.msg = None
        self.actorNodePath.setPythonTag("agent", self)

        # Initialize the action queue, with a maximum length of queueSize
        self.queue = []
        self.queueSize = queueSize
        self.lastSense = 0

    def setLayout(self, layout):
        """ Dummy method called by spatial methods for use with objects. 
        Doesn't make sense for an agent that can move around."""
        pass

    def setPos(self, pos):
        """ Wrapper to set the position of the ODE geometry, which in turn 
        sets the visual model's geometry the next time the update() method
        is called. """
        self.setGeomPos(pos)

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

    def reparentTo(self, parent):
        self.actorNodePath.reparentTo(parent)

    def setControl(self, control, value):
        """Set the state of one of the character's movement controls.  """
        self.controlMap[control] = value

    def get_objects_in_field_of_vision(self, exclude=["isisobject"]):
        """ This works in an x-ray style. Fast. Works best if you listen to
        http://en.wikipedia.org/wiki/Rock_Art_and_the_X-Ray_Style while
        you use it.
        
        needs to exclude isisobjects since they cannot be serialized  
        """
        objects = {}
        for obj in base.render.findAllMatches("**/IsisObject*"):
            if not obj.hasPythonTag("isisobj"):
                continue
            o = obj.getPythonTag("isisobj")
            bounds = o.activeModel.getBounds()
            bounds.xform(o.activeModel.getMat(self.fov))
            if self.fov.node().isInView(o.activeModel.getPos(self.fov)):
                pos = o.activeModel.getPos(render)
                pos = (pos[0], pos[1], pos[2] + o.getHeight() / 2)
                p1 = self.fov.getRelativePoint(render, pos)
                p2 = Point2()
                self.fov.node().getLens().project(p1, p2)
                p3 = aspect2d.getRelativePoint(render2d, Point3(p2[0], 0, p2[1]))
                object_dict = {}
                if "x_pos" not in exclude:
                    object_dict["x_pos"] = p3[0]
                if "y_pos" not in exclude:
                    object_dict["y_pos"] = p3[2]
                if "distance" not in exclude:
                    object_dict["distance"] = o.activeModel.getDistance(self.fov)
                if "orientation" not in exclude:
                    object_dict["orientation"] = o.activeModel.getH(self.fov)
                if "actions" not in exclude:
                    object_dict["actions"] = o.list_actions()
                if "isisobject" not in exclude:
                    object_dict["isisobject"] = o
                # add item to dinctionary
                objects[o] = object_dict
        return objects

    def get_agents_in_field_of_vision(self):
        """ This works in an x-ray vision style as well"""
        agents = {}
        for agent in base.render.findAllMatches("**/agent-*"):
            if not agent.hasPythonTag("agent"):
                continue
            a = agent.getPythonTag("agent")
            bounds = a.actorNodePath.getBounds()
            bounds.xform(a.actorNodePath.getMat(self.fov))
            pos = a.actorNodePath.getPos(self.fov)
            if self.fov.node().isInView(pos):
                p1 = self.fov.getRelativePoint(render, pos)
                p2 = Point2()
                self.fov.node().getLens().project(p1, p2)
                p3 = aspect2d.getRelativePoint(render2d, Point3(p2[0], 0, p2[1]))
                agentDict = {
                    "x_pos": p3[0],
                    "y_pos": p3[2],
                    "distance": a.actorNodePath.getDistance(self.fov),
                    "orientation": a.actorNodePath.getH(self.fov),
                }
                agents[a] = agentDict
        return agents

    def in_view(self, isisobj):
        """ Returns true iff a particular isisobject is in view """
        return len(
            filter(lambda x: x["isisobject"] == isisobj, self.get_objects_in_field_of_vision(exclude=[]).values())
        )

    def get_objects_in_view(self):
        """ Gets objects through ray tracing.  Slow"""
        return self.picker.get_objects_in_view()

    def control__turn_left__start(self, speed=None):
        self.setControl("turn_left", 1)
        self.setControl("turn_right", 0)
        if speed:
            self.speeds[0] = speed
        return "success"

    def control__turn_left__stop(self):
        self.setControl("turn_left", 0)
        return "success"

    def control__turn_right__start(self, speed=None):
        self.setControl("turn_left", 0)
        self.setControl("turn_right", 1)
        if speed:
            self.speeds[1] = speed
        return "success"

    def control__turn_right__stop(self):
        self.setControl("turn_right", 0)
        return "success"

    def control__move_forward__start(self, speed=None):
        self.setControl("move_forward", 1)
        self.setControl("move_backward", 0)
        if speed:
            self.speeds[2] = speed
        return "success"

    def control__move_forward__stop(self):
        self.setControl("move_forward", 0)
        return "success"

    def control__move_backward__start(self, speed=None):
        self.setControl("move_forward", 0)
        self.setControl("move_backward", 1)
        if speed:
            self.speeds[3] = speed
        return "success"

    def control__move_backward__stop(self):
        self.setControl("move_backward", 0)
        return "success"

    def control__move_left__start(self, speed=None):
        self.setControl("move_left", 1)
        self.setControl("move_right", 0)
        if speed:
            self.speeds[4] = speed
        return "success"

    def control__move_left__stop(self):
        self.setControl("move_left", 0)
        return "success"

    def control__move_right__start(self, speed=None):
        self.setControl("move_right", 1)
        self.setControl("move_left", 0)
        if speed:
            self.speeds[5] = speed
        return "success"

    def control__move_right__stop(self):
        self.setControl("move_right", 0)
        return "success"

    def control__look_left__start(self, speed=None):
        self.setControl("look_left", 1)
        self.setControl("look_right", 0)
        if speed:
            self.speeds[9] = speed
        return "success"

    def control__look_left__stop(self):
        self.setControl("look_left", 0)
        return "success"

    def control__look_right__start(self, speed=None):
        self.setControl("look_right", 1)
        self.setControl("look_left", 0)
        if speed:
            self.speeds[8] = speed
        return "success"

    def control__look_right__stop(self):
        self.setControl("look_right", 0)
        return "success"

    def control__look_up__start(self, speed=None):
        self.setControl("look_up", 1)
        self.setControl("look_down", 0)
        if speed:
            self.speeds[6] = speed
        return "success"

    def control__look_up__stop(self):
        self.setControl("look_up", 0)
        return "success"

    def control__look_down__start(self, speed=None):
        self.setControl("look_down", 1)
        self.setControl("look_up", 0)
        if speed:
            self.speeds[7] = speed
        return "success"

    def control__look_down__stop(self):
        self.setControl("look_down", 0)
        return "success"

    def control__jump(self):
        self.setControl("jump", 1)
        return "success"

    def control__view_objects(self):
        """ calls a raytrace to to all objects in view """
        objects = self.get_objects_in_field_of_vision()
        self.control__say("If I were wearing x-ray glasses, I could see %i items" % len(objects))
        print "Objects in view:", objects
        return objects

    def control__sense(self):
        """ perceives the world, returns percepts dict """
        percepts = dict()
        # eyes: visual matricies
        # percepts['vision'] = self.sense__get_vision()
        # objects in purview (cheating object recognition)
        percepts["objects"] = self.sense__get_objects()
        # global position in environment - our robots can have GPS :)
        percepts["position"] = self.sense__get_position()
        # language: get last utterances that were typed
        percepts["language"] = self.sense__get_utterances()
        # agents: returns a map of agents to a list of actions that have been sensed
        percepts["agents"] = self.sense__get_agents()
        print percepts
        return percepts

    def control__think(self, message, layer=0):
        """ Changes the contents of an agent's thought bubble"""
        # only say things that are checked in the controller
        if self.thought_filter.has_key(layer):
            self.thought_bubble.show()
            self.thought_bubble["text"] = message
            # self.thought_bubble.component('text0').textNode.setShadow(0.05, 0.05)
            # self.thought_bubble.component('text0').textNode.setShadowColor(self.thought_filter[layer])
            self.last_thought = 0
        return "success"

    def control__say(self, message="Hello!"):
        self.speech_bubble["text"] = message
        self.last_spoke = 0
        return "success"

    """

    Methods explicitly for IsisScenario files 

    """

    def put_in_front_of(self, isisobj):
        # find open direction
        pos = isisobj.getGeomPos()
        direction = render.getRelativeVector(isisobj, Vec3(0, 1.0, 0))
        closestEntry, closestObject = IsisAgent.physics.doRaycastNew("aimRay", 5, [pos, direction], [isisobj.geom])
        print "CLOSEST", closestEntry, closestObject
        if closestObject == None:
            self.setPosition(pos + Vec3(0, 2, 0))
        else:
            print "CANNOT PLACE IN FRONT OF %s BECAUSE %s IS THERE" % (isisobj, closestObject)
            direction = render.getRelativeVector(isisobj, Vec3(0, -1.0, 0))
            closestEntry, closestObject = IsisAgent.physics.doRaycastNew("aimRay", 5, [pos, direction], [isisobj.geom])
            if closestEntry == None:
                self.setPosition(pos + Vec3(0, -2, 0))
            else:
                print "CANNOT PLACE BEHIND %s BECAUSE %s IS THERE" % (isisobj, closestObject)
                direction = render.getRelativeVector(isisobj, Vec3(1, 0, 0))
                closestEntry, closestObject = IsisAgent.physics.doRaycastNew(
                    "aimRay", 5, [pos, direction], [isisobj.geom]
                )
                if closestEntry == None:
                    self.setPosition(pos + Vec3(2, 0, 0))
                else:
                    print "CANNOT PLACE TO LEFT OF %s BECAUSE %s IS THERE" % (isisobj, closestObject)
                    # there's only one option left, do it anyway
                    self.setPosition(pos + Vec3(-2, 0, 0))
        # rotate agent to look at it
        self.actorNodePath.setPos(self.getGeomPos())
        self.actorNodePath.lookAt(pos)
        self.setH(self.actorNodePath.getH())

    def put_in_right_hand(self, target):
        return self.pick_object_up_with(target, self.right_hand_holding_object, self.player_right_hand)

    def put_in_left_hand(self, target):
        return self.pick_object_up_with(target, self.left_hand_holding_object, self.player_left_hand)

    def __get_object_in_center_of_view(self):
        direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0))
        pos = self.fov.getPos(render)
        exclude = []  # [base.render.find("**/kitchenNode*").getPythonTag("isisobj").geom]
        closestEntry, closestObject = IsisAgent.physics.doRaycastNew("aimRay", 5, [pos, direction], exclude)
        return closestObject

    def pick_object_up_with(self, target, hand_slot, hand_joint):
        """ Attaches an IsisObject, target, to the hand joint.  Does not check anything first,
        other than the fact that the hand joint is not currently holding something else."""
        if hand_slot != None:
            print "already holding " + hand_slot.getName() + "."
            return None
        else:
            if target.layout:
                target.layout.remove(target)
                target.layout = None
            # store original position
            target.originalHpr = target.getHpr(render)
            target.disable()  # turn off physics
            if target.body:
                target.body.setGravityMode(0)
            target.reparentTo(hand_joint)
            target.setPosition(hand_joint.getPos(render))
            target.setTag("heldBy", self.name)
            if hand_joint == self.player_right_hand:
                self.right_hand_holding_object = target
            elif hand_joint == self.player_left_hand:
                self.left_hand_holding_object = target
            hand_slot = target
            return target

    def control__pick_up_with_right_hand(self, target=None):
        if not target:
            target = self.__get_object_in_center_of_view()
            if not target:
                print "no target in reach"
                return "error: no target in reach"
        else:
            target = render.find("**/*" + target + "*").getPythonTag("isisobj")
        print "attempting to pick up " + target.name + " with right hand.\n"
        if self.can_grasp(target):  # object within distance
            return self.pick_object_up_with(target, self.right_hand_holding_object, self.player_right_hand)
        else:
            print "object (" + target.name + ") is not graspable (i.e. in view and close enough)."
            return "error: object not graspable"

    def control__pick_up_with_left_hand(self, target=None):
        if not target:
            target = self.__get_object_in_center_of_view()
            if not target:
                print "no target in reach"
                return
        else:
            target = render.find("**/*" + target + "*").getPythonTag("isisobj")
        print "attempting to pick up " + target.name + " with left hand.\n"
        if self.can_grasp(target):  # object within distance
            return self.pick_object_up_with(target, self.left_hand_holding_object, self.player_left_hand)
        else:
            print "object (" + target.name + ") is not graspable (i.e. in view and close enough)."
            return "error: object not graspable"

    def control__drop_from_right_hand(self):
        print "attempting to drop object from right hand.\n"

        if self.right_hand_holding_object is None:
            print "right hand is not holding an object."
            return False
        if self.right_hand_holding_object.getNetTag("heldBy") == self.name:
            self.right_hand_holding_object.reparentTo(render)
            direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0))
            pos = self.player_right_hand.getPos(render)
            heldPos = self.right_hand_holding_object.geom.getPosition()
            self.right_hand_holding_object.setPosition(pos)
            self.right_hand_holding_object.synchPosQuatToNode()
            self.right_hand_holding_object.setTag("heldBy", "")
            self.right_hand_holding_object.setRotation(self.right_hand_holding_object.originalHpr)
            self.right_hand_holding_object.enable()
            if self.right_hand_holding_object.body:
                quat = self.getQuat()
                # throw object
                force = 5
                self.right_hand_holding_object.body.setGravityMode(1)
                self.right_hand_holding_object.getBody().setForce(quat.xform(Vec3(0, force, 0)))
            self.right_hand_holding_object = None
            return "success"
        else:
            return "Error: not being held by agent %s" % (self.name)

    def control__drop_from_left_hand(self):
        print "attempting to drop object from left hand.\n"
        if self.left_hand_holding_object is None:
            return "left hand is not holding an object."
        if self.left_hand_holding_object.getNetTag("heldBy") == self.name:
            self.left_hand_holding_object.reparentTo(render)
            direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0))
            pos = self.player_left_hand.getPos(render)
            heldPos = self.left_hand_holding_object.geom.getPosition()
            self.left_hand_holding_object.setPosition(pos)
            self.left_hand_holding_object.synchPosQuatToNode()
            self.left_hand_holding_object.setTag("heldBy", "")
            self.left_hand_holding_object.setRotation(self.left_hand_holding_object.originalHpr)
            self.left_hand_holding_object.enable()
            if self.left_hand_holding_object.body:
                quat = self.getQuat()
                # throw object
                force = 5
                self.left_hand_holding_object.body.setGravityMode(1)
                self.left_hand_holding_object.getBody().setForce(quat.xform(Vec3(0, force, 0)))
            self.left_hand_holding_object = None
            return "success"
        else:
            return "Error: not being held by agent %s" % (self.name)

    def control__use_right_hand(self, target=None, action=None):
        # TODO, rename this to use object with
        if not action:
            if self.msg:
                action = self.msg
            else:
                action = "divide"
        if not target:
            target = self.__get_object_in_center_of_view()
            if not target:
                print "no target in reach"
                return
        else:
            target = render.find("**/*" + target + "*").getPythonTag("isisobj")
        print "Trying to use object", target
        if self.can_grasp(target):
            if target.call(self, action, self.right_hand_holding_object) or (
                self.right_hand_holding_object and self.right_hand_holding_object.call(self, action, target)
            ):
                return "success"
            return str(action) + " not associated with either target or object"
        return "target not within reach"

    def control__use_left_hand(self, target=None, action=None):
        if not action:
            if self.msg:
                action = self.msg
            else:
                action = "divide"
        if not target:
            target = self.__get_object_in_center_of_view()
            if not target:
                print "no target in reach"
                return
        else:
            target = render.find("**/*" + target + "*").getPythonTag("isisobj")
        if self.can_grasp(target):
            if target.call(self, action, self.left_hand_holding_object) or (
                self.left_hand_holding_object and self.left_hand_holding_object.call(self, action, target)
            ):
                return "success"
            return str(action) + " not associated with either target or object"
        return "target not within reach"

    def can_grasp(self, isisobject):
        distance = isisobject.activeModel.getDistance(self.fov)
        print "distance = ", distance
        return distance < 5.0

    def is_holding(self, object_name):
        return (
            self.left_hand_holding_object
            and (self.left_hand_holding_object.getPythonTag("isisobj").name == object_name)
        ) or (
            self.right_hand_holding_object
            and (self.right_hand_holding_object.getPythonTag("isisobj").name == object_name)
        )

    def empty_hand(self):
        if self.left_hand_holding_object is None:
            return self.player_left_hand
        elif self.right_hand_holding_object is None:
            return self.player_right_hand
        return False

    def has_empty_hand(self):
        return self.empty_hand() is not False

    def control__use_aimed(self):
        """
        Try to use the object that we aim at, by calling its callback method.
        """
        target = self.__get_object_in_center_of_view()
        if target.selectionCallback:
            target.selectionCallback(self, dir)
        return "success"

    def sense__get_position(self):
        x, y, z = self.actorNodePath.getPos()
        h, p, r = self.actorNodePath.getHpr()
        # FIXME
        # neck is not positioned in Blockman nh,np,nr = self.agents[agent_id].actor_neck.getHpr()
        left_hand_obj = ""
        right_hand_obj = ""
        if self.left_hand_holding_object:
            left_hand_obj = self.left_hand_holding_object.getName()
        if self.right_hand_holding_object:
            right_hand_obj = self.right_hand_holding_object.getName()
        return {
            "body_x": x,
            "body_y": y,
            "body_z": z,
            "body_h": h,
            "body_p": p,
            "body_r": r,
            "in_left_hand": left_hand_obj,
            "in_right_hand": right_hand_obj,
        }

    def sense__get_vision(self):
        self.fov.node().saveScreenshot("temp.jpg")
        image = Image.open("temp.jpg")
        os.remove("temp.jpg")
        return image

    def sense__get_objects(self):
        return dict([x.getName(), y] for (x, y) in self.get_objects_in_field_of_vision().items())

    def sense__get_agents(self):
        curSense = time()
        agents = {}
        for k, v in self.get_agents_in_field_of_vision().items():
            v["actions"] = k.get_other_agents_actions(self.lastSense, curSense)
            agents[k.name] = v
        self.lastSense = curSense
        return agents

    def sense__get_utterances(self):
        """ Clear out the buffer of things that the teacher has typed,
        FIXME: this doesn't work right now """
        return []
        utterances = self.teacher_utterances
        self.teacher_utterances = []
        return utterances

    def debug__print_objects(self):
        text = "Objects in FOV: " + ", ".join(self.sense__get_objects().keys())
        print text

    def add_action_to_history(self, action, args, result=0):
        self.queue.append((time(), action, args, result))
        if len(self.queue) > self.queueSize:
            self.queue.pop(0)

    def get_other_agents_actions(self, start=0, end=None):
        if not end:
            end = time()
        actions = []
        for act in self.queue:
            if act[0] >= start:
                if act[0] < end:
                    actions.append(act)
                else:
                    break
        return actions

    def update(self, stepSize=0.1):
        self.speed = [0.0, 0.0]
        self.actorNodePath.setPos(self.geom.getPosition() + Vec3(0, 0, -0.70))
        self.actorNodePath.setQuat(self.getQuat())
        # the values in self.speeds are used as coefficientes for turns and movements
        if self.controlMap["turn_left"] != 0:
            self.addToH(stepSize * self.speeds[0])
        if self.controlMap["turn_right"] != 0:
            self.addToH(-stepSize * self.speeds[1])
        if self.verticalState == "ground":
            # these actions require contact with the ground
            if self.controlMap["move_forward"] != 0:
                self.speed[1] = self.speeds[2]
            if self.controlMap["move_backward"] != 0:
                self.speed[1] = -self.speeds[3]
            if self.controlMap["move_left"] != 0:
                self.speed[0] = -self.speeds[4]
            if self.controlMap["move_right"] != 0:
                self.speed[0] = self.speeds[5]
            if self.controlMap["jump"] != 0:
                kinematicCharacterController.jump(self)
                # one jump at a time!
                self.controlMap["jump"] = 0
        if self.controlMap["look_left"] != 0:
            self.neck.setR(bound(self.neck.getR(), -60, 60) + stepSize * 80)
        if self.controlMap["look_right"] != 0:
            self.neck.setR(bound(self.neck.getR(), -60, 60) - stepSize * 80)
        if self.controlMap["look_up"] != 0:
            self.neck.setP(bound(self.neck.getP(), -60, 80) + stepSize * 80)
        if self.controlMap["look_down"] != 0:
            self.neck.setP(bound(self.neck.getP(), -60, 80) - stepSize * 80)

        kinematicCharacterController.update(self, stepSize)

        """
        Update the held object position to be in the hands
        """
        if self.right_hand_holding_object != None:
            self.right_hand_holding_object.setPosition(self.player_right_hand.getPos(render))
        if self.left_hand_holding_object != None:
            self.left_hand_holding_object.setPosition(self.player_left_hand.getPos(render))

        # Update the dialog box and thought windows
        # This allows dialogue window to gradually decay (changing transparancy) and then disappear
        self.last_spoke += stepSize / 2
        self.last_thought += stepSize / 2
        self.speech_bubble["text_bg"] = (1, 1, 1, 1 / (self.last_spoke + 0.01))
        self.speech_bubble["frameColor"] = (0.6, 0.2, 0.1, 0.5 / (self.last_spoke + 0.01))
        if self.last_spoke > 2:
            self.speech_bubble["text"] = ""
        if self.last_thought > 1:
            self.thought_bubble.hide()

        # If the character is moving, loop the run animation.
        # If he is standing still, stop the animation.
        if (
            (self.controlMap["move_forward"] != 0)
            or (self.controlMap["move_backward"] != 0)
            or (self.controlMap["move_left"] != 0)
            or (self.controlMap["move_right"] != 0)
        ):
            if self.isMoving is False:
                self.isMoving = True
        else:
            if self.isMoving:
                self.current_frame_count = 5.0
                self.isMoving = False

        total_frame_num = self.actor.getNumFrames("walk")
        if self.isMoving:
            self.current_frame_count = self.current_frame_count + (stepSize * 250.0)
            if self.current_frame_count > total_frame_num:
                self.current_frame_count = self.current_frame_count % total_frame_num
            self.actor.pose("walk", self.current_frame_count)
        elif self.current_frame_count != 0:
            self.current_frame_count = 0
            self.actor.pose("idle", 0)
        return Task.cont

    def destroy(self):
        self.disable()
        self.specialDirectObject.ignoreAll()
        self.actorNodePath.removeNode()
        del self.specialDirectObject

        kinematicCharacterController.destroy(self)

    def disable(self):
        self.isDisabled = True
        self.geom.disable()
        self.footRay.disable()

    def enable(self):
        self.footRay.enable()
        self.geom.enable()
        self.isDisabled = False

    """
    Set camera to correct height above the center of the capsule
    when crouching and when standing up.
    """

    def crouch(self):
        kinematicCharacterController.crouch(self)
        self.camH = self.crouchCamH

    def crouchStop(self):
        """
        Only change the camera's placement when the KCC allows standing up.
        See the KCC to find out why it might not allow it.
        """
        if kinematicCharacterController.crouchStop(self):
            self.camH = self.walkCamH
Beispiel #13
0
class IsisAgent(kinematicCharacterController, DirectObject):
    @classmethod
    def setPhysics(cls, physics):
        """ This method is set in src.loader when the generators are loaded
        into the namespace.  This frees the environment definitions (in 
        scenario files) from having to pass around the physics parameter 
        that is required for all IsisObjects """
        cls.physics = physics

    def __init__(self, name, queueSize=100):

        # load the model and the different animations for the model into an Actor object.
        self.actor = Actor("media/models/boxman", {
            "walk": "media/models/boxman-walk",
            "idle": "media/models/boxman-idle"
        })
        self.actor.setScale(1.0)
        self.actor.setH(0)
        #self.actor.setLODAnimation(10,5,2) # slows animation framerate when actor is far from camera, if you can figure out reasonable params
        self.actor.setColorScale(random.random(), random.random(),
                                 random.random(), 1.0)
        self.actorNodePath = NodePath('agent-%s' % name)
        self.activeModel = self.actorNodePath

        self.actorNodePath.reparentTo(render)

        self.actor.reparentTo(self.actorNodePath)
        self.name = name
        self.isMoving = False

        # initialize ODE controller
        kinematicCharacterController.__init__(self, IsisAgent.physics,
                                              self.actorNodePath)
        self.setGeomPos(self.actorNodePath.getPos(render))
        """
        Additional Direct Object that I use for convenience.
        """
        self.specialDirectObject = DirectObject()
        """
        How high above the center of the capsule you want the camera to be
        when walking and when crouching. It's related to the values in KCC.
        """
        self.walkCamH = 0.7
        self.crouchCamH = 0.2
        self.camH = self.walkCamH
        """
        This tells the Player Controller what we're aiming at.
        """
        self.aimed = None

        self.isSitting = False
        self.isDisabled = False
        """
        The special direct object is used for trigger messages and the like.
        """
        #self.specialDirectObject.accept("ladder_trigger_enter", self.setFly, [True])
        #self.specialDirectObject.accept("ladder_trigger_exit", self.setFly, [False])

        self.actor.makeSubpart("arms", ["LeftShoulder", "RightShoulder"])

        # Expose agent's right hand joint to attach objects to
        self.player_right_hand = self.actor.exposeJoint(
            None, 'modelRoot', 'Hand.R')
        self.player_left_hand = self.actor.exposeJoint(None, 'modelRoot',
                                                       'Hand.L')

        self.right_hand_holding_object = None
        self.left_hand_holding_object = None

        # don't change the color of things you pick up
        self.player_right_hand.setColorScaleOff()
        self.player_left_hand.setColorScaleOff()

        self.player_head = self.actor.exposeJoint(None, 'modelRoot', 'Head')
        self.neck = self.actor.controlJoint(None, 'modelRoot', 'Head')

        self.controlMap = {
            "turn_left": 0,
            "turn_right": 0,
            "move_forward": 0,
            "move_backward": 0,
            "move_right": 0,
            "move_left": 0,
            "look_up": 0,
            "look_down": 0,
            "look_left": 0,
            "look_right": 0,
            "jump": 0
        }
        # see update method for uses, indices are [turn left, turn right, move_forward, move_back, move_right, move_left, look_up, look_down, look_right, look_left]
        # turns are in degrees per second, moves are in units per second
        self.speeds = [270, 270, 5, 5, 5, 5, 60, 60, 60, 60]

        self.originalPos = self.actor.getPos()

        bubble = loader.loadTexture("media/textures/thought_bubble.png")
        #bubble.setTransparency(TransparencyAttrib.MAlpha)

        self.speech_bubble = DirectLabel(parent=self.actor,
                                         text="",
                                         text_wordwrap=10,
                                         pad=(3, 3),
                                         relief=None,
                                         text_scale=(.3, .3),
                                         pos=(0, 0, 3.6),
                                         frameColor=(.6, .2, .1, .5),
                                         textMayChange=1,
                                         text_frame=(0, 0, 0, 1),
                                         text_bg=(1, 1, 1, 1))
        #self.myImage=
        self.speech_bubble.setTransparency(TransparencyAttrib.MAlpha)
        # stop the speech bubble from being colored like the agent
        self.speech_bubble.setColorScaleOff()
        self.speech_bubble.component('text0').textNode.setCardDecal(1)
        self.speech_bubble.setBillboardAxis()
        # hide the speech bubble from IsisAgent's own camera
        self.speech_bubble.hide(BitMask32.bit(1))

        self.thought_bubble = DirectLabel(parent=self.actor,
                                          text="",
                                          text_wordwrap=9,
                                          text_frame=(1, 0, -2, 1),
                                          text_pos=(0, .5),
                                          text_bg=(1, 1, 1, 0),
                                          relief=None,
                                          frameSize=(0, 1.5, -2, 3),
                                          text_scale=(.18, .18),
                                          pos=(0, 0.2, 3.6),
                                          textMayChange=1,
                                          image=bubble,
                                          image_pos=(0, 0.1, 0),
                                          sortOrder=5)
        self.thought_bubble.setTransparency(TransparencyAttrib.MAlpha)
        # stop the speech bubble from being colored like the agent
        self.thought_bubble.setColorScaleOff()
        self.thought_bubble.component('text0').textNode.setFrameColor(
            1, 1, 1, 0)
        self.thought_bubble.component('text0').textNode.setFrameAsMargin(
            0.1, 0.1, 0.1, 0.1)
        self.thought_bubble.component('text0').textNode.setCardDecal(1)
        self.thought_bubble.setBillboardAxis()
        # hide the thought bubble from IsisAgent's own camera
        self.thought_bubble.hide(BitMask32.bit(1))
        # disable by default
        self.thought_bubble.hide()
        self.thought_filter = {}  # only show thoughts whose values are in here
        self.last_spoke = 0  # timers to keep track of last thought/speech and
        self.last_thought = 0  # hide visualizations

        # put a camera on ralph
        self.fov = NodePath(Camera('RaphViz'))
        self.fov.node().setCameraMask(BitMask32.bit(1))

        # position the camera to be infront of Boxman's face.
        self.fov.reparentTo(self.player_head)
        # x,y,z are not in standard orientation when parented to player-Head
        self.fov.setPos(0, 0.2, 0)
        # if P=0, canrea is looking directly up. 90 is back of head. -90 is on face.
        self.fov.setHpr(0, -90, 0)

        lens = self.fov.node().getLens()
        lens.setFov(60)  #  degree field of view (expanded from 40)
        lens.setNear(0.2)
        #self.fov.node().showFrustum() # displays a box around his head
        #self.fov.place()

        self.prevtime = 0
        self.current_frame_count = 0

        self.isSitting = False
        self.isDisabled = False
        self.msg = None
        self.actorNodePath.setPythonTag("agent", self)

        # Initialize the action queue, with a maximum length of queueSize
        self.queue = []
        self.queueSize = queueSize
        self.lastSense = 0

    def setLayout(self, layout):
        """ Dummy method called by spatial methods for use with objects. 
        Doesn't make sense for an agent that can move around."""
        pass

    def setPos(self, pos):
        """ Wrapper to set the position of the ODE geometry, which in turn 
        sets the visual model's geometry the next time the update() method
        is called. """
        self.setGeomPos(pos)

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

    def reparentTo(self, parent):
        self.actorNodePath.reparentTo(parent)

    def setControl(self, control, value):
        """Set the state of one of the character's movement controls.  """
        self.controlMap[control] = value

    def get_objects_in_field_of_vision(self, exclude=['isisobject']):
        """ This works in an x-ray style. Fast. Works best if you listen to
        http://en.wikipedia.org/wiki/Rock_Art_and_the_X-Ray_Style while
        you use it.
        
        needs to exclude isisobjects since they cannot be serialized  
        """
        objects = {}
        for obj in base.render.findAllMatches("**/IsisObject*"):
            if not obj.hasPythonTag("isisobj"):
                continue
            o = obj.getPythonTag("isisobj")
            bounds = o.activeModel.getBounds()
            bounds.xform(o.activeModel.getMat(self.fov))
            if self.fov.node().isInView(o.activeModel.getPos(self.fov)):
                pos = o.activeModel.getPos(render)
                pos = (pos[0], pos[1], pos[2] + o.getHeight() / 2)
                p1 = self.fov.getRelativePoint(render, pos)
                p2 = Point2()
                self.fov.node().getLens().project(p1, p2)
                p3 = aspect2d.getRelativePoint(render2d,
                                               Point3(p2[0], 0, p2[1]))
                object_dict = {}
                if 'x_pos' not in exclude: object_dict['x_pos'] = p3[0]
                if 'y_pos' not in exclude: object_dict['y_pos'] = p3[2]
                if 'distance' not in exclude:
                    object_dict['distance'] = o.activeModel.getDistance(
                        self.fov)
                if 'orientation' not in exclude:
                    object_dict['orientation'] = o.activeModel.getH(self.fov)
                if 'actions' not in exclude:
                    object_dict['actions'] = o.list_actions()
                if 'isisobject' not in exclude: object_dict['isisobject'] = o
                # add item to dinctionary
                objects[o] = object_dict
        return objects

    def get_agents_in_field_of_vision(self):
        """ This works in an x-ray vision style as well"""
        agents = {}
        for agent in base.render.findAllMatches("**/agent-*"):
            if not agent.hasPythonTag("agent"):
                continue
            a = agent.getPythonTag("agent")
            bounds = a.actorNodePath.getBounds()
            bounds.xform(a.actorNodePath.getMat(self.fov))
            pos = a.actorNodePath.getPos(self.fov)
            if self.fov.node().isInView(pos):
                p1 = self.fov.getRelativePoint(render, pos)
                p2 = Point2()
                self.fov.node().getLens().project(p1, p2)
                p3 = aspect2d.getRelativePoint(render2d,
                                               Point3(p2[0], 0, p2[1]))
                agentDict = {'x_pos': p3[0],\
                             'y_pos': p3[2],\
                             'distance':a.actorNodePath.getDistance(self.fov),\
                             'orientation': a.actorNodePath.getH(self.fov)}
                agents[a] = agentDict
        return agents

    def in_view(self, isisobj):
        """ Returns true iff a particular isisobject is in view """
        return len(
            filter(lambda x: x['isisobject'] == isisobj,
                   self.get_objects_in_field_of_vision(exclude=[]).values()))

    def get_objects_in_view(self):
        """ Gets objects through ray tracing.  Slow"""
        return self.picker.get_objects_in_view()

    def control__turn_left__start(self, speed=None):
        self.setControl("turn_left", 1)
        self.setControl("turn_right", 0)
        if speed:
            self.speeds[0] = speed
        return "success"

    def control__turn_left__stop(self):
        self.setControl("turn_left", 0)
        return "success"

    def control__turn_right__start(self, speed=None):
        self.setControl("turn_left", 0)
        self.setControl("turn_right", 1)
        if speed:
            self.speeds[1] = speed
        return "success"

    def control__turn_right__stop(self):
        self.setControl("turn_right", 0)
        return "success"

    def control__move_forward__start(self, speed=None):
        self.setControl("move_forward", 1)
        self.setControl("move_backward", 0)
        if speed:
            self.speeds[2] = speed
        return "success"

    def control__move_forward__stop(self):
        self.setControl("move_forward", 0)
        return "success"

    def control__move_backward__start(self, speed=None):
        self.setControl("move_forward", 0)
        self.setControl("move_backward", 1)
        if speed:
            self.speeds[3] = speed
        return "success"

    def control__move_backward__stop(self):
        self.setControl("move_backward", 0)
        return "success"

    def control__move_left__start(self, speed=None):
        self.setControl("move_left", 1)
        self.setControl("move_right", 0)
        if speed:
            self.speeds[4] = speed
        return "success"

    def control__move_left__stop(self):
        self.setControl("move_left", 0)
        return "success"

    def control__move_right__start(self, speed=None):
        self.setControl("move_right", 1)
        self.setControl("move_left", 0)
        if speed:
            self.speeds[5] = speed
        return "success"

    def control__move_right__stop(self):
        self.setControl("move_right", 0)
        return "success"

    def control__look_left__start(self, speed=None):
        self.setControl("look_left", 1)
        self.setControl("look_right", 0)
        if speed:
            self.speeds[9] = speed
        return "success"

    def control__look_left__stop(self):
        self.setControl("look_left", 0)
        return "success"

    def control__look_right__start(self, speed=None):
        self.setControl("look_right", 1)
        self.setControl("look_left", 0)
        if speed:
            self.speeds[8] = speed
        return "success"

    def control__look_right__stop(self):
        self.setControl("look_right", 0)
        return "success"

    def control__look_up__start(self, speed=None):
        self.setControl("look_up", 1)
        self.setControl("look_down", 0)
        if speed:
            self.speeds[6] = speed
        return "success"

    def control__look_up__stop(self):
        self.setControl("look_up", 0)
        return "success"

    def control__look_down__start(self, speed=None):
        self.setControl("look_down", 1)
        self.setControl("look_up", 0)
        if speed:
            self.speeds[7] = speed
        return "success"

    def control__look_down__stop(self):
        self.setControl("look_down", 0)
        return "success"

    def control__jump(self):
        self.setControl("jump", 1)
        return "success"

    def control__view_objects(self):
        """ calls a raytrace to to all objects in view """
        objects = self.get_objects_in_field_of_vision()
        self.control__say(
            "If I were wearing x-ray glasses, I could see %i items" %
            len(objects))
        print "Objects in view:", objects
        return objects

    def control__sense(self):
        """ perceives the world, returns percepts dict """
        percepts = dict()
        # eyes: visual matricies
        #percepts['vision'] = self.sense__get_vision()
        # objects in purview (cheating object recognition)
        percepts['objects'] = self.sense__get_objects()
        # global position in environment - our robots can have GPS :)
        percepts['position'] = self.sense__get_position()
        # language: get last utterances that were typed
        percepts['language'] = self.sense__get_utterances()
        # agents: returns a map of agents to a list of actions that have been sensed
        percepts['agents'] = self.sense__get_agents()
        print percepts
        return percepts

    def control__think(self, message, layer=0):
        """ Changes the contents of an agent's thought bubble"""
        # only say things that are checked in the controller
        if self.thought_filter.has_key(layer):
            self.thought_bubble.show()
            self.thought_bubble['text'] = message
            #self.thought_bubble.component('text0').textNode.setShadow(0.05, 0.05)
            #self.thought_bubble.component('text0').textNode.setShadowColor(self.thought_filter[layer])
            self.last_thought = 0
        return "success"

    def control__say(self, message="Hello!"):
        self.speech_bubble['text'] = message
        self.last_spoke = 0
        return "success"

    """

    Methods explicitly for IsisScenario files 

    """

    def put_in_front_of(self, isisobj):
        # find open direction
        pos = isisobj.getGeomPos()
        direction = render.getRelativeVector(isisobj, Vec3(0, 1.0, 0))
        closestEntry, closestObject = IsisAgent.physics.doRaycastNew(
            'aimRay', 5, [pos, direction], [isisobj.geom])
        print "CLOSEST", closestEntry, closestObject
        if closestObject == None:
            self.setPosition(pos + Vec3(0, 2, 0))
        else:
            print "CANNOT PLACE IN FRONT OF %s BECAUSE %s IS THERE" % (
                isisobj, closestObject)
            direction = render.getRelativeVector(isisobj, Vec3(0, -1.0, 0))
            closestEntry, closestObject = IsisAgent.physics.doRaycastNew(
                'aimRay', 5, [pos, direction], [isisobj.geom])
            if closestEntry == None:
                self.setPosition(pos + Vec3(0, -2, 0))
            else:
                print "CANNOT PLACE BEHIND %s BECAUSE %s IS THERE" % (
                    isisobj, closestObject)
                direction = render.getRelativeVector(isisobj, Vec3(1, 0, 0))
                closestEntry, closestObject = IsisAgent.physics.doRaycastNew(
                    'aimRay', 5, [pos, direction], [isisobj.geom])
                if closestEntry == None:
                    self.setPosition(pos + Vec3(2, 0, 0))
                else:
                    print "CANNOT PLACE TO LEFT OF %s BECAUSE %s IS THERE" % (
                        isisobj, closestObject)
                    # there's only one option left, do it anyway
                    self.setPosition(pos + Vec3(-2, 0, 0))
        # rotate agent to look at it
        self.actorNodePath.setPos(self.getGeomPos())
        self.actorNodePath.lookAt(pos)
        self.setH(self.actorNodePath.getH())

    def put_in_right_hand(self, target):
        return self.pick_object_up_with(target, self.right_hand_holding_object,
                                        self.player_right_hand)

    def put_in_left_hand(self, target):
        return self.pick_object_up_with(target, self.left_hand_holding_object,
                                        self.player_left_hand)

    def __get_object_in_center_of_view(self):
        direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0))
        pos = self.fov.getPos(render)
        exclude = [
        ]  #[base.render.find("**/kitchenNode*").getPythonTag("isisobj").geom]
        closestEntry, closestObject = IsisAgent.physics.doRaycastNew(
            'aimRay', 5, [pos, direction], exclude)
        return closestObject

    def pick_object_up_with(self, target, hand_slot, hand_joint):
        """ Attaches an IsisObject, target, to the hand joint.  Does not check anything first,
        other than the fact that the hand joint is not currently holding something else."""
        if hand_slot != None:
            print 'already holding ' + hand_slot.getName() + '.'
            return None
        else:
            if target.layout:
                target.layout.remove(target)
                target.layout = None
            # store original position
            target.originalHpr = target.getHpr(render)
            target.disable()  #turn off physics
            if target.body: target.body.setGravityMode(0)
            target.reparentTo(hand_joint)
            target.setPosition(hand_joint.getPos(render))
            target.setTag('heldBy', self.name)
            if hand_joint == self.player_right_hand:
                self.right_hand_holding_object = target
            elif hand_joint == self.player_left_hand:
                self.left_hand_holding_object = target
            hand_slot = target
            return target

    def control__pick_up_with_right_hand(self, target=None):
        if not target:
            target = self.__get_object_in_center_of_view()
            if not target:
                print "no target in reach"
                return "error: no target in reach"
        else:
            target = render.find("**/*" + target + "*").getPythonTag("isisobj")
        print "attempting to pick up " + target.name + " with right hand.\n"
        if self.can_grasp(target):  # object within distance
            return self.pick_object_up_with(target,
                                            self.right_hand_holding_object,
                                            self.player_right_hand)
        else:
            print 'object (' + target.name + ') is not graspable (i.e. in view and close enough).'
            return 'error: object not graspable'

    def control__pick_up_with_left_hand(self, target=None):
        if not target:
            target = self.__get_object_in_center_of_view()
            if not target:
                print "no target in reach"
                return
        else:
            target = render.find("**/*" + target + "*").getPythonTag("isisobj")
        print "attempting to pick up " + target.name + " with left hand.\n"
        if self.can_grasp(target):  # object within distance
            return self.pick_object_up_with(target,
                                            self.left_hand_holding_object,
                                            self.player_left_hand)
        else:
            print 'object (' + target.name + ') is not graspable (i.e. in view and close enough).'
            return 'error: object not graspable'

    def control__drop_from_right_hand(self):
        print "attempting to drop object from right hand.\n"

        if self.right_hand_holding_object is None:
            print 'right hand is not holding an object.'
            return False
        if self.right_hand_holding_object.getNetTag('heldBy') == self.name:
            self.right_hand_holding_object.reparentTo(render)
            direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0))
            pos = self.player_right_hand.getPos(render)
            heldPos = self.right_hand_holding_object.geom.getPosition()
            self.right_hand_holding_object.setPosition(pos)
            self.right_hand_holding_object.synchPosQuatToNode()
            self.right_hand_holding_object.setTag('heldBy', '')
            self.right_hand_holding_object.setRotation(
                self.right_hand_holding_object.originalHpr)
            self.right_hand_holding_object.enable()
            if self.right_hand_holding_object.body:
                quat = self.getQuat()
                # throw object
                force = 5
                self.right_hand_holding_object.body.setGravityMode(1)
                self.right_hand_holding_object.getBody().setForce(
                    quat.xform(Vec3(0, force, 0)))
            self.right_hand_holding_object = None
            return 'success'
        else:
            return "Error: not being held by agent %s" % (self.name)

    def control__drop_from_left_hand(self):
        print "attempting to drop object from left hand.\n"
        if self.left_hand_holding_object is None:
            return 'left hand is not holding an object.'
        if self.left_hand_holding_object.getNetTag('heldBy') == self.name:
            self.left_hand_holding_object.reparentTo(render)
            direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0))
            pos = self.player_left_hand.getPos(render)
            heldPos = self.left_hand_holding_object.geom.getPosition()
            self.left_hand_holding_object.setPosition(pos)
            self.left_hand_holding_object.synchPosQuatToNode()
            self.left_hand_holding_object.setTag('heldBy', '')
            self.left_hand_holding_object.setRotation(
                self.left_hand_holding_object.originalHpr)
            self.left_hand_holding_object.enable()
            if self.left_hand_holding_object.body:
                quat = self.getQuat()
                # throw object
                force = 5
                self.left_hand_holding_object.body.setGravityMode(1)
                self.left_hand_holding_object.getBody().setForce(
                    quat.xform(Vec3(0, force, 0)))
            self.left_hand_holding_object = None
            return 'success'
        else:
            return "Error: not being held by agent %s" % (self.name)

    def control__use_right_hand(self, target=None, action=None):
        # TODO, rename this to use object with
        if not action:
            if self.msg:
                action = self.msg
            else:
                action = "divide"
        if not target:
            target = self.__get_object_in_center_of_view()
            if not target:
                print "no target in reach"
                return
        else:
            target = render.find("**/*" + target + "*").getPythonTag('isisobj')
        print "Trying to use object", target
        if self.can_grasp(target):
            if (target.call(self, action, self.right_hand_holding_object) or
                (self.right_hand_holding_object and
                 self.right_hand_holding_object.call(self, action, target))):
                return "success"
            return str(action) + " not associated with either target or object"
        return "target not within reach"

    def control__use_left_hand(self, target=None, action=None):
        if not action:
            if self.msg:
                action = self.msg
            else:
                action = "divide"
        if not target:
            target = self.__get_object_in_center_of_view()
            if not target:
                print "no target in reach"
                return
        else:
            target = render.find("**/*" + target + "*").getPythonTag('isisobj')
        if self.can_grasp(target):
            if (target.call(self, action, self.left_hand_holding_object) or
                (self.left_hand_holding_object and
                 self.left_hand_holding_object.call(self, action, target))):
                return "success"
            return str(action) + " not associated with either target or object"
        return "target not within reach"

    def can_grasp(self, isisobject):
        distance = isisobject.activeModel.getDistance(self.fov)
        print "distance = ", distance
        return distance < 5.0

    def is_holding(self, object_name):
        return ((self.left_hand_holding_object and (self.left_hand_holding_object.getPythonTag('isisobj').name  == object_name)) \
             or (self.right_hand_holding_object and (self.right_hand_holding_object.getPythonTag('isisobj').name == object_name)))

    def empty_hand(self):
        if (self.left_hand_holding_object is None):
            return self.player_left_hand
        elif (self.right_hand_holding_object is None):
            return self.player_right_hand
        return False

    def has_empty_hand(self):
        return (self.empty_hand() is not False)

    def control__use_aimed(self):
        """
        Try to use the object that we aim at, by calling its callback method.
        """
        target = self.__get_object_in_center_of_view()
        if target.selectionCallback:
            target.selectionCallback(self, dir)
        return "success"

    def sense__get_position(self):
        x, y, z = self.actorNodePath.getPos()
        h, p, r = self.actorNodePath.getHpr()
        #FIXME
        # neck is not positioned in Blockman nh,np,nr = self.agents[agent_id].actor_neck.getHpr()
        left_hand_obj = ""
        right_hand_obj = ""
        if self.left_hand_holding_object:
            left_hand_obj = self.left_hand_holding_object.getName()
        if self.right_hand_holding_object:
            right_hand_obj = self.right_hand_holding_object.getName()
        return {'body_x': x, 'body_y': y, 'body_z': z,'body_h':h,\
                'body_p': p, 'body_r': r,  'in_left_hand': left_hand_obj, 'in_right_hand':right_hand_obj}

    def sense__get_vision(self):
        self.fov.node().saveScreenshot("temp.jpg")
        image = Image.open("temp.jpg")
        os.remove("temp.jpg")
        return image

    def sense__get_objects(self):
        return dict([x.getName(), y]
                    for (x,
                         y) in self.get_objects_in_field_of_vision().items())

    def sense__get_agents(self):
        curSense = time()
        agents = {}
        for k, v in self.get_agents_in_field_of_vision().items():
            v['actions'] = k.get_other_agents_actions(self.lastSense, curSense)
            agents[k.name] = v
        self.lastSense = curSense
        return agents

    def sense__get_utterances(self):
        """ Clear out the buffer of things that the teacher has typed,
        FIXME: this doesn't work right now """
        return []
        utterances = self.teacher_utterances
        self.teacher_utterances = []
        return utterances

    def debug__print_objects(self):
        text = "Objects in FOV: " + ", ".join(self.sense__get_objects().keys())
        print text

    def add_action_to_history(self, action, args, result=0):
        self.queue.append((time(), action, args, result))
        if len(self.queue) > self.queueSize:
            self.queue.pop(0)

    def get_other_agents_actions(self, start=0, end=None):
        if not end:
            end = time()
        actions = []
        for act in self.queue:
            if act[0] >= start:
                if act[0] < end:
                    actions.append(act)
                else:
                    break
        return actions

    def update(self, stepSize=0.1):
        self.speed = [0.0, 0.0]
        self.actorNodePath.setPos(self.geom.getPosition() + Vec3(0, 0, -0.70))
        self.actorNodePath.setQuat(self.getQuat())
        # the values in self.speeds are used as coefficientes for turns and movements
        if (self.controlMap["turn_left"] != 0):
            self.addToH(stepSize * self.speeds[0])
        if (self.controlMap["turn_right"] != 0):
            self.addToH(-stepSize * self.speeds[1])
        if self.verticalState == 'ground':
            # these actions require contact with the ground
            if (self.controlMap["move_forward"] != 0):
                self.speed[1] = self.speeds[2]
            if (self.controlMap["move_backward"] != 0):
                self.speed[1] = -self.speeds[3]
            if (self.controlMap["move_left"] != 0):
                self.speed[0] = -self.speeds[4]
            if (self.controlMap["move_right"] != 0):
                self.speed[0] = self.speeds[5]
            if (self.controlMap["jump"] != 0):
                kinematicCharacterController.jump(self)
                # one jump at a time!
                self.controlMap["jump"] = 0
        if (self.controlMap["look_left"] != 0):
            self.neck.setR(bound(self.neck.getR(), -60, 60) + stepSize * 80)
        if (self.controlMap["look_right"] != 0):
            self.neck.setR(bound(self.neck.getR(), -60, 60) - stepSize * 80)
        if (self.controlMap["look_up"] != 0):
            self.neck.setP(bound(self.neck.getP(), -60, 80) + stepSize * 80)
        if (self.controlMap["look_down"] != 0):
            self.neck.setP(bound(self.neck.getP(), -60, 80) - stepSize * 80)

        kinematicCharacterController.update(self, stepSize)
        """
        Update the held object position to be in the hands
        """
        if self.right_hand_holding_object != None:
            self.right_hand_holding_object.setPosition(
                self.player_right_hand.getPos(render))
        if self.left_hand_holding_object != None:
            self.left_hand_holding_object.setPosition(
                self.player_left_hand.getPos(render))

        #Update the dialog box and thought windows
        #This allows dialogue window to gradually decay (changing transparancy) and then disappear
        self.last_spoke += stepSize / 2
        self.last_thought += stepSize / 2
        self.speech_bubble['text_bg'] = (1, 1, 1, 1 / (self.last_spoke + 0.01))
        self.speech_bubble['frameColor'] = (.6, .2, .1,
                                            .5 / (self.last_spoke + 0.01))
        if self.last_spoke > 2:
            self.speech_bubble['text'] = ""
        if self.last_thought > 1:
            self.thought_bubble.hide()

        # If the character is moving, loop the run animation.
        # If he is standing still, stop the animation.
        if (self.controlMap["move_forward"] !=
                0) or (self.controlMap["move_backward"] !=
                       0) or (self.controlMap["move_left"] !=
                              0) or (self.controlMap["move_right"] != 0):
            if self.isMoving is False:
                self.isMoving = True
        else:
            if self.isMoving:
                self.current_frame_count = 5.0
                self.isMoving = False

        total_frame_num = self.actor.getNumFrames('walk')
        if self.isMoving:
            self.current_frame_count = self.current_frame_count + (stepSize *
                                                                   250.0)
            if self.current_frame_count > total_frame_num:
                self.current_frame_count = self.current_frame_count % total_frame_num
            self.actor.pose('walk', self.current_frame_count)
        elif self.current_frame_count != 0:
            self.current_frame_count = 0
            self.actor.pose('idle', 0)
        return Task.cont

    def destroy(self):
        self.disable()
        self.specialDirectObject.ignoreAll()
        self.actorNodePath.removeNode()
        del self.specialDirectObject

        kinematicCharacterController.destroy(self)

    def disable(self):
        self.isDisabled = True
        self.geom.disable()
        self.footRay.disable()

    def enable(self):
        self.footRay.enable()
        self.geom.enable()
        self.isDisabled = False

    """
    Set camera to correct height above the center of the capsule
    when crouching and when standing up.
    """

    def crouch(self):
        kinematicCharacterController.crouch(self)
        self.camH = self.crouchCamH

    def crouchStop(self):
        """
        Only change the camera's placement when the KCC allows standing up.
        See the KCC to find out why it might not allow it.
        """
        if kinematicCharacterController.crouchStop(self):
            self.camH = self.walkCamH