class DistributedEagleSuitAI(DistributedSuitAI):
    notify = directNotify.newCategory("DistributedEagleSuitAI")

    def __init__(self, air):
        DistributedSuitAI.__init__(self, air)
        self.mg = None
        self.flyTrack = None
        self.currentFlyPoint = None
        self.flySpeed = 0.0

    def setMinigame(self, mg):
        self.mg = mg

    def getMinigame(self):
        return self.mg

    def handleGotHit(self):
        self.b_setAnimState('flail')
        if self.flyTrack:
            self.ignore(self.flyTrack.getDoneEvent())
            self.flyTrack.pause()
            self.flyTrack = None
        self.sendUpdate('fallAndExplode', [])
        self.b_setSuitState(6, -1, -1)
        self.flyTrack = Sequence(
            LerpPosInterval(self,
                            duration=4.0,
                            pos=self.getPos(render) - (0, 0, 75),
                            startPos=self.getPos(render),
                            blendType='easeIn'), Wait(1.5), Func(self.killMe))
        self.flyTrack.start()

    def killMe(self):
        self.disable()
        self.requestDelete()

    def setFlySpeed(self, value):
        self.flySpeed = value

    def b_setFlySpeed(self, value):
        self.sendUpdate('setFlySpeed', [value])
        self.setFlySpeed(value)

    def getFlySpeed(self):
        return self.flySpeed

    def spawn(self):
        # spawn() also exists in DistributedSuitAI, but we're not doing
        # anything that a normal suit would do here, so don't even call
        # DistributedSuitAI.spawn.

        if not self.getMinigame():
            self.notify.error("Tried to spawn before self.mg was set!")

        self.b_setAnimState('flyNeutral')
        point = random.choice(EGG.EAGLE_FLY_POINTS)
        self.setPos(point)
        self.d_setPos(*point)

        self.b_setFlySpeed(
            EGG.ROUND_2_EAGLE_SPEED[self.getMinigame().getRound()])

        self.createFlyPath()
        self.b_setParent(CIGlobals.SPRender)

    def createFlyPath(self):
        self.b_setAnimState('flyNeutral')
        if self.flyTrack:
            self.ignore(self.flyTrack.getDoneEvent())
            self.flyTrack.pause()
            self.flyTrack = None
        point = random.choice(EGG.EAGLE_FLY_POINTS)
        if self.currentFlyPoint == point:
            self.createFlyPath()
            return
        if self.currentFlyPoint is None:
            point_list = list(EGG.EAGLE_FLY_POINTS)
            point_list.remove(point)
            startIndex = point_list.index(random.choice(point_list))
        else:
            startIndex = -1
        self.b_setSuitState(5, startIndex, EGG.EAGLE_FLY_POINTS.index(point))
        mgRound = self.getMinigame().getRound()
        if mgRound:
            self.flyTrack = NPCWalkInterval(
                self,
                point,
                durationFactor=EGG.ROUND_2_EAGLE_SPEED[mgRound],
                startPos=self.getPos(render),
                fluid=1,
                name=self.uniqueName('DEagleSuitAI-flyTrack'))
            self.flyTrack.setDoneEvent(self.flyTrack.getName())
            self.acceptOnce(self.flyTrack.getDoneEvent(), self.handleFlyDone)
            self.flyTrack.start()
            self.currentFlyPoint = point
        else:
            return

    def handleFlyDone(self):
        self.createFlyPath()

    def delete(self):
        del self.currentFlyPoint
        del self.mg
        if self.flyTrack:
            self.ignore(self.flyTrack.getDoneEvent())
            self.flyTrack.pause()
            self.flyTrack = None
        DistributedSuitAI.delete(self)
Example #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.getTrucksWithBarrels())
        self.truckIndex = self.truck.getIndex()
        self.spawnPoint = None
        self.holdingBarrel = False
        self.track = None

    def getTruckIndex(self):
        return self.truckIndex

    def walkToTruck(self):
        if self.mg.barrelsRemaining == 0:
            return

        index = DGG.WalkToTruckIndex
        pos = DGG.TruckSuitPointsByIndex[self.truckIndex]
        startPos = self.getPos(render)
        self.b_setSuitState(1, -1, index)

        numPlayers = self.mg.getNumPlayers()
        durationFactor = 0.2
        if numPlayers == 2:
            durationFactor = 0.15
        elif numPlayers == 3:
            durationFactor = 0.1
        elif numPlayers == 4:
            durationFactor = 0.08

        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):
        if self.mg.barrelsRemaining == 0:
            return
        self.truck.suitPickUpBarrel(self.doId)
        self.holdingBarrel = True
        self.walkBackToSpawnPointWithBarrel()

    def walkBackToSpawnPointWithBarrel(self):

        pos = DGG.SpawnPoints[self.spawnPoint]
        startPos = self.getPos(render)
        self.b_setSuitState(1, -1, self.spawnPoint)

        numPlayers = self.mg.getNumPlayers()
        durationFactor = 0.2
        if numPlayers == 2:
            durationFactor = 0.15
        elif numPlayers == 3:
            durationFactor = 0.1
        elif numPlayers == 4:
            durationFactor = 0.08

        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(6))
        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 = SuitBank.MrHollywood
    VARIANT = Variant.NORMAL
    VIEW_DISTANCE_TASK_NAME = "ViewDistanceTask"
    MAX_VIEW_DISTANCE = 100.0
    GUARD_DIED_DELAY = 6.0
    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 = 0
        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 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 setHealth(self, hp):
        self.health = hp
        self.updateHealthBar(hp)

    def getHealth(self):
        return self.health

    def generate(self):
        self.level = 12
        self.maxHealth = 200
        self.health = 200
        Suit.generate(self,
                      FactorySneakGuardSuit.SUIT,
                      FactorySneakGuardSuit.VARIANT,
                      hideFirst=False)
        self.setName(self.suitPlan.getName(), None)
        self.cleanupPropeller()
        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)
Example #4
0
class DistributedTutorialSuitAI(DistributedSuitAI):
    notify = directNotify.newCategory('DistributedTutorialSuitAI')

    ATTACK_IVAL_RANGE = [3, 15]

    def __init__(self, air, index, tut, avatarId):
        DistributedSuitAI.__init__(self, air)
        self.tutPartIndex = index
        self.tutorial = tut
        self.avatarId = avatarId
        self.currentPath = None
        self.walkTrack = None

    def delete(self):
        base.taskMgr.remove(self.uniqueName('monitorHealth'))
        base.taskMgr.remove(self.uniqueName('doAttack'))
        base.taskMgr.remove(self.uniqueName('scwaa'))
        self.stopAttacks()
        if self.track:
            self.track.pause()
            self.track = None
        if self.walkTrack:
            self.walkTrack.pause()
            self.walkTrack = None
        if self.currentPath:
            self.currentPath = None
        self.tutorial = None
        self.tutPartIndex = None
        self.avatarId = None
        DistributedSuitAI.delete(self)

    def spawn(self):
        pos = TutorialGlobals.SUIT_POINTS[TutorialGlobals.SUIT_SPAWN_POINT]
        index = TutorialGlobals.SUIT_POINTS.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(6.5))
        self.track.append(Func(self.b_setAnimState, 'neutral'))
        self.track.append(Wait(1.0))
        self.track.append(Func(self.startAI))
        self.track.start()
        self.b_setParent(CIGlobals.SPRender)
        taskMgr.add(self.monitorHealth, self.uniqueName('monitorHealth'))

    def createPath(self, fromCurPos=False):
        durationFactor = 0.2
        if not hasattr(self, 'currentPath'):
            self.currentPath = None
        if self.currentPath is None:
            path = random.choice(TutorialGlobals.SUIT_POINTS)
            self.currentPath = TutorialGlobals.SUIT_POINTS.index(path)
            startIndex = -1
        else:
            if fromCurPos == False:
                startIndex = int(self.currentPath)
            else:
                startIndex = -1
            self.currentPath += 1
            if self.currentPath >= len(TutorialGlobals.SUIT_POINTS):
                self.currentPath = 0
            path = TutorialGlobals.SUIT_POINTS[self.currentPath]
        endIndex = self.currentPath
        startPos = self.getPos(render)
        pathName = self.uniqueName('suitPath')
        self.walkTrack = NPCWalkInterval(self,
                                         path,
                                         startPos=startPos,
                                         name=pathName,
                                         durationFactor=durationFactor,
                                         fluid=1)
        self.walkTrack.setDoneEvent(self.walkTrack.getName())
        self.acceptOnce(self.walkTrack.getDoneEvent(), self.createPath)
        self.walkTrack.start()
        self.b_setAnimState('walk')
        self.b_setSuitState(1, startIndex, endIndex)

    def monitorHealth(self, task):
        if self.health <= 0:
            self.tutorial.sendUpdateToAvatarId(self.avatarId, 'suitNoHealth',
                                               [self.tutPartIndex])
            self.tutorial.suitsKilled += 1
            if self.tutorial.suitsKilled == 3:
                self.battleZone.battleComplete()
            if self.walkTrack:
                self.ignore(self.walkTrack.getDoneEvent())
                self.walkTrack.pause()
                self.walkTrack = None
            self.b_setSuitState(0, -1, -1)
            currentAnim = SuitGlobals.getAnimByName(self.anim)
            self.clearTrack()
            base.taskMgr.remove(self.uniqueName('scwaa'))
            self.stopAttacks()
            if currentAnim:
                self.track = Sequence(Wait(currentAnim.getDeathHoldTime()),
                                      Func(self.killSuit))
                self.track.start()
            else:
                self.killSuit()

            return Task.done
        return Task.cont

    def setSuit(self, plan, variant=0):
        DistributedSuitAI.setSuit(self, plan, variant, self.tutorial)

    def closeSuit(self):
        DistributedSuitAI.closeSuit(self)
        self.tutorial.sendUpdateToAvatarId(self.avatarId, 'suitExploded',
                                           [self.tutPartIndex])

    def startAttacks(self):
        base.taskMgr.doMethodLater(random.randint(*self.ATTACK_IVAL_RANGE),
                                   self.__doAttack,
                                   self.uniqueName('doAttack'))

    def __doAttack(self, task):
        return task.done
        base.taskMgr.remove(self.uniqueName('scwaa'))
        target = self.air.doId2do.get(self.avatarId)
        if not target:
            return task.done
        self.clearTrack()
        self.b_setSuitState(0, -1, -1)
        self.b_setAnimState('neutral')
        self.headsUp(target)
        # Choose a random attack and start it.
        attack = random.choice(self.suitPlan.getAttacks())
        attackCls = SuitAttacks.SuitAttacks.attack2attackClass[attack]
        taunts = attackCls.tauns
        attackTaunt = random.choice(taunts)
        timestamp = globalClockDelta.getFrameNetworkTime()
        if self.isDead():
            self.stopAttacks()
            return task.done
        self.sendUpdate('doAttack', [attack, target.doId, timestamp])
        self.d_setChat(attackTaunt)
        attackLength = attackCls.length
        base.taskMgr.doMethodLater(attackLength,
                                   self.__suitContinueWalkAfterAttack,
                                   self.uniqueName('scwaa'))

        task.delayTime = random.randint(*self.ATTACK_IVAL_RANGE)
        return task.again

    def __suitContinueWalkAfterAttack(self, task):
        self.createPath(fromCurPos=True)
        return task.done

    def stopAttacks(self):
        base.taskMgr.remove(self.uniqueName('doAttack'))

    def startAI(self):
        if self.tutPartIndex == 0:
            # This is part one, all we do is stand still and wait to die.
            self.b_setAnimState('neutral')
        elif self.tutPartIndex == 1:
            # This is part two, we just walk around and wait to die.
            self.createPath()
        elif self.tutPartIndex == 2:
            # This is part three, we walk around, attack a bit, and wait to die.
            self.createPath()
            self.startAttacks()