コード例 #1
0
class FactorySneakGuardSuit(Suit, FSM):
    notify = directNotify.newCategory('FactorySneakGuardSuit')
    SUIT = 'mrhollywood'
    VIEW_DISTANCE_TASK_NAME = 'ViewDistanceTask'
    MAX_VIEW_DISTANCE = 100.0
    GUARD_DIED_DELAY = 6.0
    MAX_HP = 200
    PROWLER_DISTANCE = 40.0
    IN_VIEW = 'somethingInSight'
    HEARD = 'heard'
    TRY_TO_CONFIRM_TIME = 5.0

    def __init__(self, world, guardKey):
        Suit.__init__(self)
        FSM.__init__(self, 'FactorySneakGuardSuit')
        self.gameWorld = world
        self.guardKey = guardKey
        self.viewDistanceTaskName = self.VIEW_DISTANCE_TASK_NAME + '-' + str(
            id(self))
        self.diedTaskName = 'GuardDied-' + str(id(self))
        self.health = 0
        self.maxHealth = self.MAX_HP
        self.eyeLight = None
        self.eyeLens = None
        self.eyeNode = None
        self.moveTrack = None
        self.trav = None
        self.rayNP = None
        self.queue = None
        self.currentKey = self.guardKey
        self.firstPoint = CGG.GuardPointData[self.guardKey]
        self.walkTrack = None
        self.pathQueue = []
        self.currentPathIndex = 0
        return

    def enterGuard(self):
        self.loop('neutral')
        pos, hpr = CGG.FactoryGuardPoints[self.guardKey]
        self.setHpr(hpr - (180, 0, 0))
        self.setPos(pos)
        base.taskMgr.add(self.__guard, self.taskName('guard'))

    def __checkToon(self):
        self.rayNP.lookAt(base.localAvatar)
        self.trav.traverse(render)
        if self.queue.getNumEntries() > 0:
            self.queue.sortEntries()
            hitObj = self.queue.getEntry(0).getIntoNodePath()
            print hitObj
            isLocalAvatar = hitObj.getParent().getPythonTag('localAvatar')
            if isLocalAvatar == 1:
                return 1
        return 0

    def __guard(self, task):
        if self.eyeNode.node().isInView(base.localAvatar.getPos(
                self.eyeNode)) and self.getDistance(
                    base.localAvatar) <= self.PROWLER_DISTANCE:
            if self.__checkToon():
                self.request('SeekTarget', self.IN_VIEW)
                return task.done
        return task.cont

    def exitGuard(self):
        base.taskMgr.remove(self.taskName('guard'))

    def enterTurnToGuardSpot(self):
        self.loop('walk')
        _, hpr = CGG.FactoryGuardPoints[self.guardKey]
        self.moveTrack = LerpHprInterval(self,
                                         duration=1.0,
                                         hpr=hpr,
                                         startHpr=self.getHpr())
        self.moveTrack.setDoneEvent(self.uniqueName('TurnedToGuardSpot'))
        self.acceptOnce(self.moveTrack.getDoneEvent(), self.request, ['Guard'])
        self.moveTrack.start()

    def exitTurnToGuardSpot(self):
        if self.moveTrack:
            self.ignore(self.moveTrack.getDoneEvent())
            self.moveTrack.finish()
            self.moveTrack = None
        return

    def enterSeekTarget(self, event):
        dialogue = random.choice(CGG.GuardDialog[event])
        self.setChat(dialogue)
        self.loop('walk')
        self.moveTrack = NPCLookInterval(self, base.localAvatar)
        self.moveTrack.setDoneEvent(self.uniqueName('SeekLocalAvatar'))
        self.acceptOnce(self.moveTrack.getDoneEvent(), self.request,
                        ['TryToConfirmTarget'])
        self.moveTrack.start()

    def exitSeekTarget(self):
        if self.moveTrack:
            self.ignore(self.moveTrack.getDoneEvent())
            self.moveTrack.finish()
            self.moveTrack = None
        return

    def enterTryToConfirmTarget(self):
        self.loop('neutral')
        base.taskMgr.add(self.__tryToConfirmTarget,
                         self.uniqueName('TryToConfirmTarget'))

    def __tryToConfirmTarget(self, task):
        if task.time >= self.TRY_TO_CONFIRM_TIME:
            chat = random.choice(CGG.GuardDialog['disregard'])
            self.setChat(chat)
            self.request('TurnToGuardSpot')
            return task.done
        if self.eyeNode.node().isInView(base.localAvatar.getPos(
                self.eyeNode)) and self.getDistance(
                    base.localAvatar) <= self.PROWLER_DISTANCE:
            if self.__checkToon():
                chat = random.choice(CGG.GuardDialog['spot'])
                self.setChat(chat)
                self.request('Pursue')
                return task.done
        return task.cont

    def exitTryToConfirmTarget(self):
        base.taskMgr.remove(self.uniqueName('TryToConfirmTarget'))

    def enterGoBackToGuardSpot(self):
        self.walkBackToGuardSpot()

    def walkBackToGuardSpot(self):
        self.currentPathIndex = 0
        self.pathQueue = SuitPathFinder.find_path(CGG.FactoryWalkPoints,
                                                  CGG.FactoryWayPointData,
                                                  self.currentKey,
                                                  self.guardKey)
        self.currentKey = self.guardKey
        self.walk(0.2)
        self.loop('walk')

    def exitGoBackToGuardSpot(self):
        pass

    def enterPursue(self):
        self.numTries = 0
        self.maxTries = 3
        self.runToClosestPoint()
        self.setPlayRate(1.5, 'walk')
        self.loop('walk')
        messenger.send('guardPursue')

    def getClosestPoint(self):
        closestPoint = None
        pointKey2range = {}
        for key, point in CGG.FactoryWalkPoints.items():
            dummyNode = render.attachNewNode('dummyNode')
            dummyNode.setPos(point)
            pointKey2range[key] = base.localAvatar.getDistance(dummyNode)
            dummyNode.removeNode()

        ranges = []
        for distance in pointKey2range.values():
            ranges.append(distance)

        ranges.sort()
        for key in pointKey2range.keys():
            distance = pointKey2range[key]
            if distance == ranges[0]:
                closestPoint = key
                break

        return closestPoint

    def runToClosestPoint(self):
        self.numTries += 1
        closestPoint = self.getClosestPoint()
        self.currentPathIndex = 0
        startKey = None
        if self.currentKey == self.guardKey and self.firstPoint in CGG.GuardPointData:
            startKey = CGG.GuardPointData[self.firstPoint]
        else:
            startKey = self.currentKey
        self.pathQueue = SuitPathFinder.find_path(CGG.FactoryWalkPoints,
                                                  CGG.FactoryWayPointData,
                                                  startKey, closestPoint)
        if self.currentKey == self.guardKey:
            self.pathQueue.insert(0, 1)
        else:
            self.pathQueue.insert(0, 0)
        self.currentKey = closestPoint
        self.walk(0.1)
        return

    def walk(self, speed=0.2):
        self.currentPathIndex += 1
        if len(self.pathQueue) <= self.currentPathIndex:
            if self.getCurrentOrNextState() == 'Pursue':
                if self.getClosestPoint() != self.currentKey:
                    if self.numTries >= self.maxTries:
                        self.request('GoBackToGuardSpot')
                    else:
                        self.runToClosestPoint()
            else:
                if self.getCurrentOrNextState() == 'GoBackToGuardSpot':
                    self.request('Guard')
            return
        print self.pathQueue[self.currentPathIndex]
        if self.currentPathIndex == 1 and self.pathQueue[0] == 1:
            startPoint = self.getPos(render)
            endPoint = CGG.FactoryWalkPoints[self.firstPoint]
        else:
            if self.pathQueue[0] == 0:
                self.pathQueue.remove(self.pathQueue[0])
            key = self.pathQueue[self.currentPathIndex]
            endPoint = CGG.FactoryWalkPoints[key]
            oldKey = self.pathQueue[self.currentPathIndex - 1]
            startPoint = CGG.FactoryWalkPoints[oldKey]
        self.walkTrack = NPCWalkInterval(self, endPoint, speed, startPoint)
        self.walkTrack.setDoneEvent(self.uniqueName('guardWalkDone'))
        self.acceptOnce(self.uniqueName('guardWalkDone'), self.walk)
        self.walkTrack.start()

    def exitPursue(self):
        self.setPlayRate(1.0, 'walk')
        del self.numTries
        if self.walkTrack:
            self.ignore(self.walkTrack.getDoneEvent())
            self.walkTrack.pause()
            self.walkTrack = None
        messenger.send('guardStopPursue')
        return

    def uniqueName(self, name):
        return self.taskName(name)

    def taskName(self, name):
        return name + '-' + str(id(self))

    def setHealth(self, hp):
        self.health = hp

    def getHealth(self):
        return self.health

    def shot(self):
        dialogue = random.choice(CGG.GuardDialog['shot'])
        self.setChat(dialogue)

    def dead(self):
        self.request('Off')
        self.animFSM.request('die')
        base.taskMgr.doMethodLater(self.GUARD_DIED_DELAY, self.__diedDone,
                                   self.diedTaskName)

    def __diedDone(self, task):
        self.gameWorld.deleteGuard(self)
        return task.done

    def generate(self):
        data = CIGlobals.SuitBodyData[self.SUIT]
        type = data[0]
        team = data[1]
        self.team = team
        self.level = 12
        self.suit = type
        Suit.generate(self, SuitBank.MrHollywood, 0, hideFirst=False)
        self.suit = type
        base.taskMgr.add(self.__viewDistance, self.viewDistanceTaskName)
        self.setPythonTag('guard', self)
        self.eyeLight = Spotlight('eyes')
        self.eyeLens = PerspectiveLens()
        self.eyeLens.setMinFov(90.0 / (4.0 / 3.0))
        self.eyeLight.setLens(self.eyeLens)
        self.eyeNode = self.headModel.attachNewNode(self.eyeLight)
        self.eyeNode.setZ(-5)
        self.eyeNode.setY(-4.5)
        self.trav = CollisionTraverser(self.uniqueName('eyeTrav'))
        ray = CollisionRay(0, 0, 0, 0, 1, 0)
        rayNode = CollisionNode('ToonFPS.rayNode')
        rayNode.addSolid(ray)
        rayNode.setFromCollideMask(CGG.GuardBitmask | CIGlobals.WallBitmask)
        rayNode.setIntoCollideMask(BitMask32.allOff())
        self.rayNP = base.camera.attachNewNode(rayNode)
        self.rayNP.setZ(3)
        self.queue = CollisionHandlerQueue()
        self.trav.addCollider(self.rayNP, self.queue)
        self.trav.addCollider(self.gameWorld.mg.avatarBody, self.queue)
        self.request('Guard')

    def __viewDistance(self, task):
        if self.getDistance(base.localAvatar) > self.MAX_VIEW_DISTANCE:
            if not self.isHidden():
                self.hide()
        else:
            if self.isHidden():
                self.show()
        task.delayTime = 1.0
        return task.again

    def disable(self):
        self.request('Off')
        base.taskMgr.remove(self.taskName('guard'))
        base.taskMgr.remove(self.diedTaskName)
        base.taskMgr.remove(self.viewDistanceTaskName)
        self.trav = None
        if self.rayNP:
            self.rayNP.removeNode()
            self.rayNP = None
        self.queue = None
        self.currentPathIndex = None
        if self.eyeNode:
            self.eyeNode.removeNode()
            self.eyeNode = None
            self.eyeLens = None
            self.eyeLight = None
        self.viewDistanceTaskName = None
        self.guardKey = None
        self.gameWorld = None
        self.pathQueue = None
        if self.walkTrack:
            self.ignore(self.walkTrack.getDoneEvent())
            self.walkTrack.finish()
            self.walkTrack = None
        Suit.disable(self)
        return
コード例 #2
0
class DistributedDeliveryGameSuitAI(DistributedSuitAI):
    notify = directNotify.newCategory('DistributedDeliveryGameSuitAI')

    def __init__(self, air, mg):
        DistributedSuitAI.__init__(self, air)
        self.mg = mg
        self.truck = random.choice(self.mg.trucks)
        self.truckIndex = self.mg.trucks.index(self.truck)
        self.spawnPoint = None
        return

    def walkToTruck(self):
        index = DGG.WalkToTruckIndex
        pos = DGG.TruckSuitPointsByIndex[self.truckIndex]
        startPos = self.getPos(render)
        self.b_setSuitState(1, -1, index)
        durationFactor = 0.2
        pathName = self.uniqueName('WalkToTruck')
        self.walkTrack = NPCWalkInterval(self, pos, startPos=startPos, name=pathName, durationFactor=durationFactor, fluid=1)
        self.walkTrack.setDoneEvent(self.walkTrack.getName())
        self.acceptOnce(self.walkTrack.getDoneEvent(), self.__walkedToTruck)
        self.walkTrack.start()
        self.b_setAnimState(SuitGlobals.getAnimId(SuitGlobals.getAnimByName('walk')))

    def __walkedToTruck(self):
        self.truck.suitPickUpBarrel(self.doId)
        self.walkBackToSpawnPointWithBarrel()

    def walkBackToSpawnPointWithBarrel(self):
        pos = DGG.SpawnPoints[self.spawnPoint]
        startPos = self.getPos(render)
        self.b_setSuitState(1, -1, self.spawnPoint)
        durationFactor = 0.2
        pathName = self.uniqueName('WalkBackToSpawn')
        self.walkTrack = NPCWalkInterval(self, pos, startPos=startPos, name=pathName, durationFactor=durationFactor, fluid=1)
        self.walkTrack.setDoneEvent(self.walkTrack.getName())
        self.acceptOnce(self.walkTrack.getDoneEvent(), self.__walkedBack2Spawn)
        self.walkTrack.start()
        self.b_setAnimState(SuitGlobals.getAnimId(SuitGlobals.getAnimByName('tray-walk')))

    def __walkedBack2Spawn(self):
        self.b_setSuitState(3, self.spawnPoint, self.spawnPoint)
        base.taskMgr.doMethodLater(10, self.__finished, self.uniqueName('finishSuit'))

    def __finished(self, task):
        self.mg.suits.remove(self)
        self.truck.barrelDroppedOff()
        self.requestDelete()
        return task.done

    def spawn(self):
        pos = random.choice(DGG.SpawnPoints)
        index = DGG.SpawnPoints.index(pos)
        self.spawnPoint = index
        self.b_setSuitState(2, index, index)
        flyTrack = self.posInterval(3, pos, startPos=pos + (0, 0, 50))
        flyTrack.start()
        self.track = Sequence()
        self.track.append(Wait(5.4))
        self.track.append(Func(self.b_setAnimState, 'neutral'))
        self.track.append(Wait(1.0))
        self.track.append(Func(self.walkToTruck))
        self.track.start()
        self.b_setParent(CIGlobals.SPRender)

    def delete(self):
        base.taskMgr.remove(self.uniqueName('finishSuit'))
        if hasattr(self, 'walkTrack') and self.walkTrack:
            self.ignore(self.walkTrack.getDoneEvent())
            self.walkTrack.finish()
            self.walkTrack = None
        self.mg = None
        self.truck = None
        self.truckIndex = None
        self.spawnPoint = None
        DistributedSuitAI.delete(self)
        return
コード例 #3
0
class DistributedSuitAI(DistributedAvatarAI, DistributedSmoothNodeAI):
    notify = directNotify.newCategory("DistributedSuitAI")

    def __init__(self, air):
        try:
            self.DistributedSuitAI_initialized
            return
        except:
            self.DistributedSuitAI_initialized = 1
        DistributedAvatarAI.__init__(self, air)
        DistributedSmoothNodeAI.__init__(self, air)
        self.itemDropper = SuitItemDropper(self)
        self.avatarType = CIGlobals.Suit
        self.aiChar = None
        self.aiBehaviors = None
        self.walkTrack = None
        self.name = ""
        self.anim = "neutral"
        self.state = "alive"
        self.damage = 0
        self.health = 132
        self.type = "A"
        self.team = "c"
        self.head = "bigcheese"
        self.name = "The Big Cheese"
        self.skeleton = 0
        self.dmg_lbl = None
        self.lbl_int = None
        self.bean = None
        self.boss = None
        self.brain = None
        self.startPoint = -1
        self.endPoint = -1
        self.suitState = 0
        self.walkPaused = 0
        self.attacking = False
        self.suitHealTrack = None
        self.continuePathId = 0
        self.attackId = 0
        self.mgr = None
        self.backup = 0
        self.difficulty = None
        self.track = None
        self.lateX = 0
        self.lateY = 0
        self.stateTimestamp = 0
        self.animState2animId = {
            'off': 13,
            'neutral': 10,
            'walk': 9,
            'die': 5,
            'attack': 7,
            'flydown': 1,
            'pie': 4,
            'win': 12,
            'flyaway': 14,
            'rollodex': 3,
            'flyNeutral': 15,
            'flail': 0,
            'drop': 6,
            'drop-react': 16,
            'squirt-large': 8,
            'squirt-small': 11,
            'soak': 2,
        }
        self.animId2animState = {
            v: k
            for k, v in self.animState2animId.items()
        }
        self.level = 0
        self.currentPathQueue = []
        return

    def resetPathQueue(self):
        self.currentPathQueue = []

    def setLevel(self, level):
        self.level = level

    def d_setLevel(self, level):
        self.sendUpdate('setLevel', [level])

    def b_setLevel(self, level):
        self.d_setLevel(level)
        self.setLevel(level)

    def getLevel(self):
        return self.level

    def setLatePos(self, x, y):
        self.lateX = x
        self.lateY = y

    def getLatePos(self):
        return [self.lateX, self.lateY]

    def setSuitState(self, index, startPoint, endPoint):
        if index == 0:
            self.setLatePos(self.getX(render), self.getY(render))
        self.suitState = index
        self.startPoint = startPoint
        self.endPoint = endPoint

    def d_setSuitState(self, index, startPoint, endPoint):
        self.stateTimestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate('setSuitState',
                        [index, startPoint, endPoint, self.stateTimestamp])

    def b_setSuitState(self, index, startPoint, endPoint):
        self.d_setSuitState(index, startPoint, endPoint)
        self.setSuitState(index, startPoint, endPoint)

    def getSuitState(self):
        return [
            self.suitState, self.startPoint, self.endPoint, self.stateTimestamp
        ]

    def setDifficulty(self, difficulty):
        self.difficulty = difficulty

    def getDifficulty(self):
        return self.difficulty

    def setBackup(self, backup):
        self.backup = backup

    def isBackup(self):
        return self.backup

    def setManager(self, mgr):
        self.mgr = mgr
        self.hood = CogBattleGlobals.HoodIndex2HoodName[
            self.getManager().getBattle().getHoodIndex()]

    def getManager(self):
        return self.mgr

    def printPos(self, task):
        print self.getPos(render)
        print self.getHpr(render)
        return task.cont

    def spawn(self):
        self.brain = CogBrainAI.CogBrain(self)
        landspot = random.choice(CIGlobals.SuitSpawnPoints[self.hood].keys())
        path = CIGlobals.SuitSpawnPoints[self.hood][landspot]
        index = CIGlobals.SuitSpawnPoints[self.hood].keys().index(landspot)
        self.b_setSuitState(2, index, index)
        self.currentPath = landspot
        track = self.posInterval(3, path, startPos=path + (0, 0, 50))
        track.start()
        yaw = random.uniform(0.0, 360.0)
        self.setH(yaw)
        if self.track:
            self.track.pause()
            self.track = None
        self.track = Sequence(Wait(5.4), Func(self.b_setAnimState, 'neutral'),
                              Wait(1.0), Func(self.startRoaming))
        self.track.start()
        self.b_setParent(CIGlobals.SPRender)

    def startRoaming(self):
        if self.head == "vp" or self.isBackup():
            # If this is a vp or a backup cog, do the random attacks.
            self.startAttacks()
        taskMgr.add(self.monitorHealth, self.uniqueName('monitorHealth'))
        if self.head == "vp":
            self.boss = SuitBoss.SuitBoss(self)
            self.boss.startBoss()
        else:
            self.brain.start()

    def startAttacks(self):
        if self.head != "vp":
            attackTime = random.randint(8, 20)
        else:
            attackTime = random.randint(8, 12)
        taskMgr.doMethodLater(attackTime, self.attackTask,
                              self.uniqueName('attackTask'))

    def attackTask(self, task):
        if self.brain.fsm.getCurrentState().getName() == "runAway":
            # Attack while running away... ain't nobody got time for that!
            delay = random.randint(6, 12)
            task.delayTime = delay
            return task.again
        if self.head == "vp":
            # We can't attack while we're flying
            if not self.boss.getFlying():
                self.chooseVictim()
        else:
            self.chooseVictim()
        if self.head != "vp":
            delay = random.randint(6, 15)
        else:
            delay = random.randint(6, 12)
        task.delayTime = delay
        return task.again

    def enableMovement(self):
        self.brain.start()
        if self.head != "vp":
            attackTime = random.randint(8, 20)
        else:
            attackTime = random.randint(8, 12)
        taskMgr.doMethodLater(attackTime, self.attackTask,
                              self.uniqueName('attackTask'))

    def disableMovement(self):
        taskMgr.remove(self.uniqueName('attackTask'))
        taskMgr.remove(self.uniqueName('continueSuitRoam'))
        if self.suitHealTrack:
            self.suitHealTrack.pause()
            self.suitHealTrack = None
        self.brain.end()
        self.b_setSuitState(3, -1, -1)
        if self.head != "vp":
            if self.walkTrack:
                self.ignore(self.walkTrack.getName())
                self.walkTrack.clearToInitial()
                self.walkTrack = None
        self.d_interruptAttack()

    def chooseVictim(self):
        toons = []
        for key in self.air.doId2do.keys():
            val = self.air.doId2do[key]
            if val.__class__.__name__ == "DistributedToonAI" or val.__class__.__name__ == "DistributedSuitAI" or val.__class__.__name__ == "DistributedPieTurretAI":
                if val.zoneId == self.zoneId:
                    if val.__class__.__name__ == "DistributedSuitAI" and val.head == "vp" \
                    and val.doId != self.doId or val.__class__.__name__ == "DistributedToonAI" or val.__class__.__name__ == "DistributedPieTurretAI":
                        # We can be a medic and heal the fellow VP...
                        if not val.isDead():
                            if self.getDistance(val) <= 40:
                                if val.__class__.__name__ == "DistributedToonAI":
                                    if not val.getGhost():
                                        toons.append(val)
                                else:
                                    toons.append(val)
        if toons == []:
            return
        toon = random.randint(0, len(toons) - 1)
        self.disableMovement()
        self.headsUp(toons[toon])
        self.attackToon(toons[toon])
        self.setAttacking(True)

    def attackToon(self, av):
        if av.__class__.__name__ in [
                "DistributedSuitAI", "DistributedPieTurretAI"
        ]:
            # Why would I pick pocket my boss?
            attack = random.randint(0, 6)
            attackName = SuitAttacks.SuitAttackLengths.keys()[attack]
        else:
            if self.head in ['vp']:
                attack = random.randint(0, 6)
                attackName = SuitAttacks.SuitAttackLengths.keys()[attack]
            else:
                attackName = random.choice(
                    SuitAttacks.SuitAttackLengths.keys())
                attack = SuitAttacks.SuitAttackLengths.keys().index(attackName)
        attackTaunt = random.randint(
            0,
            len(CIGlobals.SuitAttackTaunts[attackName]) - 1)
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate('doAttack', [attack, av.doId, timestamp])
        if av.__class__.__name__ in [
                "DistributedSuitAI", "DistributedPieTurretAI"
        ]:
            distance = self.getDistance(av)
            speed = 50.0
            if attackName == "glowerpower":
                speed = 100.0
            timeUntilHeal = distance / speed
            if av.__class__.__name__ == "DistributedSuitAI":
                self.d_setChat(CIGlobals.SuitHealTaunt)
            else:
                self.d_setChat(
                    CIGlobals.SuitAttackTaunts[attackName][attackTaunt])
            if attackName != "glowerpower":
                if self.type == "C":
                    timeUntilRelease = 2.2
                else:
                    timeUntilRelease = 3.0
            else:
                timeUntilRelease = 1.0
            currentBossPos = av.getPos(render)
            hp = int(self.maxHealth /
                     SuitAttacks.SuitAttackDamageFactors[attackName])
            self.suitHealTrack = Sequence(
                Wait(timeUntilRelease + timeUntilHeal),
                Func(self.attemptToHealBoss, av, currentBossPos, hp))
            self.suitHealTrack.start()
        else:
            self.d_setChat(CIGlobals.SuitAttackTaunts[attackName][attackTaunt])
        time = SuitAttacks.SuitAttackLengths[attackName]
        if self.track:
            self.track.pause()
            self.track = None
        taskMgr.doMethodLater(SuitAttacks.SuitAttackLengths[attackName],
                              self.continuePathTask,
                              self.uniqueName('continueSuitRoam'))

    def attemptToHealBoss(self, boss, currBossPos, hp):
        if not boss.isEmpty():
            if (boss.getPos(render) - currBossPos).length() <= 1:
                if not boss.isDead():
                    if boss.__class__.__name__ == "DistributedSuitAI":
                        boss.b_setHealth(boss.getHealth() + hp)
                        boss.d_announceHealth(1, hp)
                    else:
                        # Turret
                        boss.b_setHealth(boss.getHealth() - hp)
                        boss.d_announceHealth(0, hp)
                    self.d_handleWeaponTouch()

    def continuePathTask(self, task):
        self.setAttacking(False)
        if self.head != "vp":
            if self.brain.fsm.getCurrentState().getName() == "followBoss":
                # If we're protecting the boss, don't walk away from him!
                return task.done
            else:
                self.brain.neutral_startLookingForToons()
                self.brain.start()
                return task.done
        self.continuePath()
        return task.done

    def d_handleWeaponTouch(self):
        self.sendUpdate("handleWeaponTouch", [])

    def continuePath(self):
        # Create a new path for the Suit if they are stuck...
        if self.head != "vp":
            if self.walkTrack:
                self.ignore(self.walkTrack.getName())
                self.walkTrack.clearToInitial()
                self.walkTrack = None
            self.brain.end()
            self.brain.start()
        else:
            self.b_setAnimState("neutral")

    def setAttacking(self, value):
        self.attacking = value

    def getAttacking(self):
        return self.attacking

    def monitorHealth(self, task):
        if self.health <= 0:
            taskMgr.remove(self.uniqueName('attackTask'))
            taskMgr.remove(self.uniqueName('continueSuitRoam'))
            if self.suitHealTrack:
                self.suitHealTrack.pause()
                self.suitHealTrack = None
            self.b_setSuitState(3, -1, -1)
            if self.walkTrack:
                self.ignore(self.walkTrack.getName())
                self.walkTrack.clearToInitial()
                self.walkTrack = None
            self.d_interruptAttack()
            self.brain.end()
            if self.head == "vp":
                self.boss.stopBoss()
            if self.track:
                self.track.pause()
                self.track = None

            anim2WaitTime = {
                'pie': 2.0,
                'drop': 6.0,
                'drop-react': 3.5,
                'squirt-small': 4.0,
                'squirt-large': 4.9,
                'soak': 6.5,
                'neutral': 0.0,
                'walk': 0.0
            }
            self.track = Sequence(Wait(anim2WaitTime[self.getAnimStateStr()]),
                                  Func(self.killSuit))
            self.track.start()

            return task.done
        return task.cont

    def isWalking(self):
        if self.walkTrack:
            return self.walkTrack.isPlaying()
        else:
            return False

    def killSuit(self):
        self.b_setAnimState('die')
        if self.track:
            self.track.pause()
            self.track = None
        self.track = Sequence(Wait(6.0), Func(self.closeSuit))
        self.track.start()

    def closeSuit(self):
        # Drop the jellybeans I stole before I die!
        self.itemDropper.drop()
        self.getManager().deadSuit(self.doId)
        self.disable()
        self.requestDelete()

    def createPath(self, path_key=None, durationFactor=0.2, fromCurPos=False):
        if path_key == None and not len(self.currentPathQueue):
            path_key_list = CIGlobals.SuitPathData[self.hood][self.currentPath]
            path_key = random.choice(path_key_list)
        elif len(self.currentPathQueue):
            path_key = self.currentPathQueue[0]
            self.currentPathQueue.remove(path_key)
        endIndex = CIGlobals.SuitSpawnPoints[self.hood].keys().index(path_key)
        path = CIGlobals.SuitSpawnPoints[self.hood][path_key]
        if self.walkTrack:
            self.ignore(self.walkTrack.getDoneEvent())
            self.walkTrack.clearToInitial()
            self.walkTrack = None
        if not self.currentPath or fromCurPos:
            startIndex = -1
        else:
            oldPath = self.currentPath
            startIndex = CIGlobals.SuitSpawnPoints[self.hood].keys().index(
                oldPath)
        self.currentPath = path_key
        pathName = self.uniqueName('suitPath')
        self.walkTrack = NPCWalkInterval(self,
                                         path,
                                         startPos=self.getPos(render),
                                         name=pathName,
                                         durationFactor=durationFactor,
                                         fluid=1)
        self.walkTrack.setDoneEvent(self.walkTrack.getName())
        self.startFollow()
        self.b_setSuitState(1, startIndex, endIndex)

    def startFollow(self):
        #self.b_setAnimState('walk')
        if self.walkTrack:
            self.acceptOnce(self.walkTrack.getName(), self.walkDone)
            self.walkTrack.start()

    def walkDone(self):
        if self.walkTrack:
            self.walkTrack.finish()
            self.walkTrack = None
        self.b_setAnimState('neutral')
        self.createPath()

    def toonHitByWeapon(self, weaponId, avId):
        sender = self.air.getMsgSender()
        weapon = SuitAttacks.SuitAttackLengths.keys()[weaponId]
        if not weapon in [
                "pickpocket", "fountainpen", "hangup", "buzzword",
                "razzledazzle", "jargon", "mumbojumbo", 'doubletalk',
                'schmooze', 'fingerwag', 'filibuster'
        ]:
            self.d_handleWeaponTouch()
        dmg = int(self.maxHealth / SuitAttacks.SuitAttackDamageFactors[weapon])
        toon = self.air.doId2do.get(avId, None)
        if toon:
            hp = toon.getHealth() - dmg
            if hp < 0:
                hp = 0
            toon.b_setHealth(hp)
            toon.d_announceHealth(0, dmg)
            if toon.isDead():
                self.b_setAnimState('win')
                taskMgr.remove(self.uniqueName('continueSuitRoam'))
                taskMgr.doMethodLater(6.0, self.continuePathTask,
                                      self.uniqueName('continueSuitRoam'))

    def turretHitByWeapon(weaponId, avId):
        weapon = SuitAttacks.SuitAttackLengths.keys()[weaponId]
        if not weapon in ["pickpocket", "fountainpen", "hangup"]:
            self.d_handleWeaponTouch()
        dmg = int(self.maxHealth / CIGlobals.SuitAttackDamageFactors[weapon])
        turret = self.air.doId2do.get(avId, None)
        if turret:
            turret.b_setHealth(turret.getHealth() - 1)
            turret.d_announceHealth(0, dmg)

    def setSuit(self, suitType, head, team, skeleton):
        self.type = suitType
        self.head = head
        self.team = team
        self.skeleton = skeleton
        self.health = CIGlobals.getSuitHP(self.level)
        self.maxHealth = self.health
        self.itemDropper.calculate()

    def b_setSuit(self, suitType, head, team, skeleton):
        self.d_setSuit(suitType, head, team, skeleton)
        self.setSuit(suitType, head, team, skeleton)

    def d_setSuit(self, suitType, head, team, skeleton):
        self.sendUpdate("setSuit", [suitType, head, team, skeleton])

    def getSuit(self):
        return tuple((self.type, self.head, self.team, self.skeleton))

    def setAnimState(self, anim):
        self.anim = anim

    def b_setAnimState(self, anim):
        if type(anim) == types.StringType:
            anim = self.animState2animId[anim]
        self.d_setAnimState(anim)
        self.setAnimState(anim)

    def d_setAnimState(self, anim):
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate("setAnimState", [anim, timestamp])

    def getAnimState(self):
        return self.anim

    def getAnimStateStr(self):
        return self.animId2animState[self.getAnimState()]

    def d_interruptAttack(self):
        self.sendUpdate("interruptAttack", [])

    def d_setAttack(self, attack):
        self.sendUpdate("setAttack", [attack])

    def announceGenerate(self):
        DistributedAvatarAI.announceGenerate(self)
        if self.track:
            self.track.pause()
            self.track = None
        Sequence(Wait(0.1), Func(self.spawn)).start()

    def generate(self):
        DistributedAvatarAI.generate(self)
        DistributedSmoothNodeAI.generate(self)

    def disable(self):
        try:
            self.DistributedSuitAI_disabled
        except:
            self.DistributedSuitAI_disabled = 1
            if self.track:
                self.track.pause()
                self.track = None
            taskMgr.remove(self.uniqueName('monitorHealth'))
            taskMgr.remove(self.uniqueName('attackTask'))
            taskMgr.remove(self.uniqueName('continueSuitRoam'))
            if self.suitHealTrack:
                self.suitHealTrack.pause()
                self.suitHealTrack = None
            if self.walkTrack:
                self.ignore(self.walkTrack.getName())
                self.walkTrack.clearToInitial()
                self.walkTrack = None
            if self.boss:
                self.boss.stopBoss()
                self.boss = None
            if self.brain:
                self.brain.end()
                self.brain = None
            self.itemDropper.cleanup()
            self.itemDropper = None
            self.aiChar = None
            self.aiBehaviors = None
            self.continuePathId = None
            self.attackId = None
            self.name = None
            self.anim = None
            self.state = None
            self.damage = None
            self.health = None
            self.backup = None
            self.type = None
            self.team = None
            self.head = None
            self.skeleton = 0
            self.dmg_lbl = None
            self.currentPath = None
            self.lbl_int = None
            self.bean = None
            self.avatarType = None
            self.lateX = None
            self.lateY = None
            self.currentPathQueue = None
            DistributedAvatarAI.disable(self)
        return

    def delete(self):
        try:
            self.DistributedSuitAI_deleted
        except:
            self.DistributedSuitAI_deleted = 1
            del self.aiChar
            del self.brain
            del self.aiBehaviors
            del self.boss
            del self.continuePathId
            del self.attackId
            del self.name
            del self.anim
            del self.state
            del self.damage
            del self.health
            del self.type
            del self.team
            del self.head
            del self.skeleton
            del self.dmg_lbl
            del self.lbl_int
            del self.bean
            del self.currentPath
            del self.avatarType
            del self.walkTrack
            del self.suitHealTrack
            del self.backup
            del self.lateX
            del self.lateY
            del self.currentPathQueue
            DistributedAvatarAI.delete(self)
            DistributedSmoothNodeAI.delete(self)
        return
コード例 #4
0
class VicePresident(Avatar):
    notify = directNotify.newCategory("VicePresident")

    def __init__(self):
        Avatar.__init__(self)
        self.fsm = ClassicFSM('VicePresident', [
            State('off', self.enterOff, self.exitOff),
            State('throwGear', self.enterThrowGear, self.exitThrowGear),
            State('neutral', self.enterNeutral, self.exitNeutral),
            State('jump', self.enterJump, self.exitJump),
            State('emerge', self.enterEmerge, self.exitEmerge),
            State('knockDown', self.enterKnockDown, self.exitKnockDown),
            State('riseUp', self.enterRiseUp, self.exitRiseUp)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.track = None
        self.treads = None
        self.rearDoor = None
        self.frontDoor = None
        self.gearModel = None
        self.gearThrowIval = None
        self.knockedDown = False
        self.chirps = base.audio3d.loadSfx("phase_4/audio/sfx/SZ_TC_bird1.mp3")
        base.audio3d.attachSoundToObject(self.chirps, self)
        self.vp_torso_node = NodePath('vp_torso_node')

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterRiseUp(self, ts=0):
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('vpRiseUp')
        else:
            name = 'vpRiseUp'
        sfx = base.audio3d.loadSfx("phase_9/audio/sfx/CHQ_VP_raise_up.mp3")
        base.audio3d.attachSoundToObject(sfx, self)
        self.track = Sequence(Func(base.playSfx, sfx),
                              ActorInterval(self, "up"),
                              name=name)
        self.knockedDown = False
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.fsm.request,
                        ["neutral"])
        self.track.start(ts)

    def exitRiseUp(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    def enterKnockDown(self, ts=0):
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('vpKnockDown')
        else:
            name = 'vpKnockDown'
        sfx = base.audio3d.loadSfx("phase_5/audio/sfx/AA_sound_aoogah.mp3")
        base.audio3d.attachSoundToObject(sfx, self)
        self.track = Sequence(Func(base.playSfx, sfx),
                              ActorInterval(self, "fall"),
                              name=name)
        self.knockedDown = True
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.fsm.request,
                        ["neutral"])
        self.track.start(ts)

    def exitKnockDown(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    def enterEmerge(self, ts=0):
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('emergeTrack')
        else:
            name = 'emergeTrack'
        self.setScale(0.1)
        emergeSfx = base.audio3d.loadSfx(
            "phase_5/audio/sfx/TL_train_track_appear.mp3")
        base.audio3d.attachSoundToObject(emergeSfx, self)
        self.track = Sequence(Func(base.playSfx, emergeSfx),
                              LerpScaleInterval(self,
                                                duration=1.2,
                                                scale=1.0,
                                                startScale=0.05,
                                                blendType='easeOut'),
                              name=name)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.fsm.request,
                        ["neutral"])
        self.track.start(ts)
        self.loop('stand-angry')

    def exitEmerge(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    def enterNeutral(self, ts=0):
        if self.getCurrentAnim() != 'stand-angry':
            if self.knockedDown:
                base.playSfx(self.chirps, looping=1)
                self.loop("dn_neutral")
            else:
                self.loop("stand-angry")
        self.track = NPCLookInterval(self.vp_torso_node,
                                     Vec3(0, 0, 0),
                                     blendType='easeInOut',
                                     name='lookAtCenter',
                                     isBackwards=False)
        self.track.start(ts)

    def exitNeutral(self):
        self.stop()
        self.chirps.stop()

    def enterJump(self, ts=0):
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('vpJump')
        else:
            name = 'vpJump'
        jumpSfx = base.audio3d.loadSfx(
            "phase_5/audio/sfx/General_throw_miss.mp3")
        landSfx = base.audio3d.loadSfx(
            "phase_3.5/audio/sfx/ENC_cogfall_apart.mp3")
        base.audio3d.attachSoundToObject(jumpSfx, self)
        base.audio3d.attachSoundToObject(landSfx, self)
        self.track = Sequence(Func(self.play, "jump"),
                              Func(base.playSfx, jumpSfx),
                              Wait(1.2),
                              Func(base.playSfx, landSfx),
                              Wait(1.8),
                              name=name)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.fsm.request,
                        ["neutral"])
        self.track.start(ts)

    def exitJump(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    def enterThrowGear(self, point, ts=0):
        lookNode = render.attachNewNode('pointNode')
        lookNode.setPos(point)
        #self.gearModel.reparentTo(render)
        #self.gearModel.setPos(point)
        throwSfx = base.audio3d.loadSfx(
            "phase_9/audio/sfx/CHQ_VP_frisbee_gears.mp3")
        base.audio3d.attachSoundToObject(throwSfx, self)
        if hasattr(self, 'uniqueName'):
            name = self.uniqueName('vpThrowGear')
        else:
            name = 'vpThrowGear'
        self.track = Sequence(NPCLookInterval(self.vp_torso_node,
                                              lookNode,
                                              blendType='easeInOut',
                                              isBackwards=False),
                              Func(VicePresident.throwGear, self, point),
                              Func(base.playSfx, throwSfx),
                              ActorInterval(self, "throw"),
                              name=name)
        self.track.setDoneEvent(self.track.getName())
        self.acceptOnce(self.track.getDoneEvent(), self.fsm.request,
                        ["neutral"])
        self.track.start(ts)
        lookNode.removeNode()
        del lookNode

    def throwGear(self, point):
        self.gearModel.reparentTo(self.getPart("body"))
        self.gearModel.setX(0.0)
        self.gearModel.setY(-2)
        self.gearModel.setZ(5)
        self.gearModel.setPos(self.gearModel.getPos(render))
        self.gearModel.reparentTo(render)
        self.gearModel.show()
        self.gearModel.lookAt(point)
        if self.gearThrowIval:
            self.gearThrowIval.finish()
            self.gearThrowIval = None
        self.gearThrowIval = NPCWalkInterval(self.gearModel,
                                             point,
                                             durationFactor=0.01,
                                             fluid=1,
                                             lookAtTarget=False)
        self.gearThrowIval.start()

    def exitThrowGear(self):
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None

    def destroy(self):
        if 'head' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['head']
        if 'body' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['body']
        if 'legs' in self._Actor__commonBundleHandles:
            del self._Actor__commonBundleHandles['legs']
        if self.treads:
            self.treads.removeNode()
            self.treads = None
        if self.gearThrowIval:
            self.gearThrowIval.finish()
            self.gearThrowIval = None
        if self.gearModel:
            self.gearModel.removeNode()
            self.gearModel = None
        if self.track:
            self.ignore(self.track.getDoneEvent())
            self.track.finish()
            self.track = None
        self.rearDoor = None
        self.frontDoor = None
        if self.vp_torso_node:
            self.vp_torso_node.removeNode()
            self.vp_torso_node = None
        self.removePart("head")
        self.removePart("body")
        self.removePart("legs")

    def generate(self):
        self.generateLegs()
        self.generateBody()
        self.generateHead()
        self.generateTreads()
        self.generateGear()
        self.parentParts()

    def parentParts(self):
        self.attach('head', 'body', 'joint34')
        self.treads.reparentTo(self.getPart("legs").find('**/joint_axle'))
        self.vp_torso_node.reparentTo(
            self.getPart("legs").find('**/joint_legs'))
        self.getPart("body").reparentTo(self.vp_torso_node)
        self.getPart("body").setH(180)

        self.frontDoor.setR(-80)
        self.rearDoor.setR(77)

    def generateGear(self):
        self.gearModel = loader.loadModel("phase_9/models/char/gearProp.bam")
        self.gearModel.setScale(0.25)
        self.gearModel.hide()

    def generateTreads(self):
        self.treads = loader.loadModel(
            "phase_9/models/char/bossCog-treads.bam")

    def generateLegs(self):
        self.loadModel("phase_9/models/char/bossCog-legs-zero.bam", "legs")
        self.loadAnims(
            {
                "stand-angry":
                "phase_9/models/char/bossCog-legs-Fb_neutral.bam",
                "stand-happy":
                "phase_9/models/char/bossCog-legs-Ff_neutral.bam",
                "jump": "phase_9/models/char/bossCog-legs-Fb_jump.bam",
                "throw": "phase_9/models/char/bossCog-legs-Fb_UpThrow.bam",
                "fall": "phase_9/models/char/bossCog-legs-Fb_firstHit.bam",
                "up": "phase_9/models/char/bossCog-legs-Fb_down2Up.bam",
                "dn_neutral":
                "phase_9/models/char/bossCog-legs-Fb_downNeutral.bam",
                "dn_throw":
                "phase_9/models/char/bossCog-legs-Fb_DownThrow.bam",
                "speech": "phase_9/models/char/bossCog-legs-Ff_speech.bam",
                "wave": "phase_9/models/char/bossCog-legs-wave.bam",
                "downhit": "phase_9/models/char/bossCog-legs-Fb_firstHit.bam"
            }, "legs")

        self.frontDoor = self.controlJoint(None, "legs", "joint_doorFront")
        self.rearDoor = self.controlJoint(None, "legs", "joint_doorRear")

    def generateBody(self):
        self.loadModel("phase_9/models/char/sellbotBoss-torso-zero.bam",
                       "body")
        self.loadAnims(
            {
                "stand-angry":
                "phase_9/models/char/bossCog-torso-Fb_neutral.bam",
                "stand-happy":
                "phase_9/models/char/bossCog-torso-Ff_neutral.bam",
                "jump": "phase_9/models/char/bossCog-torso-Fb_jump.bam",
                "throw": "phase_9/models/char/bossCog-torso-Fb_UpThrow.bam",
                "fall": "phase_9/models/char/bossCog-torso-Fb_firstHit.bam",
                "up": "phase_9/models/char/bossCog-torso-Fb_down2Up.bam",
                "dn_neutral":
                "phase_9/models/char/bossCog-torso-Fb_downNeutral.bam",
                "dn_throw":
                "phase_9/models/char/bossCog-torso-Fb_DownThrow.bam",
                "speech": "phase_9/models/char/bossCog-torso-Ff_speech.bam",
                "wave": "phase_9/models/char/bossCog-torso-wave.bam",
                "downhit": "phase_9/models/char/bossCog-torso-Fb_firstHit.bam"
            }, "body")

    def generateHead(self):
        self.loadModel("phase_9/models/char/sellbotBoss-head-zero.bam", "head")
        self.loadAnims(
            {
                "stand-angry":
                "phase_9/models/char/bossCog-head-Fb_neutral.bam",
                "stand-happy":
                "phase_9/models/char/bossCog-head-Ff_neutral.bam",
                "jump": "phase_9/models/char/bossCog-head-Fb_jump.bam",
                "throw": "phase_9/models/char/bossCog-head-Fb_UpThrow.bam",
                "fall": "phase_9/models/char/bossCog-head-Fb_firstHit.bam",
                "up": "phase_9/models/char/bossCog-head-Fb_down2Up.bam",
                "dn_neutral":
                "phase_9/models/char/bossCog-head-Fb_downNeutral.bam",
                "dn_throw":
                "phase_9/models/char/bossCog-head-Fb_DownThrow.bam",
                "speech": "phase_9/models/char/bossCog-head-Ff_speech.bam",
                "wave": "phase_9/models/char/bossCog-head-wave.bam",
                "downhit": "phase_9/models/char/bossCog-head-Fb_firstHit.bam"
            }, "head")
class DistributedDeliveryGameSuitAI(DistributedSuitAI):
    notify = directNotify.newCategory('DistributedDeliveryGameSuitAI')

    def __init__(self, air, mg):
        DistributedSuitAI.__init__(self, air)
        self.mg = mg
        self.truck = random.choice(self.mg.trucks)
        self.truckIndex = self.mg.trucks.index(self.truck)
        self.spawnPoint = None

    def walkToTruck(self):
        index = DGG.WalkToTruckIndex
        pos = DGG.TruckSuitPointsByIndex[self.truckIndex]
        startPos = self.getPos(render)
        self.b_setSuitState(1, -1, index)
        durationFactor = 0.2
        pathName = self.uniqueName('WalkToTruck')
        self.walkTrack = NPCWalkInterval(self,
                                         pos,
                                         startPos=startPos,
                                         name=pathName,
                                         durationFactor=durationFactor,
                                         fluid=1)
        self.walkTrack.setDoneEvent(self.walkTrack.getName())
        self.acceptOnce(self.walkTrack.getDoneEvent(), self.__walkedToTruck)
        self.walkTrack.start()
        self.b_setAnimState(
            SuitGlobals.getAnimId(SuitGlobals.getAnimByName('walk')))

    def __walkedToTruck(self):
        self.truck.suitPickUpBarrel(self.doId)
        self.walkBackToSpawnPointWithBarrel()

    def walkBackToSpawnPointWithBarrel(self):
        pos = DGG.SpawnPoints[self.spawnPoint]
        startPos = self.getPos(render)
        self.b_setSuitState(1, -1, self.spawnPoint)
        durationFactor = 0.2
        pathName = self.uniqueName('WalkBackToSpawn')
        self.walkTrack = NPCWalkInterval(self,
                                         pos,
                                         startPos=startPos,
                                         name=pathName,
                                         durationFactor=durationFactor,
                                         fluid=1)
        self.walkTrack.setDoneEvent(self.walkTrack.getName())
        self.acceptOnce(self.walkTrack.getDoneEvent(), self.__walkedBack2Spawn)
        self.walkTrack.start()
        self.b_setAnimState(
            SuitGlobals.getAnimId(SuitGlobals.getAnimByName('tray-walk')))

    def __walkedBack2Spawn(self):
        self.b_setSuitState(3, self.spawnPoint, self.spawnPoint)
        base.taskMgr.doMethodLater(10, self.__finished,
                                   self.uniqueName('finishSuit'))

    def __finished(self, task):
        self.mg.suits.remove(self)
        self.truck.barrelDroppedOff()
        self.requestDelete()
        return task.done

    def spawn(self):
        pos = random.choice(DGG.SpawnPoints)
        index = DGG.SpawnPoints.index(pos)
        self.spawnPoint = index
        self.b_setSuitState(2, index, index)
        flyTrack = self.posInterval(3, pos, startPos=pos + (0, 0, 50))
        flyTrack.start()
        self.track = Sequence()
        self.track.append(Wait(5.4))
        self.track.append(Func(self.b_setAnimState, 'neutral'))
        self.track.append(Wait(1.0))
        self.track.append(Func(self.walkToTruck))
        self.track.start()
        self.b_setParent(CIGlobals.SPRender)

    def delete(self):
        base.taskMgr.remove(self.uniqueName('finishSuit'))
        if hasattr(self, 'walkTrack') and self.walkTrack:
            self.ignore(self.walkTrack.getDoneEvent())
            self.walkTrack.finish()
            self.walkTrack = None
        self.mg = None
        self.truck = None
        self.truckIndex = None
        self.spawnPoint = None
        DistributedSuitAI.delete(self)
class FactorySneakGuardSuit(Suit, FSM):
    notify = directNotify.newCategory("FactorySneakGuardSuit")

    SUIT = "mrhollywood"
    VIEW_DISTANCE_TASK_NAME = "ViewDistanceTask"
    MAX_VIEW_DISTANCE = 100.0
    GUARD_DIED_DELAY = 6.0
    MAX_HP = 200
    PROWLER_DISTANCE = 40.0

    IN_VIEW = "somethingInSight"
    HEARD = "heard"
    TRY_TO_CONFIRM_TIME = 5.0

    def __init__(self, world, guardKey):
        Suit.__init__(self)
        FSM.__init__(self, 'FactorySneakGuardSuit')
        self.gameWorld = world
        self.guardKey = guardKey
        self.viewDistanceTaskName = self.VIEW_DISTANCE_TASK_NAME + "-" + str(
            id(self))
        self.diedTaskName = "GuardDied-" + str(id(self))
        self.health = 0
        self.maxHealth = self.MAX_HP
        self.eyeLight = None
        self.eyeLens = None
        self.eyeNode = None
        self.moveTrack = None
        self.trav = None
        self.rayNP = None
        self.queue = None
        self.currentKey = self.guardKey
        self.firstPoint = CGG.GuardPointData[self.guardKey]
        self.walkTrack = None
        self.pathQueue = []
        self.currentPathIndex = 0

    def enterGuard(self):
        self.loop('neutral')
        pos, hpr = CGG.FactoryGuardPoints[self.guardKey]
        self.setHpr(hpr - (180, 0, 0))
        self.setPos(pos)

        base.taskMgr.add(self.__guard, self.taskName("guard"))

    def __checkToon(self):
        self.rayNP.lookAt(base.localAvatar)
        self.trav.traverse(render)
        if self.queue.getNumEntries() > 0:
            self.queue.sortEntries()
            hitObj = self.queue.getEntry(0).getIntoNodePath()
            print hitObj
            isLocalAvatar = hitObj.getParent().getPythonTag('localAvatar')
            if isLocalAvatar == 1:
                # Yes! We see the prowler!
                return 1
        return 0

    def __guard(self, task):
        # Let me check if the target is my frustrum, and if it's a close enough distance from me.
        if (self.eyeNode.node().isInView(base.localAvatar.getPos(self.eyeNode))
                and
                self.getDistance(base.localAvatar) <= self.PROWLER_DISTANCE):
            # Now, let me check if the toon is standing right in front of me; not occluded.
            if self.__checkToon():
                # Yes! We see some one!
                self.request('SeekTarget', self.IN_VIEW)
                return task.done
        return task.cont

    def exitGuard(self):
        base.taskMgr.remove(self.taskName("guard"))

    def enterTurnToGuardSpot(self):
        self.loop('walk')
        _, hpr = CGG.FactoryGuardPoints[self.guardKey]
        self.moveTrack = LerpHprInterval(self,
                                         duration=1.0,
                                         hpr=hpr,
                                         startHpr=self.getHpr())
        self.moveTrack.setDoneEvent(self.uniqueName('TurnedToGuardSpot'))
        self.acceptOnce(self.moveTrack.getDoneEvent(), self.request, ['Guard'])
        self.moveTrack.start()

    def exitTurnToGuardSpot(self):
        if self.moveTrack:
            self.ignore(self.moveTrack.getDoneEvent())
            self.moveTrack.finish()
            self.moveTrack = None

    def enterSeekTarget(self, event):
        dialogue = random.choice(CGG.GuardDialog[event])
        self.setChat(dialogue)

        self.loop('walk')
        self.moveTrack = NPCLookInterval(self, base.localAvatar)
        self.moveTrack.setDoneEvent(self.uniqueName("SeekLocalAvatar"))
        self.acceptOnce(self.moveTrack.getDoneEvent(), self.request,
                        ['TryToConfirmTarget'])
        self.moveTrack.start()

    def exitSeekTarget(self):
        if self.moveTrack:
            self.ignore(self.moveTrack.getDoneEvent())
            self.moveTrack.finish()
            self.moveTrack = None

    def enterTryToConfirmTarget(self):
        self.loop('neutral')
        base.taskMgr.add(self.__tryToConfirmTarget,
                         self.uniqueName('TryToConfirmTarget'))

    def __tryToConfirmTarget(self, task):
        if task.time >= self.TRY_TO_CONFIRM_TIME:
            # Hmm, I guess it was nothing.
            chat = random.choice(CGG.GuardDialog['disregard'])
            self.setChat(chat)
            self.request('TurnToGuardSpot')
            return task.done
        # Let me see the target again, so I know it's actually something.
        if (self.eyeNode.node().isInView(base.localAvatar.getPos(self.eyeNode))
                and
                self.getDistance(base.localAvatar) <= self.PROWLER_DISTANCE):
            # Now, let me check if the toon is standing right in front of me; not occluded.
            if self.__checkToon():
                # There he is!
                chat = random.choice(CGG.GuardDialog['spot'])
                self.setChat(chat)
                self.request('Pursue')
                return task.done
        return task.cont

    def exitTryToConfirmTarget(self):
        base.taskMgr.remove(self.uniqueName('TryToConfirmTarget'))

    def enterGoBackToGuardSpot(self):
        self.walkBackToGuardSpot()

    def walkBackToGuardSpot(self):
        self.currentPathIndex = 0
        self.pathQueue = SuitPathFinder.find_path(CGG.FactoryWalkPoints,
                                                  CGG.FactoryWayPointData,
                                                  self.currentKey,
                                                  self.guardKey)
        self.currentKey = self.guardKey
        self.walk(0.2)
        self.loop('walk')

    def exitGoBackToGuardSpot(self):
        pass

    def enterPursue(self):
        self.numTries = 0
        self.maxTries = 3
        self.runToClosestPoint()
        self.setPlayRate(1.5, 'walk')
        self.loop('walk')
        messenger.send('guardPursue')

    def getClosestPoint(self):
        # Return the key of the closest point to the localAvatar.
        closestPoint = None
        pointKey2range = {}
        for key, point in CGG.FactoryWalkPoints.items():
            dummyNode = render.attachNewNode('dummyNode')
            dummyNode.setPos(point)
            pointKey2range[key] = base.localAvatar.getDistance(dummyNode)
            dummyNode.removeNode()
        ranges = []
        for distance in pointKey2range.values():
            ranges.append(distance)
        ranges.sort()
        for key in pointKey2range.keys():
            distance = pointKey2range[key]
            if distance == ranges[0]:
                closestPoint = key
                break
        return closestPoint

    def runToClosestPoint(self):
        self.numTries += 1
        closestPoint = self.getClosestPoint()
        self.currentPathIndex = 0
        startKey = None
        if self.currentKey == self.guardKey:
            startKey = CGG.GuardPointData[self.firstPoint]
        else:
            startKey = self.currentKey
        self.pathQueue = SuitPathFinder.find_path(CGG.FactoryWalkPoints,
                                                  CGG.FactoryWayPointData,
                                                  startKey, closestPoint)
        if self.currentKey == self.guardKey:
            self.pathQueue.insert(0, 1)
        else:
            self.pathQueue.insert(0, 0)
        self.currentKey = closestPoint
        self.walk(0.1)

    def walk(self, speed=0.2):
        self.currentPathIndex += 1
        if len(self.pathQueue) <= self.currentPathIndex:
            if self.getCurrentOrNextState() == 'Pursue':
                if self.getClosestPoint() != self.currentKey:
                    # Wow, the player ran off somewhere else! Go there!
                    if self.numTries >= self.maxTries:
                        # Dang it, give up, we can't get to them!
                        self.request('GoBackToGuardSpot')
                    else:
                        self.runToClosestPoint()
            elif self.getCurrentOrNextState() == 'GoBackToGuardSpot':
                self.request('Guard')
            return
        print self.pathQueue[self.currentPathIndex]
        if self.currentPathIndex == 1 and self.pathQueue[0] == 1:
            # We need to walk from our guard point to the first waypoint in our path
            startPoint = self.getPos(render)
            endPoint = CGG.FactoryWalkPoints[self.firstPoint]
        else:
            if self.pathQueue[0] == 0:
                self.pathQueue.remove(self.pathQueue[0])
            key = self.pathQueue[self.currentPathIndex]
            endPoint = CGG.FactoryWalkPoints[key]
            oldKey = self.pathQueue[self.currentPathIndex - 1]
            startPoint = CGG.FactoryWalkPoints[oldKey]
        self.walkTrack = NPCWalkInterval(self, endPoint, speed, startPoint)
        self.walkTrack.setDoneEvent(self.uniqueName('guardWalkDone'))
        self.acceptOnce(self.uniqueName('guardWalkDone'), self.walk)
        self.walkTrack.start()

    def exitPursue(self):
        self.setPlayRate(1.0, 'walk')
        del self.numTries
        if self.walkTrack:
            self.ignore(self.walkTrack.getDoneEvent())
            self.walkTrack.pause()
            self.walkTrack = None
        messenger.send('guardStopPursue')

    def uniqueName(self, name):
        return self.taskName(name)

    def taskName(self, name):
        return name + "-" + str(id(self))

    def setHealth(self, hp):
        self.health = hp

    def getHealth(self):
        return self.health

    def shot(self):
        dialogue = random.choice(CGG.GuardDialog['shot'])
        self.setChat(dialogue)

    def dead(self):
        self.request('Off')
        self.animFSM.request('die')
        base.taskMgr.doMethodLater(self.GUARD_DIED_DELAY, self.__diedDone,
                                   self.diedTaskName)

    def __diedDone(self, task):
        self.gameWorld.deleteGuard(self)
        return task.done

    def generate(self):
        data = CIGlobals.SuitBodyData[self.SUIT]
        type = data[0]
        team = data[1]
        self.generateSuit(type, self.SUIT, team, self.MAX_HP, 0, False)
        base.taskMgr.add(self.__viewDistance, self.viewDistanceTaskName)
        self.setPythonTag('guard', self)
        self.eyeLight = Spotlight('eyes')
        self.eyeLens = PerspectiveLens()
        self.eyeLens.setMinFov(90.0 / (4. / 3.))
        self.eyeLight.setLens(self.eyeLens)
        self.eyeNode = self.headModel.attachNewNode(self.eyeLight)
        self.eyeNode.setZ(-5)
        self.eyeNode.setY(-4.5)
        self.trav = CollisionTraverser(self.uniqueName('eyeTrav'))
        ray = CollisionRay(0, 0, 0, 0, 1, 0)
        rayNode = CollisionNode('ToonFPS.rayNode')
        rayNode.addSolid(ray)
        rayNode.setFromCollideMask(CGG.GuardBitmask | CIGlobals.WallBitmask)
        rayNode.setIntoCollideMask(BitMask32.allOff())
        self.rayNP = base.camera.attachNewNode(rayNode)
        self.rayNP.setZ(3)
        self.queue = CollisionHandlerQueue()
        self.trav.addCollider(self.rayNP, self.queue)
        self.trav.addCollider(self.gameWorld.mg.avatarBody, self.queue)
        self.request('Guard')

    def __viewDistance(self, task):
        # All the guards in the warehouse eat up a lot of frames.  This task will
        # hide the guard geometry if it's too far away.

        if self.getDistance(base.localAvatar) > self.MAX_VIEW_DISTANCE:
            if not self.isHidden():
                self.hide()
        else:
            if self.isHidden():
                self.show()

        task.delayTime = 1.0
        return task.again

    def disable(self):
        self.request('Off')
        base.taskMgr.remove(self.taskName("guard"))
        base.taskMgr.remove(self.diedTaskName)
        base.taskMgr.remove(self.viewDistanceTaskName)
        self.trav = None
        if self.rayNP:
            self.rayNP.removeNode()
            self.rayNP = None
        self.queue = None
        self.currentPathIndex = None
        if self.eyeNode:
            self.eyeNode.removeNode()
            self.eyeNode = None
            self.eyeLens = None
            self.eyeLight = None
        self.viewDistanceTaskName = None
        self.guardKey = None
        self.gameWorld = None
        self.pathQueue = None
        if self.walkTrack:
            self.ignore(self.walkTrack.getDoneEvent())
            self.walkTrack.finish()
            self.walkTrack = None
        Suit.disable(self)