예제 #1
0
    def enterCogdo(self):
        assert (self.debugPrint("enterCogdo()"))

        # We have to send this message again, even though we've
        # already sent it in becomingCogdo, because we might have come
        # to this state directly on startup.
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])

        # Create the suit planner for the interior
        zoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
        self._cogdoLayout = CogdoLayout(self.numFloors)
        self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout,
                                                  self.difficulty, self.track,
                                                  interiorZoneId)

        self.d_setState('cogdo')
        # Create the DistributedDoor:
        exteriorZoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
        #todo: ...create the elevator.
        self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)

        self.air.writeServerEvent(
            'building-cogdo', self.doId,
            "%s|%s|%s" % (self.zoneId, self.block, self.numFloors))
예제 #2
0
 def enterCogdo(self):
     self.sendUpdate('setSuitData', [ord(self.realTrack), self.difficulty, self.numFloors])
     (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
     self._cogdoLayout = CogdoLayout(self.numFloors)
     self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout, self.difficulty, self.track, interiorZoneId)
     self.d_setState('cogdo')
     (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
     self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
     self.elevator.generateWithRequired(exteriorZoneId)
 def enterCogdo(self):
     self.sendUpdate('setSuitData', [ord(self.track), self.difficulty, self.numFloors])
     zoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
     self._cogdoLayout = CogdoLayout(self.numFloors)
     self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout, self.difficulty, self.track, interiorZoneId)
     self.d_setState('cogdo')
     exteriorZoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
     self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
     self.elevator.generateWithRequired(exteriorZoneId)
     self.air.writeServerEvent('building-cogdo', self.doId, '%s|%s|%s' % (self.zoneId, self.block, self.numFloors))
 def enterCogdo(self):
     self.sendUpdate('setSuitData', [ord(self.track), self.difficulty, self.numFloors])
     (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
     self._cogdoLayout = CogdoLayout(self.numFloors)
     self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout, self.difficulty, self.track, interiorZoneId)
     self.d_setState('cogdo')
     (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
     self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
     self.elevator.generateWithRequired(exteriorZoneId)
     self.air.writeServerEvent('building-cogdo', self.doId, '%s|%s|%s' % (self.zoneId, self.block, self.numFloors))
 def enterCogdo(self):
     self.sendUpdate('setSuitData', [
         ord(self.realTrack),
         self.difficulty,
         self.numFloors])
     (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
     self._cogdoLayout = CogdoLayout(self.numFloors)
     self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout, self.difficulty, self.track, interiorZoneId)
     self.d_setState('cogdo')
     (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
     self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
     self.elevator.generateWithRequired(exteriorZoneId)
예제 #6
0
class DistributedBuildingAI(DistributedObjectAI.DistributedObjectAI):
    def __init__(self, air, blockNumber, zoneId, trophyMgr):
        DistributedObjectAI.DistributedObjectAI.__init__(self, air)
        self.block = blockNumber
        self.zoneId = zoneId
        self.canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        self.trophyMgr = trophyMgr
        self.victorResponses = None
        self.fsm = ClassicFSM.ClassicFSM('DistributedBuildingAI', [
            State.State('off', self.enterOff, self.exitOff, [
                'waitForVictors', 'becomingToon', 'toon',
                'clearOutToonInterior', 'becomingSuit', 'suit',
                'clearOutToonInteriorForCogdo', 'becomingCogdo', 'cogdo'
            ]),
            State.State('waitForVictors', self.enterWaitForVictors,
                        self.exitWaitForVictors, ['becomingToon']),
            State.State(
                'waitForVictorsFromCogdo', self.enterWaitForVictorsFromCogdo,
                self.exitWaitForVictorsFromCogdo, ['becomingToonFromCogdo']),
            State.State('becomingToon', self.enterBecomingToon,
                        self.exitBecomingToon, ['toon']),
            State.State('becomingToonFromCogdo',
                        self.enterBecomingToonFromCogdo,
                        self.exitBecomingToonFromCogdo, ['toon']),
            State.State(
                'toon',
                self.enterToon, self.exitToon,
                ['clearOutToonInterior', 'clearOutToonInteriorForCogdo']),
            State.State('clearOutToonInterior', self.enterClearOutToonInterior,
                        self.exitClearOutToonInterior, ['becomingSuit']),
            State.State('becomingSuit', self.enterBecomingSuit,
                        self.exitBecomingSuit, ['suit']),
            State.State('suit', self.enterSuit, self.exitSuit,
                        ['waitForVictors', 'becomingToon']),
            State.State('clearOutToonInteriorForCogdo',
                        self.enterClearOutToonInteriorForCogdo,
                        self.exitClearOutToonInteriorForCogdo,
                        ['becomingCogdo']),
            State.State('becomingCogdo', self.enterBecomingCogdo,
                        self.exitBecomingCogdo, ['cogdo']),
            State.State('cogdo', self.enterCogdo, self.exitCogdo,
                        ['waitForVictorsFromCogdo', 'becomingToonFromCogdo'])
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.track = 'c'
        self.difficulty = 1
        self.numFloors = 0
        self.savedBy = None
        self.becameSuitTime = 0
        self.frontDoorPoint = None
        self.suitPlannerExt = None

    def cleanup(self):
        if self.isDeleted():
            return
        self.fsm.requestFinalState()
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
        if hasattr(self, 'door'):
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock
        if hasattr(self, 'elevator'):
            self.elevator.requestDelete()
            del self.elevator
        self.requestDelete()

    def delete(self):
        taskMgr.remove(self.taskName('suitbldg-time-out'))
        taskMgr.remove(self.taskName(str(self.block) + '_becomingToon-timer'))
        taskMgr.remove(self.taskName(str(self.block) + '_becomingSuit-timer'))
        DistributedObjectAI.DistributedObjectAI.delete(self)
        del self.fsm

    def getPickleData(self):
        pickleData = {
            'state': str(self.fsm.getCurrentState().getName()),
            'block': str(self.block),
            'track': str(self.track),
            'difficulty': str(self.difficulty),
            'numFloors': str(self.numFloors),
            'savedBy': self.savedBy,
            'becameSuitTime': self.becameSuitTime
        }
        return pickleData

    def _getMinMaxFloors(self, difficulty):
        return SuitBuildingGlobals.SuitBuildingInfo[difficulty][0]

    def suitTakeOver(self, suitTrack, difficulty, buildingHeight):
        if not self.isToonBlock():
            return
        self.updateSavedBy(None)
        difficulty = min(difficulty,
                         len(SuitBuildingGlobals.SuitBuildingInfo) - 1)
        (minFloors, maxFloors) = self._getMinMaxFloors(difficulty)
        if buildingHeight is None:
            numFloors = random.randint(minFloors, maxFloors)
        else:
            numFloors = buildingHeight + 1
            if (numFloors < minFloors) or (numFloors > maxFloors):
                numFloors = random.randint(minFloors, maxFloors)
        self.track = suitTrack
        self.difficulty = difficulty
        self.numFloors = numFloors
        self.becameSuitTime = time.time()
        self.fsm.request('clearOutToonInterior')

    def cogdoTakeOver(self, difficulty, buildingHeight):
        if not self.isToonBlock():
            return
        self.updateSavedBy(None)
        (minFloors, maxFloors) = self._getMinMaxFloors(difficulty)
        if buildingHeight is None:
            numFloors = random.randint(minFloors, maxFloors)
        else:
            numFloors = buildingHeight + 1
            if (numFloors < minFloors) or (numFloors > maxFloors):
                numFloors = random.randint(minFloors, maxFloors)
        self.track = 'c'
        self.difficulty = difficulty
        self.numFloors = numFloors
        self.becameSuitTime = time.time()
        self.fsm.request('clearOutToonInteriorForCogdo')

    def toonTakeOver(self):
        if 'cogdo' in self.fsm.getCurrentState().getName().lower():
            self.fsm.request('becomingToonFromCogdo')
        else:
            self.fsm.request('becomingToon')
        if self.suitPlannerExt:
            self.suitPlannerExt.recycleBuilding()
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior

    def getFrontDoorPoint(self):
        return self.frontDoorPoint

    def setFrontDoorPoint(self, point):
        self.frontDoorPoint = point

    def getBlock(self):
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        return [self.block, interiorZoneId]

    def getSuitData(self):
        return [ord(self.track), self.difficulty, self.numFloors]

    def getState(self):
        return [
            self.fsm.getCurrentState().getName(),
            globalClockDelta.getRealNetworkTime()
        ]

    def setState(self, state, timestamp=0):
        self.fsm.request(state)

    def isSuitBuilding(self):
        state = self.fsm.getCurrentState().getName()
        return state in ('suit', 'becomingSuit', 'clearOutToonInterior')

    def isCogdo(self):
        state = self.fsm.getCurrentState().getName()
        return state in ('cogdo', 'becomingCogdo',
                         'clearOutToonInteriorForCogdo')

    def isSuitBlock(self):
        return self.isSuitBuilding() or self.isCogdo()

    def isEstablishedSuitBlock(self):
        state = self.fsm.getCurrentState().getName()
        return state == 'suit'

    def isToonBlock(self):
        state = self.fsm.getCurrentState().getName()
        return state in ('toon', 'becomingToon', 'becomingToonFromCogdo')

    def getExteriorAndInteriorZoneId(self):
        blockNumber = self.block
        dnaStore = self.air.dnaStoreMap[self.canonicalZoneId]
        zoneId = dnaStore.getZoneFromBlockNumber(blockNumber)
        zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
        interiorZoneId = (zoneId - (zoneId % 100)) + 500 + blockNumber
        return (zoneId, interiorZoneId)

    def d_setState(self, state):
        self.sendUpdate('setState',
                        [state, globalClockDelta.getRealNetworkTime()])

    def b_setVictorList(self, victorList):
        self.setVictorList(victorList)
        self.d_setVictorList(victorList)

    def d_setVictorList(self, victorList):
        self.sendUpdate('setVictorList', [victorList])

    def setVictorList(self, victorList):
        self.victorList = victorList

    def findVictorIndex(self, avId):
        for i in xrange(len(self.victorList)):
            if self.victorList[i] == avId:
                return i

    def recordVictorResponse(self, avId):
        index = self.findVictorIndex(avId)
        if index is None:
            self.air.writeServerEvent(
                'suspicious', avId,
                'DistributedBuildingAI.setVictorReady from toon not in %s.' %
                self.victorList)
            return
        self.victorResponses[index] = avId

    def allVictorsResponded(self):
        if self.victorResponses == self.victorList:
            return 1
        else:
            return 0

    def setVictorReady(self):
        avId = self.air.getAvatarIdFromSender()
        if self.victorResponses is None:
            self.air.writeServerEvent(
                'suspicious', avId,
                'DistributedBuildingAI.setVictorReady in state %s.' %
                self.fsm.getCurrentState().getName())
            return
        self.recordVictorResponse(avId)
        event = self.air.getAvatarExitEvent(avId)
        self.ignore(event)
        if self.allVictorsResponded():
            self.toonTakeOver()

    def setVictorExited(self, avId):
        print 'victor %d exited unexpectedly for bldg %d' % (avId, self.doId)
        self.recordVictorResponse(avId)
        if self.allVictorsResponded():
            self.toonTakeOver()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def getToon(self, toonId):
        if self.air.doId2do.has_key(toonId):
            return self.air.doId2do[toonId]
        else:
            self.notify.warning('getToon() - toon: %d not in repository!' %
                                toonId)

    def updateSavedBy(self, savedBy):
        if self.savedBy:
            for (avId, name, dna) in self.savedBy:
                if not ZoneUtil.isWelcomeValley(self.zoneId):
                    self.trophyMgr.removeTrophy(avId, self.numFloors)
        self.savedBy = savedBy
        if self.savedBy:
            for (avId, name, dna) in self.savedBy:
                if not ZoneUtil.isWelcomeValley(self.zoneId):
                    self.trophyMgr.addTrophy(avId, name, self.numFloors)

    def enterWaitForVictors(self, victorList, savedBy):
        activeToons = []
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
            if toon is not None:
                activeToons.append(toon)
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
                self.air.writeServerEvent(
                    'buildingDefeated', t, '%s|%s|%s|%s' %
                    (self.track, self.numFloors, self.zoneId, victorList))
            if toon is not None:
                self.air.questManager.toonKilledBuilding(
                    toon, self.track, self.difficulty, self.numFloors,
                    self.zoneId, activeToons)
        for i in xrange(0, 4):
            victor = victorList[i]
            if (victor is None) or (victor not in self.air.doId2do):
                victorList[i] = 0
                continue
            event = self.air.getAvatarExitEvent(victor)
            self.accept(event, self.setVictorExited, extraArgs=[victor])
        self.b_setVictorList(victorList)
        self.updateSavedBy(savedBy)
        self.victorResponses = [0, 0, 0, 0]
        self.d_setState('waitForVictors')

    def exitWaitForVictors(self):
        self.victorResponses = None
        for victor in self.victorList:
            event = simbase.air.getAvatarExitEvent(victor)
            self.ignore(event)

    def enterWaitForVictorsFromCogdo(self, victorList, savedBy):
        activeToons = []
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
            if toon is not None:
                activeToons.append(toon)
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
                self.air.writeServerEvent(
                    'buildingDefeated', t, '%s|%s|%s|%s' %
                    (self.track, self.numFloors, self.zoneId, victorList))
            if toon is not None:
                self.air.questManager.toonKilledCogdo(toon, self.difficulty,
                                                      self.numFloors,
                                                      self.zoneId, activeToons)
        for i in xrange(0, 4):
            victor = victorList[i]
            if (victor is None) or (victor not in self.air.doId2do):
                victorList[i] = 0
                continue
            event = self.air.getAvatarExitEvent(victor)
            self.accept(event, self.setVictorExited, extraArgs=[victor])
        self.b_setVictorList(victorList)
        self.updateSavedBy(savedBy)
        self.victorResponses = [0, 0, 0, 0]
        self.d_setState('waitForVictorsFromCogdo')

    def exitWaitForVictorsFromCogdo(self):
        self.victorResponses = None
        for victor in self.victorList:
            event = simbase.air.getAvatarExitEvent(victor)
            self.ignore(event)

    def enterBecomingToon(self):
        self.d_setState('becomingToon')
        name = self.taskName(str(self.block) + '_becomingToon-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_SEQUENCE_TIME,
                              self.becomingToonTask, name)

    def exitBecomingToon(self):
        name = self.taskName(str(self.block) + '_becomingToon-timer')
        taskMgr.remove(name)

    def enterBecomingToonFromCogdo(self):
        self.d_setState('becomingToonFromCogdo')
        name = self.taskName(str(self.block) + '_becomingToonFromCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_SEQUENCE_TIME,
                              self.becomingToonTask, name)

    def exitBecomingToonFromCogdo(self):
        name = self.taskName(str(self.block) + '_becomingToonFromCogdo-timer')
        taskMgr.remove(name)

    def becomingToonTask(self, task):
        self.fsm.request('toon')
        self.suitPlannerExt.buildingMgr.save()
        self.trophyMgr.save()
        return Task.done

    def enterToon(self):
        self.d_setState('toon')
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        if simbase.config.GetBool(
                'want-new-toonhall',
                1) and ZoneUtil.getCanonicalZoneId(interiorZoneId) == ToonHall:
            self.interior = DistributedToonHallInteriorAI.DistributedToonHallInteriorAI(
                self.block, self.air, interiorZoneId, self)
        else:
            self.interior = DistributedToonInteriorAI.DistributedToonInteriorAI(
                self.block, self.air, interiorZoneId, self)
        self.interior.generateWithRequired(interiorZoneId)
        door = self.createExteriorDoor()
        insideDoor = DistributedDoorAI.DistributedDoorAI(
            self.air, self.block, DoorTypes.INT_STANDARD)
        door.setOtherDoor(insideDoor)
        insideDoor.setOtherDoor(door)
        door.zoneId = exteriorZoneId
        insideDoor.zoneId = interiorZoneId
        door.generateWithRequired(exteriorZoneId)
        insideDoor.generateWithRequired(interiorZoneId)
        self.door = door
        self.insideDoor = insideDoor
        self.becameSuitTime = 0
        self.knockKnock = DistributedKnockKnockDoorAI.DistributedKnockKnockDoorAI(
            self.air, self.block)
        self.knockKnock.generateWithRequired(exteriorZoneId)
        self.air.writeServerEvent('building-toon', self.doId,
                                  '%s|%s' % (self.zoneId, self.block))

    def createExteriorDoor(self):
        result = DistributedDoorAI.DistributedDoorAI(self.air, self.block,
                                                     DoorTypes.EXT_STANDARD)
        return result

    def exitToon(self):
        self.door.setDoorLock(FADoorCodes.BUILDING_TAKEOVER)

    def enterClearOutToonInterior(self):
        self.d_setState('clearOutToonInterior')
        if hasattr(self, 'interior'):
            self.interior.setState('beingTakenOver')
        name = self.taskName(str(self.block) + '_clearOutToonInterior-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME,
                              self.clearOutToonInteriorTask, name)

    def exitClearOutToonInterior(self):
        name = self.taskName(str(self.block) + '_clearOutToonInterior-timer')
        taskMgr.remove(name)

    def clearOutToonInteriorTask(self, task):
        self.fsm.request('becomingSuit')
        return Task.done

    def enterBecomingSuit(self):
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])
        self.d_setState('becomingSuit')
        name = self.taskName(str(self.block) + '_becomingSuit-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.TO_SUIT_BLDG_TIME,
                              self.becomingSuitTask, name)

    def exitBecomingSuit(self):
        name = self.taskName(str(self.block) + '_becomingSuit-timer')
        taskMgr.remove(name)
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock

    def becomingSuitTask(self, task):
        self.fsm.request('suit')
        self.suitPlannerExt.buildingMgr.save()
        return Task.done

    def enterSuit(self):
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])
        (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.planner = SuitPlannerInteriorAI.SuitPlannerInteriorAI(
            self.numFloors, self.difficulty, self.track, interiorZoneId)
        self.d_setState('suit')
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.elevator = DistributedElevatorExtAI.DistributedElevatorExtAI(
            self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)
        self.air.writeServerEvent(
            'building-cog', self.doId, '%s|%s|%s|%s' %
            (self.zoneId, self.block, self.track, self.numFloors))

    def exitSuit(self):
        del self.planner
        if hasattr(self, 'elevator'):
            self.elevator.requestDelete()
            del self.elevator

    def enterClearOutToonInteriorForCogdo(self):
        self.d_setState('clearOutToonInteriorForCogdo')
        if hasattr(self, 'interior'):
            self.interior.setState('beingTakenOver')
        name = self.taskName(
            str(self.block) + '_clearOutToonInteriorForCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME,
                              self.clearOutToonInteriorForCogdoTask, name)

    def exitClearOutToonInteriorForCogdo(self):
        name = self.taskName(
            str(self.block) + '_clearOutToonInteriorForCogdo-timer')
        taskMgr.remove(name)

    def clearOutToonInteriorForCogdoTask(self, task):
        self.fsm.request('becomingCogdo')
        return Task.done

    def enterBecomingCogdo(self):
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])
        self.d_setState('becomingCogdo')
        name = self.taskName(str(self.block) + '_becomingCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.TO_SUIT_BLDG_TIME,
                              self.becomingCogdoTask, name)

    def exitBecomingCogdo(self):
        name = self.taskName(str(self.block) + '_becomingCogdo-timer')
        taskMgr.remove(name)
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock

    def becomingCogdoTask(self, task):
        self.fsm.request('cogdo')
        self.suitPlannerExt.buildingMgr.save()
        return Task.done

    def enterCogdo(self):
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])
        (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self._cogdoLayout = CogdoLayout(self.numFloors)
        self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout,
                                                  self.difficulty, self.track,
                                                  interiorZoneId)
        self.d_setState('cogdo')
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)
        self.air.writeServerEvent(
            'building-cogdo', self.doId,
            '%s|%s|%s' % (self.zoneId, self.block, self.numFloors))

    def exitCogdo(self):
        del self.planner
        if hasattr(self, 'elevator'):
            self.elevator.requestDelete()
            del self.elevator

    def setSuitPlannerExt(self, planner):
        self.suitPlannerExt = planner

    def _createSuitInterior(self):
        return DistributedSuitInteriorAI.DistributedSuitInteriorAI(
            self.air, self.elevator)

    def _createCogdoInterior(self):
        return DistributedCogdoInteriorAI(self.air, self.elevator)

    def createSuitInterior(self):
        self.interior = self._createSuitInterior()
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.interior.fsm.request('WaitForAllToonsInside')
        self.interior.generateWithRequired(interiorZoneId)

    def createCogdoInterior(self):
        self.interior = self._createCogdoInterior()
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.interior.fsm.request('WaitForAllToonsInside')
        self.interior.generateWithRequired(interiorZoneId)

    def deleteSuitInterior(self):
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
        if hasattr(self, 'elevator'):
            self.elevator.d_setFloor(-1)
            self.elevator.open()

    def deleteCogdoInterior(self):
        self.deleteSuitInterior()
class DistributedBuildingAI(DistributedObjectAI.DistributedObjectAI):
    
    def __init__(self, air, blockNumber, zoneId, trophyMgr):
        DistributedObjectAI.DistributedObjectAI.__init__(self, air)
        self.block = blockNumber
        self.zoneId = zoneId
        self.canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        self.trophyMgr = trophyMgr
        self.victorResponses = None
        self.fsm = ClassicFSM.ClassicFSM('DistributedBuildingAI', [
            State.State('off', self.enterOff, self.exitOff, [
                'waitForVictors',
                'becomingToon',
                'toon',
                'clearOutToonInterior',
                'becomingSuit',
                'suit',
                'clearOutToonInteriorForCogdo',
                'becomingCogdo',
                'cogdo']),
            State.State('waitForVictors', self.enterWaitForVictors, self.exitWaitForVictors, [
                'becomingToon']),
            State.State('waitForVictorsFromCogdo', self.enterWaitForVictorsFromCogdo, self.exitWaitForVictorsFromCogdo, [
                'becomingToonFromCogdo']),
            State.State('becomingToon', self.enterBecomingToon, self.exitBecomingToon, [
                'toon']),
            State.State('becomingToonFromCogdo', self.enterBecomingToonFromCogdo, self.exitBecomingToonFromCogdo, [
                'toon']),
            State.State('toon', self.enterToon, self.exitToon, [
                'clearOutToonInterior',
                'clearOutToonInteriorForCogdo']),
            State.State('clearOutToonInterior', self.enterClearOutToonInterior, self.exitClearOutToonInterior, [
                'becomingSuit']),
            State.State('becomingSuit', self.enterBecomingSuit, self.exitBecomingSuit, [
                'suit']),
            State.State('suit', self.enterSuit, self.exitSuit, [
                'waitForVictors',
                'becomingToon']),
            State.State('clearOutToonInteriorForCogdo', self.enterClearOutToonInteriorForCogdo, self.exitClearOutToonInteriorForCogdo, [
                'becomingCogdo']),
            State.State('becomingCogdo', self.enterBecomingCogdo, self.exitBecomingCogdo, [
                'cogdo']),
            State.State('cogdo', self.enterCogdo, self.exitCogdo, [
                'waitForVictorsFromCogdo',
                'becomingToonFromCogdo'])], 'off', 'off')
        self.fsm.enterInitialState()
        self.track = 'c'
        self.realTrack = 'c'
        self.difficulty = 1
        self.numFloors = 0
        self.savedBy = None
        self.becameSuitTime = 0
        self.frontDoorPoint = None
        self.suitPlannerExt = None

    
    def cleanup(self):
        if self.isDeleted():
            return None
        
        self.fsm.requestFinalState()
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
        
        if hasattr(self, 'door'):
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock
        
        if hasattr(self, 'elevator'):
            self.elevator.requestDelete()
            del self.elevator
        
        self.requestDelete()

    
    def delete(self):
        taskMgr.remove(self.taskName('suitbldg-time-out'))
        taskMgr.remove(self.taskName(str(self.block) + '_becomingToon-timer'))
        taskMgr.remove(self.taskName(str(self.block) + '_becomingSuit-timer'))
        DistributedObjectAI.DistributedObjectAI.delete(self)
        del self.fsm

    
    def getPickleData(self):
        pickleData = {
            'state': str(self.fsm.getCurrentState().getName()),
            'block': str(self.block),
            'track': str(self.track),
            'difficulty': str(self.difficulty),
            'numFloors': str(self.numFloors),
            'savedBy': self.savedBy,
            'becameSuitTime': self.becameSuitTime }
        return pickleData

    
    def _getMinMaxFloors(self, difficulty):
        return SuitBuildingGlobals.SuitBuildingInfo[difficulty][0]

    
    def suitTakeOver(self, suitTrack, difficulty, buildingHeight):
        print 'Building %s (%s): suitTakeOver' % (self.doId, self.zoneId)
        if not self.isToonBlock():
            return None

        self.updateSavedBy(None)
        
        self.realTrack = suitTrack
        
        if random.random() < (1 - config.GetFloat('lt-ratio', .06)):
            difficulty = min(difficulty, len(SuitBuildingGlobals.SuitBuildingInfo) - 1)
            (minFloors, maxFloors) = self._getMinMaxFloors(difficulty)
            if buildingHeight == None:
                numFloors = random.randint(minFloors, maxFloors)
            else:
                numFloors = buildingHeight + 1
                if numFloors < minFloors or numFloors > maxFloors:
                    numFloors = random.randint(minFloors, maxFloors)
                    
        else:
            self.realTrack = "x"
            difficulty = 19
            numFloors = random.choice((1, 5))
            print '\tLT', numFloors
            
        self.track = suitTrack
        self.difficulty = difficulty
        self.numFloors = numFloors
        self.becameSuitTime = time.time()
        self.fsm.request('clearOutToonInterior')

        self.air.apiMgr.d_updateBlock(self)
        
    def cogdoTakeOver(self, difficulty, buildingHeight, track = 's'):
        print 'Building %s (%s): cogdoTakeOver' % (self.doId, self.zoneId)
        if not self.isToonBlock():
            return None
        
        self.updateSavedBy(None)
            
        self.track = track
        self.realTrack = track
        self.difficulty = difficulty
        self.numFloors = 0
        self.becameSuitTime = time.time()
        self.fsm.request('clearOutToonInteriorForCogdo')
        
        self.air.apiMgr.d_updateBlock(self)
    
    def toonTakeOver(self):
        if 'cogdo' in self.fsm.getCurrentState().getName().lower():
            self.fsm.request('becomingToonFromCogdo')
        else:
            self.fsm.request('becomingToon')
        if self.suitPlannerExt:
            self.suitPlannerExt.recycleBuilding()
        
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
        
        self.air.apiMgr.d_updateBlock(self)
    
    def getFrontDoorPoint(self):
        return self.frontDoorPoint

    
    def setFrontDoorPoint(self, point):
        self.frontDoorPoint = point

    
    def getBlock(self):
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        return [
            self.block,
            interiorZoneId]

    
    def getSuitData(self):
        return [
            ord(self.realTrack),
            self.difficulty,
            self.numFloors]

    
    def getState(self):
        return [
            self.fsm.getCurrentState().getName(),
            globalClockDelta.getRealNetworkTime()]

    
    def setState(self, state, timestamp = 0):
        self.fsm.request(state)

    
    def isSuitBuilding(self):
        state = self.fsm.getCurrentState().getName()
        return state in ('suit', 'becomingSuit', 'clearOutToonInterior')

    
    def isCogdo(self):
        state = self.fsm.getCurrentState().getName()
        return state in ('cogdo', 'becomingCogdo', 'clearOutToonInteriorForCogdo')

    
    def isSuitBlock(self):
        return self.isSuitBuilding() or self.isCogdo()

    
    def isEstablishedSuitBlock(self):
        state = self.fsm.getCurrentState().getName()
        return state == 'suit'

    
    def isToonBlock(self):
        state = self.fsm.getCurrentState().getName()
        return state in ('toon', 'becomingToon', 'becomingToonFromCogdo')

    
    def getExteriorAndInteriorZoneId(self):
        blockNumber = self.block
        dnaStore = self.air.getStorage(self.canonicalZoneId)
        zoneId = dnaStore.getZoneFromBlockNumber(blockNumber)
        zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
        interiorZoneId = (zoneId - zoneId % 100) + 500 + blockNumber
        return (zoneId, interiorZoneId)

    
    def d_setState(self, state):
        self.sendUpdate('setState', [
            state,
            globalClockDelta.getRealNetworkTime()])

    
    def b_setVictorList(self, victorList):
        self.setVictorList(victorList)
        self.d_setVictorList(victorList)

    
    def d_setVictorList(self, victorList):
        self.sendUpdate('setVictorList', [
            victorList])

    
    def setVictorList(self, victorList):
        self.victorList = victorList

    
    def findVictorIndex(self, avId):
        for i in range(len(self.victorList)):
            if self.victorList[i] == avId:
                return i
                continue
        

    
    def recordVictorResponse(self, avId):
        if not self.victorResponses:
            return
            
        index = self.findVictorIndex(avId)
        if index == None:
            self.air.writeServerEvent('suspicious', avId, 'DistributedBuildingAI.setVictorReady from toon not in %s.' % self.victorList)
            return None
        
        self.victorResponses[index] = avId

    
    def allVictorsResponded(self):
        numWaiting = len(filter(None, self.victorList))
        numReady = len(filter(None, self.victorResponses))
        
        return numWaiting == numReady
    
    def setVictorReady(self):
        avId = self.air.getAvatarIdFromSender()
        if self.victorResponses == None:
            self.air.writeServerEvent('suspicious', avId, 'DistributedBuildingAI.setVictorReady in state %s.' % self.fsm.getCurrentState().getName())
            return None
        
        print 'victor %d ready' % avId
        self.recordVictorResponse(avId)
        event = self.air.getAvatarExitEvent(avId)
        self.ignore(event)
        if self.allVictorsResponded():
            self.toonTakeOver()
        

    
    def setVictorExited(self, avId):
        print 'victor %d exited unexpectedly for bldg %d' % (avId, self.doId)
        self.recordVictorResponse(avId)
        if self.allVictorsResponded():
            self.toonTakeOver()
        

    
    def enterOff(self):
        pass

    
    def exitOff(self):
        pass

    
    def getToon(self, toonId):
        if self.air.doId2do.has_key(toonId):
            return self.air.doId2do[toonId]
        else:
            self.notify.warning('getToon() - toon: %d not in repository!' % toonId)

    def getBuildingHash(self):
        return self.zoneId << 16 | self.block
    
    def updateSavedBy(self, savedBy):
        if self.savedBy:
            for (avId, name, dna) in self.savedBy:
                if not ZoneUtil.isWelcomeValley(self.zoneId):
                    if self.trophyMgr:
                        self.trophyMgr.removeTrophy(self, avId)
        
        self.savedBy = savedBy
        if self.savedBy:
            for (avId, name, dna) in self.savedBy:
                if not ZoneUtil.isWelcomeValley(self.zoneId):
                    if self.trophyMgr and not self.isCogdo():
                        self.trophyMgr.addTrophy(self, avId, name, self.numFloors)
    
    def enterWaitForVictors(self, victorList, savedBy):
        activeToons = []
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
            
            if toon != None:
                activeToons.append(toon)
                continue
        
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
                self.air.writeServerEvent('buildingDefeated', t, '%s|%s|%s|%s' % (self.track, self.numFloors, self.zoneId, victorList))
            
            if toon != None:
                self.air.questManager.toonKilledBuilding(toon, self.track, self.difficulty, self.numFloors, self.zoneId, activeToons)
                continue
        
        for i in range(0, 4):
            victor = victorList[i]
            if victor == None or not self.air.doId2do.has_key(victor):
                victorList[i] = 0
                continue
            event = self.air.getAvatarExitEvent(victor)
            self.accept(event, self.setVictorExited, extraArgs = [
                victor])
        
        self.b_setVictorList(victorList)
        self.updateSavedBy(savedBy)
        self.victorResponses = [
            0,
            0,
            0,
            0]
        self.d_setState('waitForVictors')

    
    def exitWaitForVictors(self):
        self.victorResponses = None
        for victor in self.victorList:
            event = simbase.air.getAvatarExitEvent(victor)
            self.ignore(event)
        

    
    def enterWaitForVictorsFromCogdo(self, victorList, savedBy):
        activeToons = []
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
            
            if toon != None:
                activeToons.append(toon)
                continue
        
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
                self.air.writeServerEvent('buildingDefeated', t, '%s|%s|%s|%s' % (self.track, self.numFloors, self.zoneId, victorList))
            
            if toon != None:
                self.air.questManager.toonKilledCogdo(toon, self.track, self.difficulty, self.numFloors, self.zoneId, activeToons)
                continue
        
        victorList.extend([None, None, None, None])
        for i in range(0, 4):
            victor = victorList[i]
            if victor == None or not self.air.doId2do.has_key(victor):
                victorList[i] = 0
                continue
            event = self.air.getAvatarExitEvent(victor)
            self.accept(event, self.setVictorExited, extraArgs = [
                victor])
        
        self.b_setVictorList(victorList[:4])
        self.updateSavedBy(savedBy)
        self.victorResponses = [
            0,
            0,
            0,
            0]
        self.d_setState('waitForVictorsFromCogdo')

    
    def exitWaitForVictorsFromCogdo(self):
        self.victorResponses = None
        for victor in self.victorList:
            event = simbase.air.getAvatarExitEvent(victor)
            self.ignore(event)
        

    
    def enterBecomingToon(self):
        self.d_setState('becomingToon')
        name = self.taskName(str(self.block) + '_becomingToon-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_SEQUENCE_TIME, self.becomingToonTask, name)

    
    def exitBecomingToon(self):
        name = self.taskName(str(self.block) + '_becomingToon-timer')
        taskMgr.remove(name)

    
    def enterBecomingToonFromCogdo(self):
        self.d_setState('becomingToonFromCogdo')
        name = self.taskName(str(self.block) + '_becomingToonFromCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_SEQUENCE_TIME, self.becomingToonTask, name)

    
    def exitBecomingToonFromCogdo(self):
        name = self.taskName(str(self.block) + '_becomingToonFromCogdo-timer')
        taskMgr.remove(name)

    
    def becomingToonTask(self, task):
        self.fsm.request('toon')
        self.suitPlannerExt.buildingMgr.save()
        return Task.done

    
    def enterToon(self):
        self.d_setState('toon')
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        if simbase.config.GetBool('want-new-toonhall', 1) and ZoneUtil.getCanonicalZoneId(interiorZoneId) == ToonHall:
            self.interior = DistributedToonHallInteriorAI.DistributedToonHallInteriorAI(self.block, self.air, interiorZoneId, self)
        else:
            self.interior = DistributedToonInteriorAI.DistributedToonInteriorAI(self.block, self.air, interiorZoneId, self)
        self.interior.generateWithRequired(interiorZoneId)
        door = self.createExteriorDoor()
        insideDoor = DistributedDoorAI.DistributedDoorAI(self.air, self.block, DoorTypes.INT_STANDARD)
        door.setOtherDoor(insideDoor)
        insideDoor.setOtherDoor(door)
        door.zoneId = exteriorZoneId
        insideDoor.zoneId = interiorZoneId
        door.generateWithRequired(exteriorZoneId)
        insideDoor.generateWithRequired(interiorZoneId)
        self.door = door
        self.insideDoor = insideDoor
        self.becameSuitTime = 0
        self.knockKnock = DistributedKnockKnockDoorAI.DistributedKnockKnockDoorAI(self.air, self.block)
        self.knockKnock.generateWithRequired(exteriorZoneId)
        
    def createExteriorDoor(self):
        result = DistributedDoorAI.DistributedDoorAI(self.air, self.block, DoorTypes.EXT_STANDARD)
        return result

    
    def exitToon(self):
        self.door.setDoorLock(FADoorCodes.BUILDING_TAKEOVER)

    
    def enterClearOutToonInterior(self):
        self.d_setState('clearOutToonInterior')
        if hasattr(self, 'interior'):
            self.interior.setState('beingTakenOver')
        
        name = self.taskName(str(self.block) + '_clearOutToonInterior-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME, self.clearOutToonInteriorTask, name)

    
    def exitClearOutToonInterior(self):
        name = self.taskName(str(self.block) + '_clearOutToonInterior-timer')
        taskMgr.remove(name)

    
    def clearOutToonInteriorTask(self, task):
        self.fsm.request('becomingSuit')
        return Task.done

    
    def enterBecomingSuit(self):
        self.sendUpdate('setSuitData', [
            ord(self.realTrack),
            self.difficulty,
            self.numFloors])
        self.d_setState('becomingSuit')
        name = self.taskName(str(self.block) + '_becomingSuit-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.TO_SUIT_BLDG_TIME, self.becomingSuitTask, name)

    
    def exitBecomingSuit(self):
        name = self.taskName(str(self.block) + '_becomingSuit-timer')
        taskMgr.remove(name)
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock
        

    
    def becomingSuitTask(self, task):
        self.fsm.request('suit')
        self.suitPlannerExt.buildingMgr.save()
        return Task.done

    
    def enterSuit(self):
        self.sendUpdate('setSuitData', [
            ord(self.realTrack),
            self.difficulty,
            self.numFloors])
        (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.planner = SuitPlannerInteriorAI.SuitPlannerInteriorAI(self.numFloors, self.difficulty, self.realTrack, interiorZoneId)
        self.d_setState('suit')
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.elevator = DistributedElevatorExtAI.DistributedElevatorExtAI(self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)
        
    def exitSuit(self):
        del self.planner
        if hasattr(self, 'elevator'):
            self.elevator.requestDelete()
            del self.elevator
        

    
    def enterClearOutToonInteriorForCogdo(self):
        self.d_setState('clearOutToonInteriorForCogdo')
        if hasattr(self, 'interior'):
            self.interior.setState('beingTakenOver')
        
        name = self.taskName(str(self.block) + '_clearOutToonInteriorForCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME, self.clearOutToonInteriorForCogdoTask, name)

    
    def exitClearOutToonInteriorForCogdo(self):
        name = self.taskName(str(self.block) + '_clearOutToonInteriorForCogdo-timer')
        taskMgr.remove(name)

    
    def clearOutToonInteriorForCogdoTask(self, task):
        self.fsm.request('becomingCogdo')
        return Task.done

    
    def enterBecomingCogdo(self):
        self.sendUpdate('setSuitData', [
            ord(self.realTrack),
            self.difficulty,
            self.numFloors])
        self.d_setState('becomingCogdo')
        name = self.taskName(str(self.block) + '_becomingCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.TO_SUIT_BLDG_TIME, self.becomingCogdoTask, name)

    
    def exitBecomingCogdo(self):
        name = self.taskName(str(self.block) + '_becomingCogdo-timer')
        taskMgr.remove(name)
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock
        

    
    def becomingCogdoTask(self, task):
        self.fsm.request('cogdo')
        self.suitPlannerExt.buildingMgr.save()
        return Task.done

    
    def enterCogdo(self):
        self.sendUpdate('setSuitData', [
            ord(self.realTrack),
            self.difficulty,
            self.numFloors])
        (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self._cogdoLayout = CogdoLayout(self.numFloors)
        self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout, self.difficulty, self.track, interiorZoneId)
        self.d_setState('cogdo')
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)
        
    def exitCogdo(self):
        del self.planner
        if hasattr(self, 'elevator'):
            self.elevator.requestDelete()
            del self.elevator
        

    
    def setSuitPlannerExt(self, planner):
        self.suitPlannerExt = planner

    
    def _createSuitInterior(self):
        return DistributedSuitInteriorAI.DistributedSuitInteriorAI(self.air, self.elevator)

    
    def _createCogdoInterior(self):
        return DistributedCogdoInteriorAI(self.air, self)

    
    def createSuitInterior(self):
        self.interior = self._createSuitInterior()
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.interior.fsm.request('WaitForAllToonsInside')
        self.interior.generateWithRequired(interiorZoneId)

    
    def createCogdoInterior(self):
        self.interior = self._createCogdoInterior()
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.interior.generateWithRequired(interiorZoneId)
        self.interior.b_setState('WaitForAllToonsInside')

    
    def deleteSuitInterior(self):
        if hasattr(self, 'interior'):
            self.interior.requestDelete()
            del self.interior
        
        if hasattr(self, 'elevator'):
            self.elevator.d_setFloor(-1)
            self.elevator.open()
        

    
    def deleteCogdoInterior(self):
        self.deleteSuitInterior()
예제 #8
0
class DistributedBuildingAI(DistributedObjectAI.DistributedObjectAI):
    """
    DistributedBuildingAI class:  The server side representation of a
    single building.  This is the object that remember who 'owns' the
    associated building (either the bad guys or the toons).  The child
    of this object, the DistributedBuilding object, is the client side
    version and updates the display that client's display based on who
    'owns' the building.
    """

    if __debug__:
        notify = DirectNotifyGlobal.directNotify.newCategory(
            'DistributedBuildingAI')

    FieldOfficeNumFloors = 1

    def __init__(self, air, blockNumber, zoneId, trophyMgr):
        """blockNumber: the landmark building number (from the name)"""
        DistributedObjectAI.DistributedObjectAI.__init__(self, air)
        self.block = blockNumber
        assert (self.debugPrint("DistributedBuildingAI(%s, %s)" %
                                ("the air", str(blockNumber))))
        self.zoneId = zoneId
        self.canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        self.trophyMgr = trophyMgr
        self.victorResponses = None
        self.fsm = ClassicFSM.ClassicFSM(
            'DistributedBuildingAI',
            [
                State.State('off', self.enterOff, self.exitOff, [
                    'waitForVictors',
                    'becomingToon',
                    'toon',
                    'clearOutToonInterior',
                    'becomingSuit',
                    'suit',
                    'clearOutToonInteriorForCogdo',
                    'becomingCogdo',
                    'becomingCogdoFromCogdo'
                    'cogdo',
                ]),
                State.State('waitForVictors', self.enterWaitForVictors,
                            self.exitWaitForVictors, [
                                'becomingToon',
                            ]),
                State.State(
                    'waitForVictorsFromCogdo',
                    self.enterWaitForVictorsFromCogdo,
                    self.exitWaitForVictorsFromCogdo,
                    ['becomingToonFromCogdo', 'becomingCogdoFromCogdo']),
                State.State('becomingToon', self.enterBecomingToon,
                            self.exitBecomingToon, ['toon']),
                State.State('becomingToonFromCogdo',
                            self.enterBecomingToonFromCogdo,
                            self.exitBecomingToonFromCogdo, ['toon']),
                State.State(
                    'toon', self.enterToon, self.exitToon,
                    ['clearOutToonInterior', 'clearOutToonInteriorForCogdo']),
                State.State('clearOutToonInterior',
                            self.enterClearOutToonInterior,
                            self.exitClearOutToonInterior, ['becomingSuit']),
                State.State('becomingSuit', self.enterBecomingSuit,
                            self.exitBecomingSuit, ['suit']),
                State.State(
                    'suit',
                    self.enterSuit,
                    self.exitSuit,
                    [
                        'waitForVictors',
                        'becomingToon',  # debug only
                    ]),
                State.State('clearOutToonInteriorForCogdo',
                            self.enterClearOutToonInteriorForCogdo,
                            self.exitClearOutToonInteriorForCogdo,
                            ['becomingCogdo']),
                State.State('becomingCogdo', self.enterBecomingCogdo,
                            self.exitBecomingCogdo, ['cogdo']),
                State.State('becomingCogdoFromCogdo',
                            self.enterBecomingCogdoFromCogdo,
                            self.exitBecomingCogdoFromCogdo, ['cogdo']),
                State.State(
                    'cogdo',
                    self.enterCogdo,
                    self.exitCogdo,
                    [
                        'waitForVictorsFromCogdo',
                        'becomingToonFromCogdo',  # debug only
                    ])
            ],
            # Initial State
            'off',
            # Final State
            'off',
        )
        self.fsm.enterInitialState()
        self.track = 'c'
        self.difficulty = 1
        self.numFloors = 0
        self.savedBy = None
        self.becameSuitTime = 0
        self.frontDoorPoint = None
        self.suitPlannerExt = None

    def cleanup(self):
        if self.isDeleted():
            return

        self.fsm.requestFinalState()

        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior

        if hasattr(self, "door"):
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock

        if hasattr(self, "elevator"):
            self.elevator.requestDelete()
            del self.elevator

        self.requestDelete()

    def delete(self):
        """
        ////////////////////////////////////////////////////////////////////
        // Function:   clean up tasks that might still be running for this
        //             building
        // Parameters:
        // Changes:
        ////////////////////////////////////////////////////////////////////
        """
        # make sure to remove any tasks we might have created
        taskMgr.remove(self.taskName('suitbldg-time-out'))

        # remove the doLater associated with the state transition of
        # a suit building becoming a toon building
        taskMgr.remove(self.taskName(str(self.block) + '_becomingToon-timer'))

        # remove the doLater associated with the state transition of
        # a toon building becoming a suit building
        taskMgr.remove(self.taskName(str(self.block) + '_becomingSuit-timer'))

        DistributedObjectAI.DistributedObjectAI.delete(self)

        del self.fsm

    def getPickleData(self):
        assert (self.debugPrint("getPickleData()"))
        pickleData = {
            'state': str(self.fsm.getCurrentState().getName()),
            'block': str(self.block),
            'track': str(self.track),
            'difficulty': str(self.difficulty),
            'numFloors': str(self.numFloors),
            'savedBy': self.savedBy,
            'becameSuitTime': self.becameSuitTime,
        }
        return pickleData

    def _getMinMaxFloors(self, difficulty):
        return SuitBuildingGlobals.SuitBuildingInfo[difficulty][0]

    def suitTakeOver(self, suitTrack, difficulty, buildingHeight):
        """Switch from toon to suit building
        suitTrack: one of 'c', 'l', 'm', or 's'
        difficulty: 0+
        buildingHeight: 0..4, or None to choose based on the difficulty.
        """
        if not self.isToonBlock():
            return
        assert (suitTrack in ['c', 'l', 'm', 's'])

        # Remove the old saved by credit with the old number of floors
        self.updateSavedBy(None)

        difficulty = min(difficulty,
                         len(SuitBuildingGlobals.SuitBuildingInfo) - 1)
        minFloors, maxFloors = self._getMinMaxFloors(difficulty)
        if buildingHeight == None:
            # Pick a random floor number from the appropriate range.
            numFloors = random.randint(minFloors, maxFloors)
        else:
            # The number of floors is specified.
            numFloors = buildingHeight + 1

            if (numFloors < minFloors or numFloors > maxFloors):
                # Hmm, the number of floors is out of range for this
                # suit.  There must be an invasion in effect.  In that
                # case, go ahead and make a building of any height
                # appropriate to the suit.
                numFloors = random.randint(minFloors, maxFloors)

        assert (self.debugPrint("suitTakeOver(%s, %s, %s)" %
                                (suitTrack, difficulty, numFloors - 1)))

        self.track = suitTrack
        self.difficulty = difficulty
        self.numFloors = numFloors
        self.becameSuitTime = time.time()
        self.fsm.request('clearOutToonInterior')

    def cogdoTakeOver(self, suitTrack, difficulty, buildingHeight):
        if not self.isToonBlock():
            return

        numFloors = self.FieldOfficeNumFloors
        self.track = suitTrack
        self.difficulty = difficulty
        self.numFloors = numFloors
        self.becameSuitTime = time.time()
        self.fsm.request('clearOutToonInteriorForCogdo')

    def toonTakeOver(self):
        """Switch from suit to toon building
        savedBy: a list of 1 to 4 avatar [name, style] lists."""
        assert (self.debugPrint("toonTakeOver(savedBy=%s)" % (self.savedBy)))
        isCogdo = 'cogdo' in self.fsm.getCurrentState().getName().lower()
        takenOver = True
        if isCogdo:
            if self.buildingDefeated:
                self.fsm.request('becomingToonFromCogdo')
            else:
                self.fsm.request('becomingCogdoFromCogdo')
                takenOver = False
        else:
            self.fsm.request('becomingToon')
        if self.suitPlannerExt:
            self.suitPlannerExt.recycleBuilding(isCogdo)
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior

    def getFrontDoorPoint(self):
        """get any associated path point for this building, useful for
           suits to know where to go when exiting from a building"""
        assert (self.debugPrint("getFrontDoorPoint()"))
        return self.frontDoorPoint

    def setFrontDoorPoint(self, point):
        """set the associated front door point with this building"""
        assert (self.debugPrint("setFrontDoorPoint(%s)" % (str(point))))
        self.frontDoorPoint = point

    def getBlock(self):
        assert (self.debugPrint("getBlock()"))
        dummy, interiorZoneId = self.getExteriorAndInteriorZoneId()
        return [self.block, interiorZoneId]

    def getSuitData(self):
        assert (self.debugPrint("getSuitData()"))
        return [ord(self.track), self.difficulty, self.numFloors]

    def getState(self):
        assert (self.debugPrint("getState()"))
        return [
            self.fsm.getCurrentState().getName(),
            globalClockDelta.getRealNetworkTime()
        ]

    def setState(self, state, timestamp=0):
        assert (self.notify.debug(
            str(self.block) + " setState(state=" + str(state) + ")"))
        self.fsm.request(state)

    def isSuitBuilding(self):
        """return true if that block is a suit building"""
        assert (self.debugPrint("isSuitBlock()"))
        state = self.fsm.getCurrentState().getName()
        return state=='suit' or state=='becomingSuit' or \
               state=='clearOutToonInterior'

    def isCogdo(self):
        """return true if that block is a cogdo"""
        assert (self.debugPrint("isSuitBlock()"))
        state = self.fsm.getCurrentState().getName()
        return state=='cogdo' or state=='becomingCogdo' or \
               state=='becomingCogdoFromCogdo' or \
               state=='clearOutToonInteriorForCogdo'

    def isSuitBlock(self):
        """return true if that block is a suit block/building/cogdo"""
        assert (self.debugPrint("isSuitBlock()"))
        state = self.fsm.getCurrentState().getName()
        return self.isSuitBuilding() or self.isCogdo()

    def isEstablishedSuitBlock(self):
        """return true if that block is a fully established suit building"""
        assert (self.debugPrint("isEstablishedSuitBlock()"))
        state = self.fsm.getCurrentState().getName()
        return state == 'suit'

    def isToonBlock(self):
        """return true if that block is a toon block/building"""
        assert (self.debugPrint("isToonBlock()"))
        state = self.fsm.getCurrentState().getName()
        return state in (
            'toon',
            'becomingToon',
            'becomingToonFromCogdo',
        )

    def getExteriorAndInteriorZoneId(self):
        assert (self.notify.debug(str(self.block) + " getInteriorZoneId()"))
        blockNumber = self.block
        assert (blockNumber < 100
                )  # this may cause trouble for the interiorZoneId,
        # it may bump into the next higher zone range.
        dnaStore = self.air.dnaStoreMap[self.canonicalZoneId]
        zoneId = dnaStore.getZoneFromBlockNumber(blockNumber)
        zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
        interiorZoneId = (zoneId - zoneId % 100) + 500 + blockNumber
        assert (self.notify.debug(
            str(self.block) + " getInteriorZoneId() returning" +
            str(interiorZoneId)))
        return zoneId, interiorZoneId

    def d_setState(self, state):
        assert (self.notify.debug(
            str(self.block) + " d_setState(state=" + str(state) + ")"))
        self.sendUpdate('setState',
                        [state, globalClockDelta.getRealNetworkTime()])

    def b_setVictorList(self, victorList):
        self.setVictorList(victorList)
        self.d_setVictorList(victorList)
        return

    def d_setVictorList(self, victorList):
        self.sendUpdate("setVictorList", [victorList])
        return

    def setVictorList(self, victorList):
        self.victorList = victorList
        return

    def findVictorIndex(self, avId):
        for i in range(len(self.victorList)):
            if self.victorList[i] == avId:
                return i
        return None

    def recordVictorResponse(self, avId):
        index = self.findVictorIndex(avId)
        if index == None:
            self.air.writeServerEvent(
                'suspicious', avId,
                'DistributedBuildingAI.setVictorReady from toon not in %s.' %
                (self.victorList))
            return

        assert (self.victorResponses[index] == 0
                or self.victorResponses[index] == avId)
        self.victorResponses[index] = avId

    def allVictorsResponded(self):
        if self.victorResponses == self.victorList:
            return 1
        else:
            return 0

    def setVictorReady(self):
        avId = self.air.getAvatarIdFromSender()
        if self.victorResponses == None:
            self.air.writeServerEvent(
                'suspicious', avId,
                'DistributedBuildingAI.setVictorReady in state %s.' %
                (self.fsm.getCurrentState().getName()))
            return

        assert (self.notify.debug("victor %d is ready for bldg %d" %
                                  (avId, self.doId)))
        self.recordVictorResponse(avId)

        # Don't tell us about this avatar exiting any more.
        event = self.air.getAvatarExitEvent(avId)
        self.ignore(event)

        if self.allVictorsResponded():
            self.toonTakeOver()

    def setVictorExited(self, avId):
        print("victor %d exited unexpectedly for bldg %d" % (avId, self.doId))
        self.recordVictorResponse(avId)
        if self.allVictorsResponded():
            self.toonTakeOver()

    ##### off state #####

    def enterOff(self):
        assert (self.debugPrint("enterOff()"))

    def exitOff(self):
        assert (self.debugPrint("exitOff()"))

    ##### waitForVictors state #####

    def getToon(self, toonId):
        if (toonId in self.air.doId2do):
            return self.air.doId2do[toonId]
        else:
            self.notify.warning('getToon() - toon: %d not in repository!' \
                % toonId)
        return None

    def updateSavedBy(self, savedBy):
        # Clear the old savedBy from the trophy manager
        if self.savedBy:
            for avId, name, dna in self.savedBy:
                # Don't change building take over score when the toon is in the welcome valley.
                if not ZoneUtil.isWelcomeValley(self.zoneId):
                    self.trophyMgr.removeTrophy(avId, self.numFloors)
        # Update the new saved by list
        self.savedBy = savedBy
        if self.savedBy:
            for avId, name, dna in self.savedBy:
                # Don't change building take over score when the toon is in the welcome valley.
                if not ZoneUtil.isWelcomeValley(self.zoneId):
                    self.trophyMgr.addTrophy(avId, name, self.numFloors)

    def enterWaitForVictors(self, victorList, savedBy):
        assert (len(victorList) == 4)

        # Grab the list of active toons to pass in for each toon
        # (this is used by the quest system)
        activeToons = []
        for t in victorList:
            toon = None
            if (t):
                toon = self.getToon(t)
            if (toon != None):
                activeToons.append(toon)
        # Tell the quest manager that these toons defeated this building
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
                self.air.writeServerEvent(
                    'buildingDefeated', t, "%s|%s|%s|%s" %
                    (self.track, self.numFloors, self.zoneId, victorList))

            if toon != None:
                self.air.questManager.toonKilledBuilding(
                    toon, self.track, self.difficulty, self.numFloors,
                    self.zoneId, activeToons)

        # Convert the list to all ints. 0 means no one is there.
        # Also, if a toon has disconnected, remove him from the list.
        for i in range(0, 4):
            victor = victorList[i]
            if victor == None or victor not in self.air.doId2do:
                victorList[i] = 0

            else:
                # Handle unexpected exit messages for everyone else.
                event = self.air.getAvatarExitEvent(victor)
                self.accept(event, self.setVictorExited, extraArgs=[victor])

        # Save the list and also tell it to all the clients.
        self.b_setVictorList(victorList)
        self.updateSavedBy(savedBy)
        # List of victor responses
        self.victorResponses = [0, 0, 0, 0]
        # Tell the client to go into waitForVictors state
        self.d_setState("waitForVictors")
        return

    def exitWaitForVictors(self):
        # Stop waiting for unexpected exits.
        self.victorResponses = None
        for victor in self.victorList:
            event = simbase.air.getAvatarExitEvent(victor)
            self.ignore(event)
        return

    def enterWaitForVictorsFromCogdo(self, victorList, savedBy):
        assert (len(victorList) == 4)

        # Grab the list of active toons to pass in for each toon
        # (this is used by the quest system)
        activeToons = []
        for t in victorList:
            toon = None
            if (t):
                toon = self.getToon(t)
            if (toon != None):
                activeToons.append(toon)
        self.buildingDefeated = len(savedBy) > 0
        if self.buildingDefeated:
            # Tell the quest manager that these toons defeated this building
            for t in victorList:
                toon = None
                if t:
                    toon = self.getToon(t)
                    self.air.writeServerEvent(
                        'buildingDefeated', t, "%s|%s|%s|%s" %
                        (self.track, self.numFloors, self.zoneId, victorList))

            if toon != None:
                self.air.questManager.toonKilledCogdo(toon, self.difficulty,
                                                      self.numFloors,
                                                      self.zoneId, activeToons)

        # Convert the list to all ints. 0 means no one is there.
        # Also, if a toon has disconnected, remove him from the list.
        for i in range(0, 4):
            victor = victorList[i]
            if victor == None or victor not in self.air.doId2do:
                victorList[i] = 0

            else:
                # Handle unexpected exit messages for everyone else.
                event = self.air.getAvatarExitEvent(victor)
                self.accept(event, self.setVictorExited, extraArgs=[victor])

        # Save the list and also tell it to all the clients.
        self.b_setVictorList(victorList)
        self.updateSavedBy(savedBy)
        # List of victor responses
        self.victorResponses = [0, 0, 0, 0]
        # Tell the client to go into waitForVictors state
        self.d_setState("waitForVictorsFromCogdo")
        return

    def exitWaitForVictorsFromCogdo(self):
        # Stop waiting for unexpected exits.
        self.victorResponses = None
        for victor in self.victorList:
            event = simbase.air.getAvatarExitEvent(victor)
            self.ignore(event)
        return

    ##### becomingToon state #####

    def enterBecomingToon(self):
        assert (self.debugPrint("enterBecomingToon()"))
        self.d_setState('becomingToon')
        name = self.taskName(str(self.block) + '_becomingToon-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_SEQUENCE_TIME,
                              self.becomingToonTask, name)

    def exitBecomingToon(self):
        assert (self.debugPrint("exitBecomingToon()"))
        name = self.taskName(str(self.block) + '_becomingToon-timer')
        taskMgr.remove(name)

    ##### becomingToonFromCogdo state #####

    def enterBecomingToonFromCogdo(self):
        assert (self.debugPrint("enterBecomingToonFromCogdo()"))
        self.d_setState('becomingToonFromCogdo')
        name = self.taskName(str(self.block) + '_becomingToonFromCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_SEQUENCE_TIME,
                              self.becomingToonTask, name)

    def exitBecomingToonFromCogdo(self):
        assert (self.debugPrint("exitBecomingToonFromCogdo()"))
        name = self.taskName(str(self.block) + '_becomingToonFromCogdo-timer')
        taskMgr.remove(name)

    ##### toon state #####

    def becomingToonTask(self, task):
        assert (self.debugPrint("becomingToonTask()"))
        self.fsm.request("toon")

        # Save the building state whenever we convert a building to
        # toonness.
        self.suitPlannerExt.buildingMgr.save()

        return Task.done

    def enterToon(self):
        assert (self.debugPrint("enterToon()"))
        self.d_setState('toon')
        # Create the DistributedDoor:
        exteriorZoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
        # Toon interior:
        if ConfigVariableBool("want-new-toonhall",1).getValue() and \
           ZoneUtil.getCanonicalZoneId(interiorZoneId)== ToonHall:
            self.interior = DistributedToonHallInteriorAI.DistributedToonHallInteriorAI(
                self.block, self.air, interiorZoneId, self)
        else:
            self.interior = DistributedToonInteriorAI.DistributedToonInteriorAI(
                self.block, self.air, interiorZoneId, self)
        self.interior.generateWithRequired(interiorZoneId)

        # Outside door:
        door = self.createExteriorDoor()
        # Inside of the same door (different zone, and different distributed object):
        insideDoor = DistributedDoorAI.DistributedDoorAI(
            self.air, self.block, DoorTypes.INT_STANDARD)
        # Tell them about each other:
        door.setOtherDoor(insideDoor)
        insideDoor.setOtherDoor(door)
        door.zoneId = exteriorZoneId
        insideDoor.zoneId = interiorZoneId
        # Now that they both now about each other, generate them:
        door.generateWithRequired(exteriorZoneId)
        insideDoor.generateWithRequired(interiorZoneId)
        # keep track of them:
        self.door = door
        self.insideDoor = insideDoor
        self.becameSuitTime = 0

        self.knockKnock = DistributedKnockKnockDoorAI.DistributedKnockKnockDoorAI(
            self.air, self.block)
        self.knockKnock.generateWithRequired(exteriorZoneId)

        self.air.writeServerEvent('building-toon', self.doId,
                                  "%s|%s" % (self.zoneId, self.block))

    def createExteriorDoor(self):
        """Return the DistributedDoor for the exterior, with correct door type set"""
        # Created so animated buildings can over ride this function
        result = DistributedDoorAI.DistributedDoorAI(self.air, self.block,
                                                     DoorTypes.EXT_STANDARD)
        return result

    def exitToon(self):
        assert (self.debugPrint("exitToon()"))
        self.door.setDoorLock(FADoorCodes.BUILDING_TAKEOVER)
        # The door doesn't get unlocked, because
        # it will be distroyed and recreated.

    ##### clearOutToonInterior state #####

    def enterClearOutToonInterior(self):
        assert (self.debugPrint("enterClearOutToonInterior()"))
        self.d_setState('clearOutToonInterior')
        if hasattr(self, "interior"):
            self.interior.setState("beingTakenOver")
        name = self.taskName(str(self.block) + '_clearOutToonInterior-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME,
                              self.clearOutToonInteriorTask, name)

    def exitClearOutToonInterior(self):
        assert (self.debugPrint("exitClearOutToonInterior()"))
        name = self.taskName(str(self.block) + '_clearOutToonInterior-timer')
        taskMgr.remove(name)

    ##### becomingSuit state #####

    def clearOutToonInteriorTask(self, task):
        assert (self.debugPrint("clearOutToonInteriorTask()"))
        self.fsm.request("becomingSuit")
        return Task.done

    def enterBecomingSuit(self):
        assert (self.debugPrint("enterBecomingSuit()"))

        # We have to send this message before we send the distributed
        # update to becomingSuit state, because the clients depend on
        # knowing what kind of suit building we're becoming.
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])

        self.d_setState('becomingSuit')
        name = self.taskName(str(self.block) + '_becomingSuit-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.TO_SUIT_BLDG_TIME,
                              self.becomingSuitTask, name)

    def exitBecomingSuit(self):
        assert (self.debugPrint("exitBecomingSuit()"))
        name = self.taskName(str(self.block) + '_becomingSuit-timer')
        taskMgr.remove(name)
        # Clean up the toon distributed objects:
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock

    ##### suit state #####

    def becomingSuitTask(self, task):
        assert (self.debugPrint("becomingSuitTask()"))
        self.fsm.request("suit")

        # Save the building state whenever we convert a building to
        # suitness.
        self.suitPlannerExt.buildingMgr.save()

        return Task.done

    def enterSuit(self):
        assert (self.debugPrint("enterSuit()"))

        # We have to send this message again, even though we've
        # already sent it in becomingSuit, because we might have come
        # to this state directly on startup.
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])

        # Create the suit planner for the interior
        zoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
        self.planner = SuitPlannerInteriorAI.SuitPlannerInteriorAI(
            self.numFloors, self.difficulty, self.track, interiorZoneId)

        self.d_setState('suit')
        # Create the DistributedDoor:
        exteriorZoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
        #todo: ...create the elevator.
        self.elevator = DistributedElevatorExtAI.DistributedElevatorExtAI(
            self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)

        self.air.writeServerEvent(
            'building-cog', self.doId, "%s|%s|%s|%s" %
            (self.zoneId, self.block, self.track, self.numFloors))

    def exitSuit(self):
        assert (self.debugPrint("exitSuit()"))
        del self.planner
        # Clean up the suit distributed objects:
        if hasattr(self, "elevator"):
            self.elevator.requestDelete()
            del self.elevator

    ##### clearOutToonInteriorForCogdo state #####

    def enterClearOutToonInteriorForCogdo(self):
        assert (self.debugPrint("enterClearOutToonInteriorForCogdo()"))
        self.d_setState('clearOutToonInteriorForCogdo')
        if hasattr(self, "interior"):
            self.interior.setState("beingTakenOver")
        name = self.taskName(
            str(self.block) + '_clearOutToonInteriorForCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME,
                              self.clearOutToonInteriorForCogdoTask, name)

    def exitClearOutToonInteriorForCogdo(self):
        assert (self.debugPrint("exitClearOutToonInteriorForCogdo()"))
        name = self.taskName(
            str(self.block) + '_clearOutToonInteriorForCogdo-timer')
        taskMgr.remove(name)

    ##### becomingCogdo state #####

    def clearOutToonInteriorForCogdoTask(self, task):
        assert (self.debugPrint("clearOutToonInteriorForCogdoTask()"))
        self.fsm.request("becomingCogdo")
        return Task.done

    def enterBecomingCogdo(self):
        assert (self.debugPrint("enterBecomingCogdo()"))

        # We have to send this message before we send the distributed
        # update to becomingCogdo state, because the clients depend on
        # knowing what kind of cogdo building we're becoming.
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])

        self.d_setState('becomingCogdo')
        name = self.taskName(str(self.block) + '_becomingCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.TO_SUIT_BLDG_TIME,
                              self.becomingCogdoTask, name)

    def exitBecomingCogdo(self):
        assert (self.debugPrint("exitBecomingCogdo()"))
        name = self.taskName(str(self.block) + '_becomingCogdo-timer')
        taskMgr.remove(name)
        # Clean up the toon distributed objects:
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock

    ##### becomingCogdoFromCogdo state #####

    def enterBecomingCogdoFromCogdo(self):
        assert (self.debugPrint("enterBecomingCogdoFromCogdo()"))
        self.d_setState('becomingCogdoFromCogdo')
        name = self.taskName(str(self.block) + '_becomingCogdoFromCogdo-timer')
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_RUN_TIME,
                              self.becomingCogdoTask, name)

    def exitBecomingCogdoFromCogdo(self):
        assert (self.debugPrint("exitBecomingCogdoFromCogdo()"))
        self.fSkipElevatorOpening = True
        name = self.taskName(str(self.block) + '_becomingCogdoFromCogdo-timer')
        taskMgr.remove(name)

    ##### cogdo state #####

    def becomingCogdoTask(self, task):
        assert (self.debugPrint("becomingCogdoTask()"))
        self.fsm.request("cogdo")

        # Save the building state whenever we convert a building to
        # cogdoness.
        self.suitPlannerExt.buildingMgr.save()

        return Task.done

    def enterCogdo(self):
        assert (self.debugPrint("enterCogdo()"))

        # We have to send this message again, even though we've
        # already sent it in becomingCogdo, because we might have come
        # to this state directly on startup.
        self.sendUpdate('setSuitData',
                        [ord(self.track), self.difficulty, self.numFloors])

        # Create the suit planner for the interior
        zoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
        self._cogdoLayout = CogdoLayout(self.numFloors)
        self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout,
                                                  self.difficulty, self.track,
                                                  interiorZoneId)

        self.d_setState('cogdo')
        # Create the DistributedDoor:
        exteriorZoneId, interiorZoneId = self.getExteriorAndInteriorZoneId()
        #todo: ...create the elevator.
        self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)

        self.air.writeServerEvent(
            'building-cogdo', self.doId,
            "%s|%s|%s" % (self.zoneId, self.block, self.numFloors))

    def exitCogdo(self):
        assert (self.debugPrint("exitCogdo()"))
        del self.planner
        # Clean up the cogdo distributed objects:
        if hasattr(self, "elevator"):
            self.elevator.requestDelete()
            del self.elevator

    def setSuitPlannerExt(self, planner):
        """
        ////////////////////////////////////////////////////////////////////
        // Function:   let the building know which suit planner contains
        //             its building manager
        // Parameters: planner, the governing suit planner for this bldg
        // Changes:
        ////////////////////////////////////////////////////////////////////
        """
        self.suitPlannerExt = planner

    def _createSuitInterior(self):
        return DistributedSuitInteriorAI.DistributedSuitInteriorAI(
            self.air, self.elevator)

    def _createCogdoInterior(self):
        return DistributedCogdoInteriorAI(self.air, self.elevator)

    def createSuitInterior(self):
        # Create a building interior in the new (interior) zone
        self.interior = self._createSuitInterior()
        dummy, interiorZoneId = self.getExteriorAndInteriorZoneId()
        self.interior.fsm.request('WaitForAllToonsInside')
        self.interior.generateWithRequired(interiorZoneId)

    def createCogdoInterior(self):
        # Create a building interior in the new (interior) zone
        self.interior = self._createCogdoInterior()
        dummy, interiorZoneId = self.getExteriorAndInteriorZoneId()
        self.interior.fsm.request('WaitForAllToonsInside')
        self.interior.generateWithRequired(interiorZoneId)

    def deleteSuitInterior(self):
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior
        if hasattr(self, "elevator"):
            # -1 means the lobby.
            self.elevator.d_setFloor(-1)
            self.elevator.open()

    def deleteCogdoInterior(self):
        self.deleteSuitInterior()

    if __debug__:

        def debugPrint(self, message):
            """for debugging"""
            return self.notify.debug(
                str(self.__dict__.get('block', '?')) + ' ' + message)
예제 #9
0
class DistributedBuildingAI(DistributedObjectAI.DistributedObjectAI):
    def __init__(self, air, blockNumber, zoneId, trophyMgr):
        DistributedObjectAI.DistributedObjectAI.__init__(self, air)
        self.block = blockNumber
        self.zoneId = zoneId
        self.canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        self.trophyMgr = trophyMgr
        self.victorResponses = None
        self.fsm = ClassicFSM.ClassicFSM(
            "DistributedBuildingAI",
            [
                State.State(
                    "off",
                    self.enterOff,
                    self.exitOff,
                    [
                        "waitForVictors",
                        "becomingToon",
                        "toon",
                        "clearOutToonInterior",
                        "becomingSuit",
                        "suit",
                        "clearOutToonInteriorForCogdo",
                        "becomingCogdo",
                        "cogdo",
                    ],
                ),
                State.State("waitForVictors", self.enterWaitForVictors, self.exitWaitForVictors, ["becomingToon"]),
                State.State(
                    "waitForVictorsFromCogdo",
                    self.enterWaitForVictorsFromCogdo,
                    self.exitWaitForVictorsFromCogdo,
                    ["becomingToonFromCogdo"],
                ),
                State.State("becomingToon", self.enterBecomingToon, self.exitBecomingToon, ["toon"]),
                State.State(
                    "becomingToonFromCogdo", self.enterBecomingToonFromCogdo, self.exitBecomingToonFromCogdo, ["toon"]
                ),
                State.State(
                    "toon", self.enterToon, self.exitToon, ["clearOutToonInterior", "clearOutToonInteriorForCogdo"]
                ),
                State.State(
                    "clearOutToonInterior",
                    self.enterClearOutToonInterior,
                    self.exitClearOutToonInterior,
                    ["becomingSuit"],
                ),
                State.State("becomingSuit", self.enterBecomingSuit, self.exitBecomingSuit, ["suit"]),
                State.State("suit", self.enterSuit, self.exitSuit, ["waitForVictors", "becomingToon"]),
                State.State(
                    "clearOutToonInteriorForCogdo",
                    self.enterClearOutToonInteriorForCogdo,
                    self.exitClearOutToonInteriorForCogdo,
                    ["becomingCogdo"],
                ),
                State.State("becomingCogdo", self.enterBecomingCogdo, self.exitBecomingCogdo, ["cogdo"]),
                State.State(
                    "cogdo", self.enterCogdo, self.exitCogdo, ["waitForVictorsFromCogdo", "becomingToonFromCogdo"]
                ),
            ],
            "off",
            "off",
        )
        self.fsm.enterInitialState()
        self.track = "c"
        self.difficulty = 1
        self.numFloors = 0
        self.savedBy = None
        self.becameSuitTime = 0
        self.frontDoorPoint = None
        self.suitPlannerExt = None

    def cleanup(self):
        if self.isDeleted():
            return
        self.fsm.requestFinalState()
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior
        if hasattr(self, "door"):
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock
        if hasattr(self, "elevator"):
            self.elevator.requestDelete()
            del self.elevator
        self.requestDelete()

    def delete(self):
        self.cleanup()
        taskMgr.remove(self.taskName("suitbldg-time-out"))
        taskMgr.remove(self.taskName(str(self.block) + "_becomingToon-timer"))
        taskMgr.remove(self.taskName(str(self.block) + "_becomingSuit-timer"))
        DistributedObjectAI.DistributedObjectAI.delete(self)
        del self.fsm

    def getPickleData(self):
        pickleData = {
            "state": str(self.fsm.getCurrentState().getName()),
            "block": str(self.block),
            "track": str(self.track),
            "difficulty": str(self.difficulty),
            "numFloors": str(self.numFloors),
            "savedBy": self.savedBy,
            "becameSuitTime": self.becameSuitTime,
        }
        return pickleData

    def _getMinMaxFloors(self, difficulty):
        return SuitBuildingGlobals.SuitBuildingInfo[difficulty][0]

    def suitTakeOver(self, suitTrack, difficulty, buildingHeight):
        if not self.isToonBlock():
            return
        self.updateSavedBy(None)
        difficulty = min(difficulty, len(SuitBuildingGlobals.SuitBuildingInfo) - 1)
        (minFloors, maxFloors) = self._getMinMaxFloors(difficulty)
        if buildingHeight is None:
            numFloors = random.randint(minFloors, maxFloors)
        else:
            numFloors = buildingHeight + 1
            if (numFloors < minFloors) or (numFloors > maxFloors):
                numFloors = random.randint(minFloors, maxFloors)
        self.track = suitTrack
        self.difficulty = difficulty
        self.numFloors = numFloors
        self.becameSuitTime = time.time()
        self.fsm.request("clearOutToonInterior")

    def cogdoTakeOver(self, difficulty, buildingHeight):
        if not self.isToonBlock():
            return
        self.updateSavedBy(None)
        (minFloors, maxFloors) = self._getMinMaxFloors(difficulty)
        if buildingHeight is None:
            numFloors = random.randint(minFloors, maxFloors)
        else:
            numFloors = buildingHeight + 1
            if (numFloors < minFloors) or (numFloors > maxFloors):
                numFloors = random.randint(minFloors, maxFloors)
        self.track = "c"
        self.difficulty = difficulty
        self.numFloors = numFloors
        self.becameSuitTime = time.time()
        self.fsm.request("clearOutToonInteriorForCogdo")

    def toonTakeOver(self):
        if "cogdo" in self.fsm.getCurrentState().getName().lower():
            self.fsm.request("becomingToonFromCogdo")
        else:
            self.fsm.request("becomingToon")
        if self.suitPlannerExt:
            self.suitPlannerExt.recycleBuilding()
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior

    def getFrontDoorPoint(self):
        return self.frontDoorPoint

    def setFrontDoorPoint(self, point):
        self.frontDoorPoint = point

    def getBlock(self):
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        return [self.block, interiorZoneId]

    def getSuitData(self):
        return [ord(self.track), self.difficulty, self.numFloors]

    def getState(self):
        return [self.fsm.getCurrentState().getName(), globalClockDelta.getRealNetworkTime()]

    def setState(self, state, timestamp=0):
        self.fsm.request(state)

    def isSuitBuilding(self):
        state = self.fsm.getCurrentState().getName()
        return state in ("suit", "becomingSuit", "clearOutToonInterior")

    def isCogdo(self):
        state = self.fsm.getCurrentState().getName()
        return state in ("cogdo", "becomingCogdo", "clearOutToonInteriorForCogdo")

    def isSuitBlock(self):
        return self.isSuitBuilding() or self.isCogdo()

    def isEstablishedSuitBlock(self):
        state = self.fsm.getCurrentState().getName()
        return state == "suit"

    def isToonBlock(self):
        state = self.fsm.getCurrentState().getName()
        return state in ("toon", "becomingToon", "becomingToonFromCogdo")

    def getExteriorAndInteriorZoneId(self):
        blockNumber = self.block
        dnaStore = self.air.dnaStoreMap[self.canonicalZoneId]
        zoneId = dnaStore.getZoneFromBlockNumber(blockNumber)
        zoneId = ZoneUtil.getTrueZoneId(zoneId, self.zoneId)
        interiorZoneId = (zoneId - (zoneId % 100)) + 500 + blockNumber
        return (zoneId, interiorZoneId)

    def d_setState(self, state):
        self.sendUpdate("setState", [state, globalClockDelta.getRealNetworkTime()])

    def b_setVictorList(self, victorList):
        self.setVictorList(victorList)
        self.d_setVictorList(victorList)

    def d_setVictorList(self, victorList):
        self.sendUpdate("setVictorList", [victorList])

    def setVictorList(self, victorList):
        self.victorList = victorList

    def findVictorIndex(self, avId):
        for i in xrange(len(self.victorList)):
            if self.victorList[i] == avId:
                return i

    def recordVictorResponse(self, avId):
        index = self.findVictorIndex(avId)
        if index is None:
            self.air.writeServerEvent(
                "suspicious", avId, "DistributedBuildingAI.setVictorReady from toon not in %s." % self.victorList
            )
            return
        self.victorResponses[index] = avId

    def allVictorsResponded(self):
        if self.victorResponses == self.victorList:
            return 1
        else:
            return 0

    def setVictorReady(self):
        avId = self.air.getAvatarIdFromSender()
        if self.victorResponses is None:
            self.air.writeServerEvent(
                "suspicious",
                avId,
                "DistributedBuildingAI.setVictorReady in state %s." % self.fsm.getCurrentState().getName(),
            )
            return
        self.recordVictorResponse(avId)
        event = self.air.getAvatarExitEvent(avId)
        self.ignore(event)
        if self.allVictorsResponded():
            self.toonTakeOver()

    def setVictorExited(self, avId):
        print "victor %d exited unexpectedly for bldg %d" % (avId, self.doId)
        self.recordVictorResponse(avId)
        if self.allVictorsResponded():
            self.toonTakeOver()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def getToon(self, toonId):
        if toonId in self.air.doId2do:
            return self.air.doId2do[toonId]
        else:
            self.notify.warning("getToon() - toon: %d not in repository!" % toonId)

    def updateSavedBy(self, savedBy):
        if self.savedBy:
            for (avId, name, dna) in self.savedBy:
                if not ZoneUtil.isWelcomeValley(self.zoneId):
                    self.trophyMgr.removeTrophy(avId, self.numFloors)
        self.savedBy = savedBy
        if self.savedBy:
            for (avId, name, dna) in self.savedBy:
                if not ZoneUtil.isWelcomeValley(self.zoneId):
                    self.trophyMgr.addTrophy(avId, name, self.numFloors)

    def enterWaitForVictors(self, victorList, savedBy):
        activeToons = []
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
            if toon is not None:
                activeToons.append(toon)
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
                self.air.writeServerEvent(
                    "buildingDefeated", t, "%s|%s|%s|%s" % (self.track, self.numFloors, self.zoneId, victorList)
                )
            if toon is not None:
                self.air.questManager.toonKilledBuilding(
                    toon, self.track, self.difficulty, self.numFloors, self.zoneId, activeToons
                )
        for i in xrange(0, 4):
            victor = victorList[i]
            if (victor is None) or (victor not in self.air.doId2do):
                victorList[i] = 0
                continue
            event = self.air.getAvatarExitEvent(victor)
            self.accept(event, self.setVictorExited, extraArgs=[victor])
        self.b_setVictorList(victorList)
        self.updateSavedBy(savedBy)
        self.victorResponses = [0, 0, 0, 0]
        self.d_setState("waitForVictors")

    def exitWaitForVictors(self):
        self.victorResponses = None
        for victor in self.victorList:
            event = simbase.air.getAvatarExitEvent(victor)
            self.ignore(event)

    def enterWaitForVictorsFromCogdo(self, victorList, savedBy):
        activeToons = []
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
            if toon is not None:
                activeToons.append(toon)
        for t in victorList:
            toon = None
            if t:
                toon = self.getToon(t)
                self.air.writeServerEvent(
                    "buildingDefeated", t, "%s|%s|%s|%s" % (self.track, self.numFloors, self.zoneId, victorList)
                )
            if toon is not None:
                self.air.questManager.toonKilledCogdo(toon, self.difficulty, self.numFloors, self.zoneId, activeToons)
        for i in xrange(0, 4):
            victor = victorList[i]
            if (victor is None) or (victor not in self.air.doId2do):
                victorList[i] = 0
                continue
            event = self.air.getAvatarExitEvent(victor)
            self.accept(event, self.setVictorExited, extraArgs=[victor])
        self.b_setVictorList(victorList)
        self.updateSavedBy(savedBy)
        self.victorResponses = [0, 0, 0, 0]
        self.d_setState("waitForVictorsFromCogdo")

    def exitWaitForVictorsFromCogdo(self):
        self.victorResponses = None
        for victor in self.victorList:
            event = simbase.air.getAvatarExitEvent(victor)
            self.ignore(event)

    def enterBecomingToon(self):
        self.d_setState("becomingToon")
        name = self.taskName(str(self.block) + "_becomingToon-timer")
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_SEQUENCE_TIME, self.becomingToonTask, name)

    def exitBecomingToon(self):
        name = self.taskName(str(self.block) + "_becomingToon-timer")
        taskMgr.remove(name)

    def enterBecomingToonFromCogdo(self):
        self.d_setState("becomingToonFromCogdo")
        name = self.taskName(str(self.block) + "_becomingToonFromCogdo-timer")
        taskMgr.doMethodLater(SuitBuildingGlobals.VICTORY_SEQUENCE_TIME, self.becomingToonTask, name)

    def exitBecomingToonFromCogdo(self):
        name = self.taskName(str(self.block) + "_becomingToonFromCogdo-timer")
        taskMgr.remove(name)

    def becomingToonTask(self, task):
        self.fsm.request("toon")
        self.suitPlannerExt.buildingMgr.save()
        return Task.done

    def enterToon(self):
        self.d_setState("toon")
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        if simbase.config.GetBool("want-new-toonhall", 1) and ZoneUtil.getCanonicalZoneId(interiorZoneId) == ToonHall:
            self.interior = DistributedToonHallInteriorAI.DistributedToonHallInteriorAI(
                self.block, self.air, interiorZoneId, self
            )
        else:
            self.interior = DistributedToonInteriorAI.DistributedToonInteriorAI(
                self.block, self.air, interiorZoneId, self
            )
        self.interior.generateWithRequired(interiorZoneId)
        door = self.createExteriorDoor()
        insideDoor = DistributedDoorAI.DistributedDoorAI(self.air, self.block, DoorTypes.INT_STANDARD)
        door.setOtherDoor(insideDoor)
        insideDoor.setOtherDoor(door)
        door.zoneId = exteriorZoneId
        insideDoor.zoneId = interiorZoneId
        door.generateWithRequired(exteriorZoneId)
        insideDoor.generateWithRequired(interiorZoneId)
        self.door = door
        self.insideDoor = insideDoor
        self.becameSuitTime = 0
        self.knockKnock = DistributedKnockKnockDoorAI.DistributedKnockKnockDoorAI(self.air, self.block)
        self.knockKnock.generateWithRequired(exteriorZoneId)
        self.air.writeServerEvent("building-toon", self.doId, "%s|%s" % (self.zoneId, self.block))

    def createExteriorDoor(self):
        result = DistributedDoorAI.DistributedDoorAI(self.air, self.block, DoorTypes.EXT_STANDARD)
        return result

    def exitToon(self):
        self.door.setDoorLock(FADoorCodes.BUILDING_TAKEOVER)

    def enterClearOutToonInterior(self):
        self.d_setState("clearOutToonInterior")
        if hasattr(self, "interior"):
            self.interior.setState("beingTakenOver")
        name = self.taskName(str(self.block) + "_clearOutToonInterior-timer")
        taskMgr.doMethodLater(SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME, self.clearOutToonInteriorTask, name)

    def exitClearOutToonInterior(self):
        name = self.taskName(str(self.block) + "_clearOutToonInterior-timer")
        taskMgr.remove(name)

    def clearOutToonInteriorTask(self, task):
        self.fsm.request("becomingSuit")
        return Task.done

    def enterBecomingSuit(self):
        self.sendUpdate("setSuitData", [ord(self.track), self.difficulty, self.numFloors])
        self.d_setState("becomingSuit")
        name = self.taskName(str(self.block) + "_becomingSuit-timer")
        taskMgr.doMethodLater(SuitBuildingGlobals.TO_SUIT_BLDG_TIME, self.becomingSuitTask, name)

    def exitBecomingSuit(self):
        name = self.taskName(str(self.block) + "_becomingSuit-timer")
        taskMgr.remove(name)
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock

    def becomingSuitTask(self, task):
        self.fsm.request("suit")
        self.suitPlannerExt.buildingMgr.save()
        return Task.done

    def enterSuit(self):
        self.sendUpdate("setSuitData", [ord(self.track), self.difficulty, self.numFloors])
        (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.planner = SuitPlannerInteriorAI.SuitPlannerInteriorAI(
            self.numFloors, self.difficulty, self.track, interiorZoneId
        )
        self.d_setState("suit")
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.elevator = DistributedElevatorExtAI.DistributedElevatorExtAI(self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)
        self.air.writeServerEvent(
            "building-cog", self.doId, "%s|%s|%s|%s" % (self.zoneId, self.block, self.track, self.numFloors)
        )

    def exitSuit(self):
        del self.planner
        if hasattr(self, "elevator"):
            self.elevator.requestDelete()
            del self.elevator

    def enterClearOutToonInteriorForCogdo(self):
        self.d_setState("clearOutToonInteriorForCogdo")
        if hasattr(self, "interior"):
            self.interior.setState("beingTakenOver")
        name = self.taskName(str(self.block) + "_clearOutToonInteriorForCogdo-timer")
        taskMgr.doMethodLater(SuitBuildingGlobals.CLEAR_OUT_TOON_BLDG_TIME, self.clearOutToonInteriorForCogdoTask, name)

    def exitClearOutToonInteriorForCogdo(self):
        name = self.taskName(str(self.block) + "_clearOutToonInteriorForCogdo-timer")
        taskMgr.remove(name)

    def clearOutToonInteriorForCogdoTask(self, task):
        self.fsm.request("becomingCogdo")
        return Task.done

    def enterBecomingCogdo(self):
        self.sendUpdate("setSuitData", [ord(self.track), self.difficulty, self.numFloors])
        self.d_setState("becomingCogdo")
        name = self.taskName(str(self.block) + "_becomingCogdo-timer")
        taskMgr.doMethodLater(SuitBuildingGlobals.TO_SUIT_BLDG_TIME, self.becomingCogdoTask, name)

    def exitBecomingCogdo(self):
        name = self.taskName(str(self.block) + "_becomingCogdo-timer")
        taskMgr.remove(name)
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior
            self.door.requestDelete()
            del self.door
            self.insideDoor.requestDelete()
            del self.insideDoor
            self.knockKnock.requestDelete()
            del self.knockKnock

    def becomingCogdoTask(self, task):
        self.fsm.request("cogdo")
        self.suitPlannerExt.buildingMgr.save()
        return Task.done

    def enterCogdo(self):
        self.sendUpdate("setSuitData", [ord(self.track), self.difficulty, self.numFloors])
        (zoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self._cogdoLayout = CogdoLayout(self.numFloors)
        self.planner = SuitPlannerCogdoInteriorAI(self._cogdoLayout, self.difficulty, self.track, interiorZoneId)
        self.d_setState("cogdo")
        (exteriorZoneId, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.elevator = DistributedCogdoElevatorExtAI(self.air, self)
        self.elevator.generateWithRequired(exteriorZoneId)
        self.air.writeServerEvent("building-cogdo", self.doId, "%s|%s|%s" % (self.zoneId, self.block, self.numFloors))

    def exitCogdo(self):
        del self.planner
        if hasattr(self, "elevator"):
            self.elevator.requestDelete()
            del self.elevator

    def setSuitPlannerExt(self, planner):
        self.suitPlannerExt = planner

    def _createSuitInterior(self):
        return DistributedSuitInteriorAI.DistributedSuitInteriorAI(self.air, self.elevator)

    def _createCogdoInterior(self):
        return DistributedCogdoInteriorAI(self.air, self.elevator)

    def createSuitInterior(self):
        self.interior = self._createSuitInterior()
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.interior.fsm.request("WaitForAllToonsInside")
        self.interior.generateWithRequired(interiorZoneId)

    def createCogdoInterior(self):
        self.interior = self._createCogdoInterior()
        (dummy, interiorZoneId) = self.getExteriorAndInteriorZoneId()
        self.interior.fsm.request("WaitForAllToonsInside")
        self.interior.generateWithRequired(interiorZoneId)

    def deleteSuitInterior(self):
        if hasattr(self, "interior"):
            self.interior.requestDelete()
            del self.interior
        if hasattr(self, "elevator"):
            self.elevator.d_setFloor(-1)
            self.elevator.open()

    def deleteCogdoInterior(self):
        self.deleteSuitInterior()