class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, serverId, districtName):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            serverId,
                                            dcSuffix='AI')

        self.districtName = districtName

        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)
        self.zoneId2owner = {}

        NPCToons.generateZone2NpcDict()

        self.hoods = []
        self.zoneDataStore = AIZoneDataStore()
        self.dnaStoreMap = {}
        self.dnaDataMap = {}

        self.currentHour = 0
        self.isRaining = False

        self.useAllMinigames = self.config.GetBool('want-all-minigames', False)
        self.doLiveUpdates = self.config.GetBool('want-live-updates', True)
        self.wantFishing = self.config.GetBool('want-fishing', True)
        self.wantHousing = self.config.GetBool('want-housing', True)
        self.wantPets = self.config.GetBool('want-pets', True)
        self.wantParties = self.config.GetBool('want-parties', True)
        self.wantCogbuildings = self.config.GetBool('want-cogbuildings', True)
        self.wantCogdominiums = self.config.GetBool('want-cogdominiums', True)
        self.doLiveUpdates = self.config.GetBool('want-live-updates', False)
        self.wantTrackClsends = self.config.GetBool('want-track-clsends',
                                                    False)
        self.baseXpMultiplier = self.config.GetFloat('base-xp-multiplier', 1.0)
        self.wantHalloween = self.config.GetBool('want-halloween', False)
        self.wantChristmas = self.config.GetBool('want-christmas', False)

        self.holidayManager = HolidayManagerAI(self)

        self.fishManager = FishManagerAI()
        self.questManager = QuestManagerAI(self)
        self.cogPageManager = CogPageManagerAI()
        self.factoryMgr = FactoryManagerAI(self)
        self.mintMgr = MintManagerAI(self)
        self.lawOfficeMgr = LawOfficeManagerAI(self)
        self.countryClubMgr = CountryClubManagerAI(self)
        self.promotionMgr = PromotionManagerAI(self)
        self.cogSuitMgr = CogSuitManagerAI(self)
        self.suitInvasionManager = SuitInvasionManagerAI(self)
        self.wantCogdominiums = self.config.GetBool('want-cogdominums', False)
        self.temperatureManager = TemperatureManagerAI(self)

        self.statusSender = ShardStatusSender(self)

        self.dnaStoreMap = {}

        self.buildingManagers = {}
        self.suitPlanners = {}

    def getTrackClsends(self):
        return False

    def handleConnected(self):
        ToontownInternalRepository.handleConnected(self)
        self.districtId = self.allocateChannel()
        self.notify.info('Creating new district (%d)...' % self.districtId)
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(
            self.districtId, self.getGameDoId(), 2)

        # Claim ownership of that district...
        self.notify.info('Claiming ownership of district (%d)...' %
                         self.districtId)
        dg = PyDatagram()
        dg.addServerHeader(self.districtId, self.ourChannel,
                           STATESERVER_OBJECT_SET_AI)
        dg.addChannel(self.ourChannel)
        self.send(dg)
        self.notify.info('Creating global objects...')
        self.createGlobals()
        self.notify.info('Creating zones (Playgrounds and Cog HQs)...')
        self.createZones()

        self.statusSender.start()
        self.notify.info('Making district available to enter...')
        self.distributedDistrict.b_setAvailable(1)
        self.notify.info('District is now ready. Have fun in Toontown!')

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)
        self.statusSender.sendStatus()

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)
        self.statusSender.sendStatus()

    def setHour(self, hour):
        self.districtStats.b_setHour(hour)
        self.statusSender.sendStatus()

    def allocateZone(self, owner=None):
        zoneId = self.zoneAllocator.allocate()
        if owner:
            self.zoneId2owner[zoneId] = owner
        return zoneId

    def deallocateZone(self, zone):
        if self.zoneId2owner.get(zone):
            del self.zoneId2owner[zone]
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def createGlobals(self):
        """
        Create "global" objects, e.g. TimeManager et al.
        """
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
                                                     self.getGameDoId(), 3)
        self.notify.info('Created district stats AI (%d).' %
                         self.districtStats.doId)
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)

        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)

        self.staffManager = StaffManagerAI(self)
        self.staffManager.generateWithRequired(2)

        self.banManager = BanManagerAI(self)
        self.banManager.generateWithRequired(2)

        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)

        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)

        if config.GetBool('want-parties', True):
            self.partyManager = DistributedPartyManagerAI(self)
            self.partyManager.generateWithRequired(2)

            # setup our view of the global party manager ud
            self.globalPartyMgr = self.generateGlobalObject(
                OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        self.estateManager = EstateManagerAI(self)
        self.estateManager.generateWithRequired(2)

        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(2)

        if config.GetBool('want-pets', True):
            self.petMgr = PetManagerAI(self)
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)

        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(2)

        self.codeRedemptionManager = TTCodeRedemptionMgrAI(self)
        self.codeRedemptionManager.generateWithRequired(2)

    def createZones(self):
        """
        Spawn safezone objects, streets, doors, NPCs, etc.
        """
        start = time.clock()

        def clearQueue():
            '''So the TCP window doesn't fill up and we get the axe'''
            while self.readerPollOnce():
                pass

        self.hoods.append(TTHoodAI.TTHoodAI(self))
        clearQueue()
        self.hoods.append(DDHoodAI.DDHoodAI(self))
        clearQueue()
        self.hoods.append(DGHoodAI.DGHoodAI(self))
        clearQueue()
        self.hoods.append(BRHoodAI.BRHoodAI(self))
        clearQueue()
        self.hoods.append(MMHoodAI.MMHoodAI(self))
        clearQueue()
        self.hoods.append(DLHoodAI.DLHoodAI(self))
        clearQueue()
        self.hoods.append(GSHoodAI.GSHoodAI(self))
        clearQueue()
        self.hoods.append(OZHoodAI.OZHoodAI(self))
        clearQueue()
        self.hoods.append(GZHoodAI.GZHoodAI(self))
        clearQueue()

        if config.GetBool('want-sbhq', True):
            self.hoods.append(SellbotHQAI.SellbotHQAI(self))
            clearQueue()

        if config.GetBool('want-cbhq', True):
            self.hoods.append(CashbotHQAI.CashbotHQAI(self))
            clearQueue()

        if config.GetBool('want-lbhq', True):
            self.hoods.append(LawbotHQAI.LawbotHQAI(self))
            clearQueue()

        if config.GetBool('want-bbhq', True):
            self.hoods.append(BossbotHQAI.BossbotHQAI(self))
            clearQueue()

        for sp in self.suitPlanners.values():
            sp.assignInitialSuitBuildings()

    def lookupDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]

        return 'phase_%s/dna/%s_%s.pdna' % (phase, hood, zoneId)

    def loadDNAFileAI(self, dnastore, filename):
        return loadDNAFileAI(dnastore, filename)
Beispiel #2
0
class ToontownAIRepository(ToontownInternalRepository):

    def __init__(self, baseChannel, stateServerChannel, districtName, startTime=6):
        ToontownInternalRepository.__init__(self, baseChannel, stateServerChannel, dcSuffix='AI')
        self.districtName = districtName
        self.notify.setInfo(True)
        self.hoods = []
        self.hoodId2Hood = {}
        self.cogHeadquarters = []
        self.dnaStoreMap = {}
        self.dnaDataMap = {}
        self.suitPlanners = {}
        self.buildingManagers = {}
        self.sillyMeterMgr = None
        self.factoryMgr = None
        self.mintMgr = None
        self.lawOfficeMgr = None
        self.countryClubMgr = None
        self.boardofficeMgr = None
        self.startTime = startTime
        import pymongo
        self.isRaining = False
        self.betaEventTTC = None
        self.betaEventBDHQ = None
        self.invLastPop = None
        self.invLastStatus = None

        import pymongo

        # Mongo stuff to store seperate database things
        self.dbConn = pymongo.MongoClient(config.GetString('mongodb-url', 'localhost'))
        self.dbGlobalCursor = self.dbConn.altis
        self.dbCursor = self.dbGlobalCursor['air-%d' % self.ourChannel]
        self.zoneAllocator = UniqueIdAllocator(ToontownGlobals.DynamicZonesBegin,
                                               ToontownGlobals.DynamicZonesEnd)
        self.zoneDataStore = AIZoneDataStore()

        self.wantFishing = self.config.GetBool('want-fishing', True)
        self.wantHousing = self.config.GetBool('want-housing', True)
        self.wantPets = self.config.GetBool('want-pets', True)
        self.wantParties = self.config.GetBool('want-parties', True)
        self.wantCogbuildings = self.config.GetBool('want-cogbuildings', True)
        self.wantCogdominiums = self.config.GetBool('want-cogdominiums', True)
        self.doLiveUpdates = self.config.GetBool('want-live-updates', False)
        self.wantTrackClsends = self.config.GetBool('want-track-clsends', False)
        self.wantAchievements = self.config.GetBool('want-achievements', True)
        self.wantCharityScreen = self.config.GetBool('want-charity-screen', False)
        self.baseXpMultiplier = self.config.GetFloat('base-xp-multiplier', 1.0)
        self.wantHalloween = self.config.GetBool('want-halloween', False)
        self.wantChristmas = self.config.GetBool('want-christmas', False)
        self.wantGardening = self.config.GetBool('want-gardening', False)
        self.cogSuitMessageSent = False
        self.weatherCycleDuration = self.config.GetInt('weather-cycle-duration', 100)

    def createManagers(self):
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)
        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)
        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(2)
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)
        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)
        self.questManager = QuestManagerAI(self)
        self.banManager = BanManagerAI.BanManagerAI(self)
        self.achievementsManager = AchievementsManagerAI(self)
        self.certManager = CertificateManagerAI(self)
        self.suitInvasionManager = SuitInvasionManagerAI(self)
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(2)
        self.cogSuitMgr = CogSuitManagerAI.CogSuitManagerAI(self)
        self.promotionMgr = PromotionManagerAI.PromotionManagerAI(self)
        self.experienceMgr = ExperienceRewardManagerAI.ExperienceRewardManagerAI(self)
        self.cogPageManager = CogPageManagerAI.CogPageManagerAI()
        self.sillyMeterMgr = DistributedSillyMeterMgrAI.DistributedSillyMeterMgrAI(self)
        self.sillyMeterMgr.generateWithRequired(2)
        self.hydrantZeroMgr = DistributedHydrantZeroMgrAI.DistributedHydrantZeroMgrAI(self)
        self.hydrantZeroMgr.generateWithRequired(2)
        self.mailboxZeroMgr = DistributedMailboxZeroMgrAI.DistributedMailboxZeroMgrAI(self)
        self.mailboxZeroMgr.generateWithRequired(2)
        self.trashcanZeroMgr = DistributedTrashcanZeroMgrAI.DistributedTrashcanZeroMgrAI(self)
        self.trashcanZeroMgr.generateWithRequired(2)
        self.dialogueManager = DialogueManagerAI(self)
        self.bingoHolidayMgr = BingoHolidayMgrAI(self, ToontownGlobals.FISH_BINGO_NIGHT)
        self.bingoWeekendMgr = BingoWeekendMgrAI(self, ToontownGlobals.SILLY_SATURDAY_BINGO)
        self.trolleyHolidayMgr = TrolleyHolidayMgrAI(self, ToontownGlobals.TROLLEY_HOLIDAY)
        self.trolleyWeekendMgr = TrolleyWeekendMgrAI(self, ToontownGlobals.TROLLEY_WEEKEND)
        self.holidayManager = HolidayManagerAI(self)


        if self.wantFishing:
            self.fishManager = FishManagerAI(self)

        if self.wantHousing:
            self.estateManager = EstateManagerAI(self)
            self.estateManager.generateWithRequired(2)
            self.catalogManager = CatalogManagerAI(self)
            self.catalogManager.generateWithRequired(2)
            self.deliveryManager = self.generateGlobalObject(OTP_DO_ID_TOONTOWN_DELIVERY_MANAGER, 'DistributedDeliveryManager')
            self.mailManager = self.generateGlobalObject(OTP_DO_ID_TOONTOWN_MAIL_MANAGER, 'DistributedMailManager')

        if self.wantPets:
            self.petMgr = PetManagerAI(self)

        self.publicPetMgr = DistributedPublicPetMgrAI.DistributedPublicPetMgrAI(self)
        self.publicPetMgr.generateWithRequired(2)

        if self.wantParties:
            self.partyManager = DistributedPartyManagerAI(self)
            self.partyManager.generateWithRequired(2)
            self.globalPartyMgr = self.generateGlobalObject(OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        self.codeRedemptionMgr = TTCodeRedemptionMgrAI(self)
        self.codeRedemptionMgr.generateWithRequired(2)
        self.chatAgent = simbase.air.generateGlobalObject(OTP_DO_ID_CHAT_MANAGER, 'ChatAgent')

    def createSafeZones(self):
        NPCToons.generateZone2NpcDict()
        if self.config.GetBool('want-toontown-central', True):
            hood = TTHoodAI.TTHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        if self.config.GetBool('want-donalds-dock', True):
            hood = DDHoodAI.DDHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        if self.config.GetBool('want-daisys-garden', True):
            hood = DGHoodAI.DGHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        if self.config.GetBool('want-minnies-melodyland', True):
            hood = MMHoodAI.MMHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        if self.config.GetBool('want-the-burrrgh', True):
            hood = BRHoodAI.BRHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        if self.config.GetBool('want-donalds-dreamland', True):
            hood = DLHoodAI.DLHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        if self.config.GetBool('want-goofy-speedway', True):
            hood = GSHoodAI.GSHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        if self.config.GetBool('want-outdoor-zone', True):
            hood = OZHoodAI.OZHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        if self.config.GetBool('want-golf-zone', True):
            hood = GZHoodAI.GZHoodAI(self)
            self.hoods.append(hood)
            self.hoodId2Hood[hood.zoneId] = hood
        hood = TTOHoodAI.TTOHoodAI(self)
        self.hoods.append(hood)
        self.hoodId2Hood[hood.zoneId] = hood

    def createCogHeadquarters(self):
        NPCToons.generateZone2NpcDict()
        if self.config.GetBool('want-sellbot-headquarters', True):
            self.factoryMgr = FactoryManagerAI.FactoryManagerAI(self)
            self.cogHeadquarters.append(SellbotHQAI.SellbotHQAI(self))
        if self.config.GetBool('want-cashbot-headquarters', True):
            self.mintMgr = MintManagerAI.MintManagerAI(self)
            self.cogHeadquarters.append(CashbotHQAI.CashbotHQAI(self))
        if self.config.GetBool('want-lawbot-headquarters', True):
            self.lawOfficeMgr = LawOfficeManagerAI.LawOfficeManagerAI(self)
            self.cogHeadquarters.append(LawbotHQAI.LawbotHQAI(self))
        if self.config.GetBool('want-bossbot-headquarters', True):
            self.countryClubMgr = CountryClubManagerAI.CountryClubManagerAI(self)
            self.cogHeadquarters.append(BossbotHQAI.BossbotHQAI(self))
        if self.config.GetBool('want-bdhq', True):
            self.boardofficeMgr = BoardOfficeManagerAI.BoardOfficeManagerAI(self)
            self.cogHeadquarters.append(BoardbotHQAI.BoardbotHQAI(self))

    def handleConnected(self):
        self.registerForChannel(MESSENGER_CHANNEL_AI)

        self.districtId = self.allocateChannel()
        self.notify.info('Creating ToontownDistrictAI(%d)...' % self.districtId)
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(
            self.districtId, self.getGameDoId(), 2)

        self.notify.info('Claiming ownership of channel ID: %d...' % self.districtId)
        self.setAI(self.districtId, self.ourChannel)

        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
            self.getGameDoId(), 3)

        self.notify.info('Created ToontownDistrictStats(%d)' % self.districtStats.doId)

        self.notify.info('Creating managers...')
        self.createManagers()
        if self.config.GetBool('want-safe-zones', True):
            self.notify.info('Creating safe zones...')
            self.createSafeZones()

        if self.config.GetBool('want-cog-headquarters', True):
            self.notify.info('Creating Cog headquarters...')
            self.createCogHeadquarters()

        self.notify.info('Making district available...')
        self.distributedDistrict.b_setAvailable(1)
        self.notify.info('Done.')

        self.notify.info("Starting Invasion Tracker...")
        taskMgr.doMethodLater(2, self.updateInvasionTrackerTask, 'updateInvasionTracker-%d' % self.ourChannel)
        self.notify.info("Invasion Tracker Started!")
        self.sendNetEvent('registerShard', [self.districtId, True], channels=[MESSENGER_CHANNEL_UD])

        atexit.register(self.shardDeath)

    def shardDeath(self):
        self.sendNetEvent('registerShard', [self.districtId, False], channels=[MESSENGER_CHANNEL_UD])

    def lookupDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phaseNum = ToontownGlobals.phaseMap[hoodId]
        else:
            phaseNum = ToontownGlobals.streetPhaseMap[hoodId]

        return 'phase_%s/dna/%s_%s.pdna' % (phaseNum, hood, zoneId)

    def loadDNAFileAI(self, dnastore, filename):
        return loadDNAFileAI(dnastore, filename)

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() - 1)

    def setHour(self, hour):
        pass # Todo: Hour on district page

    def allocateZone(self):
        return self.zoneAllocator.allocate()

    def deallocateZone(self, zone):
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getTrackClsends(self):
        return self.wantTrackClsends

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % (avId)

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

    def updateInvasionTrackerTask(self, task):
        task.delayTime = 10 # Set it to 10 after doing it the first time
        statusToType = {
        0: 'None',
        1: 'Bossbot',
        2: 'Lawbot',
        3: 'Cashbot',
        4: 'Sellbot',
        5: 'Boardbot'}
        pop = self.districtStats.getAvatarCount()
        invstatus = statusToType.get(self.districtStats.getInvasionStatus(), 'None')
        total = self.districtStats.getInvasionTotal()
        defeated = total - self.districtStats.getInvasionRemaining()
        tupleStatus = (self.districtStats.getInvasionStatus(), self.districtStats.getInvasionType())
        invstatus = self.statusToType(tupleStatus)
        timeleft = self.districtStats.getInvasionTimeRemaining()

        self.invLastPop = pop
        self.invLastStatus = invstatus

        return task.again

    def statusToType(self, tupleInvasionStatus):
        try:
            statusToSuit = {
                0: 'None',
                1: 'Bossbot',
                2: 'Lawbot',
                3: 'Cashbot',
                4: 'Sellbot',
                5: 'Boardbot'
            }
            suit = statusToSuit.get(tupleInvasionStatus[0], 'None')
            if suit == 'None':
                return suit

            Type = SuitInvasionGlobals.comboToType.get(str(tupleInvasionStatus[0]) + str(tupleInvasionStatus[1]), 'None')
            Type = Type.replace(' ', '%20')
            if Type == 'None':
                return Type
            return Type + '|' + suit
        except:
            return 'None'
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, stateServerChannel, districtName):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            stateServerChannel,
                                            dcSuffix='AI')

        self.districtName = districtName

        self.notify.setInfo(True)  # Our AI repository should always log info.
        self.hoods = []
        self.cogHeadquarters = []
        self.dnaStoreMap = {}
        self.dnaDataMap = {}
        self.suitPlanners = {}
        self.buildingManagers = {}
        self.factoryMgr = None
        self.mintMgr = None
        self.lawOfficeMgr = None
        self.countryClubMgr = None

        # For when in game events occur
        self.globalOccurrenceMgr = self.generateGlobalObject(
            OTP_DO_ID_GLOBAL_OCCURRENCE_MANAGER,
            'GlobalOccurrenceManager')  # OCCURRENCE-MANAGER-AI

        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)
        self.zoneDataStore = AIZoneDataStore()

        self.wantFishing = self.config.GetBool('want-fishing', True)
        self.wantHousing = self.config.GetBool('want-housing', True)
        self.wantPets = self.config.GetBool('want-pets', True)
        self.wantParties = self.config.GetBool('want-parties', True)
        self.wantCogbuildings = self.config.GetBool('want-cogbuildings', True)
        self.wantCogdominiums = self.config.GetBool('want-cogdominiums', True)
        self.doLiveUpdates = self.config.GetBool('want-live-updates', False)
        self.wantTrackClsends = self.config.GetBool('want-track-clsends',
                                                    False)
        self.baseXpMultiplier = self.config.GetFloat('base-xp-multiplier', 1.0)
        self.wantHalloween = self.config.GetBool('want-halloween', False)
        self.wantChristmas = self.config.GetBool('want-christmas', False)
        self.wantFireworks = self.config.GetBool('want-fireworks', False)

        self.cogSuitMessageSent = False

    def createManagers(self):
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)
        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)

        self.holidayManager = HolidayManagerAI(self)

        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(2)
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)
        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)
        self.questManager = QuestManagerAI(self)
        self.banManager = BanManagerAI.BanManagerAI(self)
        self.suitInvasionManager = SuitInvasionManagerAI(self)
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(2)
        self.cogSuitMgr = CogSuitManagerAI.CogSuitManagerAI(self)
        self.promotionMgr = PromotionManagerAI.PromotionManagerAI(self)
        self.cogPageManager = CogPageManagerAI.CogPageManagerAI()

        if self.wantFishing:
            self.fishManager = FishManagerAI(self)
        if self.wantHousing:
            self.estateManager = EstateManagerAI(self)
            self.estateManager.generateWithRequired(2)
            self.catalogManager = CatalogManagerAI(self)
            self.catalogManager.generateWithRequired(2)
            self.deliveryManager = self.generateGlobalObject(
                OTP_DO_ID_TOONTOWN_DELIVERY_MANAGER,
                'DistributedDeliveryManager')
        if self.wantPets:
            self.petMgr = PetManagerAI(self)

        if self.wantParties:
            self.partyManager = DistributedPartyManagerAI(self)
            self.partyManager.generateWithRequired(2)
            # Setup view of global ub party manager
            self.globalPartyMgr = self.generateGlobalObject(
                OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        self.wantLeaderBoardMgr = True
        if self.wantLeaderBoardMgr:
            self.leaderBoardMgr = DistributedLeaderBoardManagerAI(self)

        # Need work
        self.codeRedemptionManager = TTCodeRedemptionMgrAI(self)
        self.codeRedemptionManager.generateWithRequired(2)

    def createSafeZones(self):
        NPCToons.generateZone2NpcDict()
        if self.config.GetBool('want-toontown-central', True):
            self.hoods.append(TTHoodAI.TTHoodAI(self))
        if self.config.GetBool('want-donalds-dock', True):
            self.hoods.append(DDHoodAI.DDHoodAI(self))
        if self.config.GetBool('want-daisys-garden', True):
            self.hoods.append(DGHoodAI.DGHoodAI(self))
        if self.config.GetBool('want-minnies-melodyland', True):
            self.hoods.append(MMHoodAI.MMHoodAI(self))
        if self.config.GetBool('want-the-burrrgh', True):
            self.hoods.append(BRHoodAI.BRHoodAI(self))
        if self.config.GetBool('want-donalds-dreamland', True):
            self.hoods.append(DLHoodAI.DLHoodAI(self))
        if self.config.GetBool('want-goofy-speedway', True):
            self.hoods.append(GSHoodAI.GSHoodAI(self))
        if self.config.GetBool('want-outdoor-zone', True):
            self.hoods.append(OZHoodAI.OZHoodAI(self))
        if self.config.GetBool('want-golf-zone', True):
            self.hoods.append(GZHoodAI.GZHoodAI(self))

    def createCogHeadquarters(self):
        if self.config.GetBool('want-sellbot-headquarters', True):
            self.factoryMgr = FactoryManagerAI.FactoryManagerAI(self)
            self.cogHeadquarters.append(SellbotHQAI.SellbotHQAI(self))
        if self.config.GetBool('want-cashbot-headquarters', True):
            self.mintMgr = MintManagerAI.MintManagerAI(self)
            self.cogHeadquarters.append(CashbotHQAI.CashbotHQAI(self))
        if self.config.GetBool('want-lawbot-headquarters', True):
            self.lawOfficeMgr = LawOfficeManagerAI.LawOfficeManagerAI(self)
            self.cogHeadquarters.append(LawbotHQAI.LawbotHQAI(self))
        if self.config.GetBool('want-bossbot-headquarters', True):
            self.countryClubMgr = CountryClubManagerAI.CountryClubManagerAI(
                self)
            self.cogHeadquarters.append(BossbotHQAI.BossbotHQAI(self))

    def handleConnected(self):
        self.districtId = self.allocateChannel()
        self.notify.info('Creating ToontownDistrictAI(%d)...' %
                         self.districtId)
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(
            self.districtId, self.getGameDoId(), 2)
        self.notify.info('Claiming ownership of channel ID: %d...' %
                         self.districtId)
        self.claimOwnership(self.districtId)

        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
                                                     self.getGameDoId(), 3)
        self.notify.info('Created ToontownDistrictStats(%d)' %
                         self.districtStats.doId)

        self.notify.info('Creating managers...')
        self.createManagers()
        if self.config.GetBool('want-safe-zones', True):
            self.notify.info('Creating safe zones...')
            self.createSafeZones()
        if self.config.GetBool('want-cog-headquarters', True):
            self.notify.info('Creating Cog headquarters...')
            self.createCogHeadquarters()

        self.notify.info('Starting Holiday Manager...')
        self.holidayManager.start()

        self.notify.info('Making district available...')
        self.distributedDistrict.b_setAvailable(1)
        self.notify.info('Done.')

    def claimOwnership(self, channelId):
        datagram = PyDatagram()
        datagram.addServerHeader(channelId, self.ourChannel,
                                 STATESERVER_OBJECT_SET_AI)
        datagram.addChannel(self.ourChannel)
        self.send(datagram)

    def lookupDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phaseNum = ToontownGlobals.phaseMap[hoodId]
        else:
            phaseNum = ToontownGlobals.streetPhaseMap[hoodId]
        return 'phase_%s/dna/%s_%s.pdna' % (phaseNum, hood, zoneId)

    def loadDNAFileAI(self, dnastore, filename):
        return loadDNAFileAI(dnastore, filename)

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)

    def allocateZone(self):
        return self.zoneAllocator.allocate()

    def deallocateZone(self, zone):
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getTrackClsends(self):
        return self.wantTrackClsends

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def trueUniqueName(self, name):
        return self.uniqueName(name)
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, serverId, districtName):
        ToontownInternalRepository.__init__(self, baseChannel, serverId, dcSuffix='AI')

        self.districtName = districtName

        self.zoneAllocator = UniqueIdAllocator(ToontownGlobals.DynamicZonesBegin,
                                               ToontownGlobals.DynamicZonesEnd)

        NPCToons.generateZone2NpcDict()

        self.hoods = []
        self.zoneDataStore = AIZoneDataStore()

        self.useAllMinigames = self.config.GetBool('want-all-minigames', False)
        self.doLiveUpdates = False

        self.holidayManager = HolidayManagerAI()
        
        self.fishManager = FishManagerAI()
        
        self.mintMgr = MintManagerAI.MintManagerAI(self)
        self.factoryMgr = FactoryManagerAI.FactoryManagerAI(self)

    def getTrackClsends(self):
        return False
        

    def handleConnected(self):
        self.districtId = self.allocateChannel()
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(simbase.air.districtId,
                                                           self.getGameDoId(), 2)

        # Claim ownership of that district...
        dg = PyDatagram()
        dg.addServerHeader(simbase.air.districtId, simbase.air.ourChannel, STATESERVER_OBJECT_SET_AI)
        dg.addChannel(simbase.air.ourChannel)
        simbase.air.send(dg)

        self.createGlobals()
        self.createZones()

        self.distributedDistrict.b_setAvailable(1)

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() - 1)

    def allocateZone(self):
        return self.zoneAllocator.allocate()

    def deallocateZone(self, zone):
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def createGlobals(self):
        """
        Create "global" objects, e.g. TimeManager et al.
        """
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
                                                     self.getGameDoId(), 3)

        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)

        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)

        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)

        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(2)

        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)

        self.partyManager = DistributedPartyManagerAI(self)
        self.partyManager.generateWithRequired(2)

        # setup our view of the global party manager ud
        self.globalPartyMgr = self.generateGlobalObject(OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        self.estateManager = EstateManagerAI(self)
        self.estateManager.generateWithRequired(2)

    def startFireworks(self, task):
        allFwTypes = [PartyGlobals.FireworkShows.Summer, ToontownGlobals.JULY4_FIREWORKS]
        fwType = allFwTypes[random.randint(0, len(allFwTypes)-1)]
        numShows = len(FireworkShows.shows.get(fwType, []))
        showIndex = random.randint(0, numShows-1)
        for hood in self.hoods:
            if hood.safezone == ToontownGlobals.GolfZone:
                continue
            fwShow = DistributedFireworkShowAI(self)
            fwShow.generateWithRequired(hood.safezone)
            fwShow.b_startShow(fwType, showIndex, globalClockDelta.getRealNetworkTime())
        task.delayTime = 3600
        return task.again

    def createZones(self):
        """
        Spawn safezone objects, streets, doors, NPCs, etc.
        """
        self.hoods.append(TTHoodAI.TTHoodAI(self))
        self.hoods.append(DDHoodAI.DDHoodAI(self))
        #self.hoods.append(DGHoodAI.DGHoodAI(self))
        self.hoods.append(BRHoodAI.BRHoodAI(self))
        self.hoods.append(MMHoodAI.MMHoodAI(self))
        self.hoods.append(DLHoodAI.DLHoodAI(self))
        self.hoods.append(GSHoodAI.GSHoodAI(self))
        self.hoods.append(OZHoodAI.OZHoodAI(self))
        self.hoods.append(GZHoodAI.GZHoodAI(self))
        self.hoods.append(SellbotHQAI.SellbotHQAI(self))
        self.hoods.append(CashbotHQAI.CashbotHQAI(self))
        self.hoods.append(LawbotHQAI.LawbotHQAI(self))
        self.hoods.append(BossbotHQAI.BossbotHQAI(self))

        # Calculate time until next hour.
        thetime = time.time() % 3600
        if thetime < 60: # If the AI was started less than a minute after the previous full hour.
            taskMgr.doMethodLater(1, self.startFireworks, 'fireworks-taskmgr-hourly')
        else:
            taskMgr.doMethodLater(3600-thetime, self.startFireworks, 'fireworks-taskmgr-hourly')

    def genDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]

        return 'phase_%s/dna/%s_%s.dna' % (phase, hood, zoneId)

    def loadDNAFileAI(self, dnastore, filename):
        return loadDNAFileAI(dnastore, filename)
Beispiel #5
0
class ToontownAIRepository(ToontownInternalRepository):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'ToontownAIRepository')

    def __init__(self, baseChannel, serverId, districtName):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            serverId,
                                            dcSuffix='AI')
        self.districtName = districtName
        self.doLiveUpdates = self.config.GetBool('want-live-updates', True)
        self.wantCogdominiums = self.config.GetBool('want-cogdominiums', True)
        self.wantEmblems = self.config.GetBool('want-emblems', True)
        self.useAllMinigames = self.config.GetBool('want-all-minigames', True)
        self.districtId = None
        self.district = None
        self.districtStats = None
        self.timeManager = None
        self.newsManager = None
        self.holidayManager = None
        self.welcomeValleyManager = None
        self.catalogManager = None
        self.zoneDataStore = None
        self.inGameNewsMgr = None
        self.trophyMgr = None
        self.petMgr = None
        self.dnaStoreMap = {}
        self.dnaDataMap = {}
        self.zoneTable = {}
        self.hoods = []
        self.buildingManagers = {}
        self.suitPlanners = {}
        self.suitInvasionManager = None
        self.zoneAllocator = None
        self.zoneId2owner = {}
        self.questManager = None
        self.cogPageManager = None
        self.fishManager = None
        self.factoryMgr = None
        self.mintMgr = None
        self.lawMgr = None
        self.countryClubMgr = None
        self.promotionMgr = None
        self.cogSuitMgr = None
        self.partyManager = None
        self.safeZoneManager = None
        self.raceMgr = None
        self.polarPlaceEffectMgr = None
        self.resistanceEmoteMgr = None
        self.tutorialManager = None
        self.friendManager = None
        self.toontownTimeManager = None
        self.estateMgr = None
        self.magicWordManager = None
        self.deliveryManager = None
        self.defaultAccessLevel = OTPGlobals.accessLevelValues.get(
            'TTOFF_DEVELOPER')

    def getTrackClsends(self):
        return False

    def handleConnected(self):
        ToontownInternalRepository.handleConnected(self)

        # Generate our district...
        self.districtId = self.allocateChannel()
        self.notify.info('Creating district (%d)...' % self.districtId)
        self.district = ToontownDistrictAI(self)
        self.district.setName(self.districtName)
        self.district.generateWithRequiredAndId(self.districtId,
                                                self.getGameDoId(),
                                                OTP_ZONE_ID_MANAGEMENT)

        # Claim ownership of that district...
        self.notify.info('Claiming ownership of district (%d)...' %
                         self.districtId)
        datagram = PyDatagram()
        datagram.addServerHeader(self.districtId, self.ourChannel,
                                 STATESERVER_OBJECT_SET_AI)
        datagram.addChannel(self.ourChannel)
        self.send(datagram)

        # Create our local objects.
        self.notify.info('Creating local objects...')
        self.createLocals()

        # Create our global objects.
        self.notify.info('Creating global objects...')
        self.createGlobals()

        # Create our zones.
        self.notify.info('Creating zones (Playgrounds and Cog HQs)...')
        self.createZones()

        # Make our district available, and we're done.
        self.notify.info('Making district available...')
        self.district.b_setAvailable(1)
        self.notify.info('District is now ready. Have fun in Toontown Online!')

    def createLocals(self):
        """
        Creates "local" objects.
        """

        # Create our holiday manager...
        self.holidayManager = HolidayManagerAI(self)

        # Create our zone data store...
        self.zoneDataStore = AIZoneDataStore()

        # Create our pet manager...
        self.petMgr = PetManagerAI(self)

        # Create our suit invasion manager...
        self.suitInvasionManager = SuitInvasionManagerAI(self)

        # Create our zone allocator...
        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)

        # Create our quest manager...
        self.questManager = QuestManagerAI(self)

        # Create our Cog page manager...
        self.cogPageManager = CogPageManagerAI(self)

        # Create our fish manager...
        self.fishManager = FishManagerAI(self)

        # Create our factory manager...
        self.factoryMgr = FactoryManagerAI(self)

        # Create our mint manager...
        self.mintMgr = MintManagerAI(self)

        # Create our law office manager...
        self.lawMgr = LawOfficeManagerAI(self)

        # Create our country club manager...
        self.countryClubMgr = CountryClubManagerAI(self)

        # Create our promotion manager...
        self.promotionMgr = PromotionManagerAI(self)

        # Create our Cog suit manager...
        self.cogSuitMgr = CogSuitManagerAI(self)

        # Create our race manager...
        self.raceMgr = RaceManagerAI(self)

        # Create our Toontown time manager...
        self.toontownTimeManager = ToontownTimeManager(
            serverTimeUponLogin=int(time.time()),
            globalClockRealTimeUponLogin=globalClock.getRealTime())

    def createGlobals(self):
        """
        Creates "global" objects.
        """

        # Generate our district stats...
        districtStatsId = self.allocateChannel()
        self.notify.info('Creating district stats AI (%d)...' %
                         districtStatsId)
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(districtStatsId,
                                                     self.getGameDoId(),
                                                     OTP_ZONE_ID_DISTRICTS)

        # Generate our time manager...
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our news manager...
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our Welcome Valley manager...
        self.welcomeValleyManager = WelcomeValleyManagerAI(self)
        self.welcomeValleyManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our catalog manager...
        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our in-game news manager...
        self.inGameNewsMgr = DistributedInGameNewsMgrAI(self)
        self.inGameNewsMgr.setLatestIssueStr('2013-08-22 23:49:46')
        self.inGameNewsMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our trophy manager...
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our party manager...
        self.partyManager = DistributedPartyManagerAI(self)
        self.partyManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our safezone manager...
        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our Polar Place effect manager...
        self.polarPlaceEffectMgr = DistributedPolarPlaceEffectMgrAI(self)
        self.polarPlaceEffectMgr.generateWithRequired(3821)

        # Generate our resistance emote manager...
        self.resistanceEmoteMgr = DistributedResistanceEmoteMgrAI(self)
        self.resistanceEmoteMgr.generateWithRequired(9720)

        # Generate our tutorial manager...
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our friend manager...
        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our estate manager...
        self.estateMgr = EstateManagerAI(self)
        self.estateMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our delivery manager...
        self.deliveryManager = self.generateGlobalObject(
            OTP_DO_ID_TOONTOWN_DELIVERY_MANAGER, 'DistributedDeliveryManager')

    def createHood(self, hoodCtr, zoneId):
        # Bossbot HQ doesn't use DNA, so we skip over that.
        if zoneId != ToontownGlobals.BossbotHQ:
            self.dnaStoreMap[zoneId] = DNAStorage()
            self.dnaDataMap[zoneId] = loadDNAFileAI(
                self.dnaStoreMap[zoneId], self.genDNAFileName(zoneId))
            if zoneId in ToontownGlobals.HoodHierarchy:
                for streetId in ToontownGlobals.HoodHierarchy[zoneId]:
                    self.dnaStoreMap[streetId] = DNAStorage()
                    self.dnaDataMap[streetId] = loadDNAFileAI(
                        self.dnaStoreMap[streetId],
                        self.genDNAFileName(streetId))

        hood = hoodCtr(self, zoneId)
        hood.startup()
        self.hoods.append(hood)

    def createZones(self):
        # First, generate our zone2NpcDict...
        NPCToons.generateZone2NpcDict()

        # Toontown Central
        self.zoneTable[ToontownGlobals.ToontownCentral] = (
            (ToontownGlobals.ToontownCentral, 1,
             0), (ToontownGlobals.SillyStreet, 1,
                  1), (ToontownGlobals.LoopyLane, 1,
                       1), (ToontownGlobals.PunchlinePlace, 1, 1))
        self.createHood(TTHoodDataAI, ToontownGlobals.ToontownCentral)

        # Donald's Dock
        self.zoneTable[ToontownGlobals.DonaldsDock] = (
            (ToontownGlobals.DonaldsDock, 1,
             0), (ToontownGlobals.BarnacleBoulevard, 1,
                  1), (ToontownGlobals.SeaweedStreet, 1,
                       1), (ToontownGlobals.LighthouseLane, 1, 1))
        self.createHood(DDHoodDataAI, ToontownGlobals.DonaldsDock)

        # Daisy Gardens
        self.zoneTable[ToontownGlobals.DaisyGardens] = (
            (ToontownGlobals.DaisyGardens, 1,
             0), (ToontownGlobals.ElmStreet, 1,
                  1), (ToontownGlobals.MapleStreet, 1,
                       1), (ToontownGlobals.OakStreet, 1, 1))
        self.createHood(DGHoodDataAI, ToontownGlobals.DaisyGardens)

        # Minnie's Melodyland
        self.zoneTable[ToontownGlobals.MinniesMelodyland] = (
            (ToontownGlobals.MinniesMelodyland, 1,
             0), (ToontownGlobals.AltoAvenue, 1,
                  1), (ToontownGlobals.BaritoneBoulevard, 1,
                       1), (ToontownGlobals.TenorTerrace, 1, 1))
        self.createHood(MMHoodDataAI, ToontownGlobals.MinniesMelodyland)

        # The Brrrgh
        self.zoneTable[ToontownGlobals.TheBrrrgh] = (
            (ToontownGlobals.TheBrrrgh, 1,
             0), (ToontownGlobals.WalrusWay, 1,
                  1), (ToontownGlobals.SleetStreet, 1,
                       1), (ToontownGlobals.PolarPlace, 1, 1))
        self.createHood(BRHoodDataAI, ToontownGlobals.TheBrrrgh)

        # Donald's Dreamland
        self.zoneTable[ToontownGlobals.DonaldsDreamland] = (
            (ToontownGlobals.DonaldsDreamland, 1,
             0), (ToontownGlobals.LullabyLane, 1,
                  1), (ToontownGlobals.PajamaPlace, 1, 1))
        self.createHood(DLHoodDataAI, ToontownGlobals.DonaldsDreamland)

        # Sellbot HQ
        self.zoneTable[ToontownGlobals.SellbotHQ] = (
            (ToontownGlobals.SellbotHQ, 0,
             1), (ToontownGlobals.SellbotFactoryExt, 0, 1))
        self.createHood(CSHoodDataAI, ToontownGlobals.SellbotHQ)

        # Cashbot HQ
        self.zoneTable[ToontownGlobals.CashbotHQ] = ((
            ToontownGlobals.CashbotHQ, 0, 1), )
        self.createHood(CashbotHQDataAI, ToontownGlobals.CashbotHQ)

        # Lawbot HQ
        self.zoneTable[ToontownGlobals.LawbotHQ] = ((ToontownGlobals.LawbotHQ,
                                                     0, 1), )
        self.createHood(LawbotHQDataAI, ToontownGlobals.LawbotHQ)

        # Bossbot HQ
        self.zoneTable[ToontownGlobals.BossbotHQ] = ((
            ToontownGlobals.BossbotHQ, 0, 0), )
        self.createHood(BossbotHQDataAI, ToontownGlobals.BossbotHQ)

        # Goofy Speedway
        self.zoneTable[ToontownGlobals.GoofySpeedway] = ((
            ToontownGlobals.GoofySpeedway, 1, 0), )
        self.createHood(GSHoodDataAI, ToontownGlobals.GoofySpeedway)

        # Chip 'n Dale's Acorn Acres
        self.zoneTable[ToontownGlobals.OutdoorZone] = ((
            ToontownGlobals.OutdoorZone, 1, 0), )
        self.createHood(OZHoodDataAI, ToontownGlobals.OutdoorZone)

        # Chip 'n Dale's MiniGolf
        self.zoneTable[ToontownGlobals.GolfZone] = ((ToontownGlobals.GolfZone,
                                                     1, 0), )
        self.createHood(GZHoodDataAI, ToontownGlobals.GolfZone)

        # Welcome Valley hoods (Toontown Central & Goofy Speedway)
        self.notify.info('Creating ' + TTLocalizer.WelcomeValley[2] + '...')
        self.welcomeValleyManager.createWelcomeValleyHoods()

        # Assign the initial suit buildings.
        self.notify.info(
            'Assigning initial Cog buildings and Field Offices...')
        for suitPlanner in self.suitPlanners.values():
            suitPlanner.assignInitialSuitBuildings()

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def getZoneDataStore(self):
        return self.zoneDataStore

    def genDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]

        if 'outdoor_zone' in hood or 'golf_zone' in hood:
            phase = '6'

        return 'phase_%s/dna/%s_%s.dna' % (phase, hood, zoneId)

    def findFishingPonds(self, dnaData, zoneId, area):
        fishingPonds = []
        fishingPondGroups = []
        if isinstance(dnaData, DNAGroup) and ('fishing_pond'
                                              in dnaData.getName()):
            fishingPondGroups.append(dnaData)
            pond = self.fishManager.generatePond(area, zoneId)
            fishingPonds.append(pond)
        elif isinstance(dnaData, DNAVisGroup):
            zoneId = ZoneUtil.getTrueZoneId(
                int(dnaData.getName().split(':')[0]), zoneId)

        for i in xrange(dnaData.getNumChildren()):
            foundFishingPonds, foundFishingPondGroups = self.findFishingPonds(
                dnaData.at(i), zoneId, area)
            fishingPonds.extend(foundFishingPonds)
            fishingPondGroups.extend(foundFishingPondGroups)

        return fishingPonds, fishingPondGroups

    def findFishingSpots(self, dnaData, fishingPond):
        fishingSpots = []
        if isinstance(dnaData, DNAGroup) and ('fishing_spot'
                                              in dnaData.getName()):
            spot = self.fishManager.generateSpots(dnaData, fishingPond)
            fishingSpots.append(spot)

        for i in xrange(dnaData.getNumChildren()):
            foundFishingSpots = self.findFishingSpots(dnaData.at(i),
                                                      fishingPond)
            fishingSpots.extend(foundFishingSpots)

        return fishingSpots

    def findPartyHats(self, dnaData, zoneId):
        return []

    def loadDNAFileAI(self, dnaStore, dnaFileName):
        return loadDNAFileAI(dnaStore, dnaFileName)

    def allocateZone(self, owner=None):
        zoneId = self.zoneAllocator.allocate()
        if owner:
            self.zoneId2owner[zoneId] = owner

        return zoneId

    def deallocateZone(self, zone):
        if self.zoneId2owner.get(zone):
            del self.zoneId2owner[zone]

        self.zoneAllocator.free(zone)

    def trueUniqueName(self, idString):
        return self.uniqueName(idString)

    def findRacingPads(self,
                       dnaData,
                       zoneId,
                       area,
                       type='racing_pad',
                       overrideDNAZone=False):
        racingPads, racingPadGroups = [], []
        if type in dnaData.getName():
            if type == 'racing_pad':
                nameSplit = dnaData.getName().split('_')
                racePad = DistributedRacePadAI(self)
                racePad.setArea(area)
                racePad.index = int(nameSplit[2])
                racePad.genre = nameSplit[3]
                trackInfo = RaceGlobals.getNextRaceInfo(
                    -1, racePad.genre, racePad.index)
                racePad.setTrackInfo([trackInfo[0], trackInfo[1]])
                racePad.laps = trackInfo[2]
                racePad.generateWithRequired(zoneId)
                racingPads.append(racePad)
                racingPadGroups.append(dnaData)
            elif type == 'viewing_pad':
                viewPad = DistributedViewPadAI(self)
                viewPad.setArea(area)
                viewPad.generateWithRequired(zoneId)
                racingPads.append(viewPad)
                racingPadGroups.append(dnaData)

        for i in xrange(dnaData.getNumChildren()):
            foundRacingPads, foundRacingPadGroups = self.findRacingPads(
                dnaData.at(i), zoneId, area, type, overrideDNAZone)
            racingPads.extend(foundRacingPads)
            racingPadGroups.extend(foundRacingPadGroups)

        return racingPads, racingPadGroups

    def findStartingBlocks(self, dnaData, pad):
        startingBlocks = []
        for i in xrange(dnaData.getNumChildren()):
            groupName = dnaData.getName()
            blockName = dnaData.at(i).getName()
            if 'starting_block' in blockName:
                cls = DistributedStartingBlockAI if 'racing_pad' in groupName else DistributedViewingBlockAI
                x, y, z = dnaData.at(i).getPos()
                h, p, r = dnaData.at(i).getHpr()
                padLocationId = int(dnaData.at(i).getName()[-1])
                startingBlock = cls(self, pad, x, y, z, h, p, r, padLocationId)
                startingBlock.generateWithRequired(pad.zoneId)
                startingBlocks.append(startingBlock)

        return startingBlocks

    def getAvatarDisconnectReason(self, avId):
        return self.timeManager.avId2disconnectcode.get(
            avId, ToontownGlobals.DisconnectUnknown)

    def lookupDNAFileName(self, dnaFile):
        searchPath = DSearchPath()
        searchPath.appendDirectory(Filename('/phase_3.5/dna'))
        searchPath.appendDirectory(Filename('/phase_4/dna'))
        searchPath.appendDirectory(Filename('/phase_5/dna'))
        searchPath.appendDirectory(Filename('/phase_5.5/dna'))
        searchPath.appendDirectory(Filename('/phase_6/dna'))
        searchPath.appendDirectory(Filename('/phase_8/dna'))
        searchPath.appendDirectory(Filename('/phase_9/dna'))
        searchPath.appendDirectory(Filename('/phase_10/dna'))
        searchPath.appendDirectory(Filename('/phase_11/dna'))
        searchPath.appendDirectory(Filename('/phase_12/dna'))
        searchPath.appendDirectory(Filename('/phase_13/dna'))
        filename = Filename(dnaFile)
        found = vfs.resolveFilename(filename, searchPath)
        if not found:
            self.notify.warning('lookupDNAFileName - %s not found on:' %
                                dnaFile)
            print searchPath
        else:
            return filename.getFullpath()

    def findLeaderBoards(self, dnaData, zoneId):
        leaderboards = []
        if 'leaderBoard' in dnaData.getName():
            x, y, z = dnaData.getPos()
            h, p, r = dnaData.getHpr()
            leaderboard = DistributedLeaderBoardAI(self, dnaData.getName(), x,
                                                   y, z, h, p, r)
            leaderboard.generateWithRequired(zoneId)
            leaderboards.append(leaderboard)

        for i in xrange(dnaData.getNumChildren()):
            foundLeaderBoards = self.findLeaderBoards(dnaData.at(i), zoneId)
            leaderboards.extend(foundLeaderBoards)

        return leaderboards
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, stateServerChannel, districtName):
        ToontownInternalRepository.__init__(
            self, baseChannel, stateServerChannel, dcSuffix='AI')

        self.districtName = districtName

        self.notify.setInfo(True)  # Our AI repository should always log info.
        self.hoods = []
        self.cogHeadquarters = []
        self.dnaStoreMap = {}
        self.dnaDataMap = {}
        self.suitPlanners = {}
        self.buildingManagers = {}
        self.factoryMgr = None
        self.mintMgr = None
        self.lawOfficeMgr = None
        self.countryClubMgr = None

        self.zoneAllocator = UniqueIdAllocator(ToontownGlobals.DynamicZonesBegin,
                                               ToontownGlobals.DynamicZonesEnd)
        self.zoneDataStore = AIZoneDataStore()

        self.wantFishing = self.config.GetBool('want-fishing', True)
        self.wantHousing = self.config.GetBool('want-housing', True)
        self.wantPets = self.config.GetBool('want-pets', True)
        self.wantKarts = self.config.GetBool('want-karts', True)
        self.wantParties = self.config.GetBool('want-parties', True)
        self.wantEmblems = self.config.GetBool('want-emblems', True)
        self.wantCogbuildings = self.config.GetBool('want-cogbuildings', True)
        self.wantCogdominiums = self.config.GetBool('want-cogdominiums', True)
        self.wantTrackClsends = self.config.GetBool('want-track-clsends', False)
        self.wantTopToons = self.config.GetBool('want-top-toons', True)
        self.baseXpMultiplier = self.config.GetFloat('base-xp-multiplier', 1.0)

        self.cogSuitMessageSent = False

    def createManagers(self):
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)
        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)
        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(2)
        self.topToonsMgr = TopToonsManagerAI(self)
        #self.topToonsMgr.generateWithRequired(2)
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)
        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)
        self.questManager = QuestManagerAI(self)       
        self.banManager = BanManagerAI.BanManagerAI(self)
        self.suitInvasionManager = SuitInvasionManagerAI(self)
        self.blackCatMgr = DistributedBlackCatMgrAI(self)
        self.blackCatMgr.generateWithRequired(2)
        self.reportMgr = DistributedReportMgrAI(self)
        self.reportMgr.generateWithRequired(2)
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(2)
        self.cogSuitMgr = CogSuitManagerAI.CogSuitManagerAI()
        self.promotionMgr = PromotionManagerAI.PromotionManagerAI(self)
        self.cogPageManager = CogPageManagerAI.CogPageManagerAI()
        self.codeRedemptionMgr = TTCodeRedemptionMgrAI(self)
        self.codeRedemptionMgr.generateWithRequired(2)
        self.buildingQueryMgr = DistributedBuildingQueryMgrAI(self)
        self.buildingQueryMgr.generateWithRequired(2)
        if self.wantTopToons:
            self.topToonsMgr = TopToonsManagerAI(self)
        if self.wantKarts:
            self.leaderboardMgr = LeaderboardMgrAI(self)
        if self.wantFishing:
            self.fishManager = FishManagerAI(self)
        if self.wantHousing:
            self.estateManager = EstateManagerAI(self)
            self.estateManager.generateWithRequired(2)
            self.catalogManager = CatalogManagerAI(self)
            self.catalogManager.generateWithRequired(2)
        if self.wantPets:
            self.petMgr = PetManagerAI(self)
        if self.wantParties:
            self.partyManager = DistributedPartyManagerAI(self)
            self.partyManager.generateWithRequired(2)
            self.globalPartyMgr = self.generateGlobalObject(
                OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')
        #self.lobbyManager = DistributedLobbyManagerAI(self)
        #self.lobbyManager.generateWithRequired(2)
        #self.globalLobbyMgr = self.generateGlobalObject(
        #    OTP_DO_ID_GLOBAL_LOBBY_MANAGER, 'GlobalLobbyManager')

    def createSafeZones(self):
        NPCToons.generateZone2NpcDict()
        if self.config.GetBool('want-toontown-central', True):
            self.hoods.append(TTHoodAI.TTHoodAI(self))
        if self.config.GetBool('want-donalds-dock', True):
            self.hoods.append(DDHoodAI.DDHoodAI(self))
        if self.config.GetBool('want-daisys-garden', True):
            self.hoods.append(DGHoodAI.DGHoodAI(self))
        if self.config.GetBool('want-minnies-melodyland', True):
            self.hoods.append(MMHoodAI.MMHoodAI(self))
        if self.config.GetBool('want-the-brrrgh', True):
            self.hoods.append(BRHoodAI.BRHoodAI(self))
        if self.config.GetBool('want-donalds-dreamland', True):
            self.hoods.append(DLHoodAI.DLHoodAI(self))
        if self.config.GetBool('want-goofy-speedway', True):
            self.hoods.append(GSHoodAI.GSHoodAI(self))
        if self.config.GetBool('want-outdoor-zone', True):
            self.hoods.append(OZHoodAI.OZHoodAI(self))
        if self.config.GetBool('want-golf-zone', True):
            self.hoods.append(GZHoodAI.GZHoodAI(self))

    def createCogHeadquarters(self):
        NPCToons.generateZone2NpcDict()
        if self.config.GetBool('want-sellbot-headquarters', True):
            self.factoryMgr = FactoryManagerAI.FactoryManagerAI(self)
            self.cogHeadquarters.append(SellbotHQAI.SellbotHQAI(self))
        if self.config.GetBool('want-cashbot-headquarters', True):
            self.mintMgr = MintManagerAI.MintManagerAI(self)
            self.cogHeadquarters.append(CashbotHQAI.CashbotHQAI(self))
        if self.config.GetBool('want-lawbot-headquarters', True):
            self.lawOfficeMgr = LawOfficeManagerAI.LawOfficeManagerAI(self)
            self.cogHeadquarters.append(LawbotHQAI.LawbotHQAI(self))
        if self.config.GetBool('want-bossbot-headquarters', True):
            self.countryClubMgr = CountryClubManagerAI.CountryClubManagerAI(self)
            self.cogHeadquarters.append(BossbotHQAI.BossbotHQAI(self))

    def handleConnected(self):
        ToontownInternalRepository.handleConnected(self)
        threading.Thread(target=self.startDistrict).start()
    
    def startDistrict(self):
        self.districtId = self.allocateChannel()
        self.notify.info('Creating ToontownDistrictAI(%d)...' % self.districtId)
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(
            self.districtId, self.getGameDoId(), 2)
        self.notify.info('Claiming ownership of channel ID: %d...' % self.districtId)
        self.claimOwnership(self.districtId)

        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.setDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(
            self.allocateChannel(), self.getGameDoId(), 3)
        self.notify.info('Created ToontownDistrictStats(%d)' % self.districtStats.doId)

        self.notify.info('Creating managers...')
        self.createManagers()
        if self.config.GetBool('want-safe-zones', True):
            self.notify.info('Creating safe zones...')
            self.createSafeZones()
        if self.config.GetBool('want-cog-headquarters', True):
            self.notify.info('Creating Cog headquarters...')
            self.createCogHeadquarters()

        self.notify.info('Making district available...')
        self.distributedDistrict.b_setAvailable(1)
        self.notify.info('Done.')

    def claimOwnership(self, channelId):
        datagram = PyDatagram()
        datagram.addServerHeader(channelId, self.ourChannel, STATESERVER_OBJECT_SET_AI)
        datagram.addChannel(self.ourChannel)
        self.send(datagram)

    def lookupDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phaseNum = ToontownGlobals.phaseMap[hoodId]
        else:
            phaseNum = ToontownGlobals.streetPhaseMap[hoodId]
        return 'phase_%s/dna/%s_%s.pdna' % (phaseNum, hood, zoneId)

    def loadDNAFileAI(self, dnastore, filename):
        return loadDNAFileAI(dnastore, filename)

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() - 1)

    def allocateZone(self):
        return self.zoneAllocator.allocate()

    def deallocateZone(self, zone):
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getTrackClsends(self):
        return self.wantTrackClsends

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def trueUniqueName(self, name):
        return self.uniqueName(name)
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, serverId, districtName):
        ToontownInternalRepository.__init__(self, baseChannel, serverId, dcSuffix='AI')

        self.dnaSpawner = DNASpawnerAI(self)

        self.districtName = districtName

        self.zoneAllocator = UniqueIdAllocator(ToontownGlobals.DynamicZonesBegin,
                                               ToontownGlobals.DynamicZonesEnd)
        self.zoneId2owner = {}

        NPCToons.generateZone2NpcDict()

        self.hoods = []
        self.zoneDataStore = AIZoneDataStore()

        self.useAllMinigames = self.config.GetBool('want-all-minigames', False)
        self.doLiveUpdates = self.config.GetBool('want-live-updates', True)

        self.holidayManager = HolidayManagerAI(self)

        self.fishManager = FishManagerAI()
        self.questManager = QuestManagerAI(self)
        self.cogPageManager = CogPageManagerAI()
        self.factoryMgr = FactoryManagerAI(self)
        self.mintMgr = MintManagerAI(self)
        self.lawOfficeMgr = LawOfficeManagerAI(self)
        self.countryClubMgr = CountryClubManagerAI(self)
        self.promotionMgr = PromotionManagerAI(self)
        self.cogSuitMgr = CogSuitManagerAI(self)
        self.suitInvasionManager = SuitInvasionManagerAI(self)

        self.statusSender = ShardStatusSender(self)

        self.dnaStoreMap = {}

        self.buildingManagers = {}
        self.suitPlanners = {}

    def getTrackClsends(self):
        return False

    def handleConnected(self):
        ToontownInternalRepository.handleConnected(self)
        self.districtId = self.allocateChannel()
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(self.districtId,
                                                           self.getGameDoId(), 2)

        # Claim ownership of that district...
        dg = PyDatagram()
        dg.addServerHeader(self.districtId, self.ourChannel, STATESERVER_OBJECT_SET_AI)
        dg.addChannel(self.ourChannel)
        self.send(dg)

        self.createGlobals()
        self.createZones()

        self.statusSender.start()

        self.distributedDistrict.b_setAvailable(1)
        self.notify.info('District is now ready.')

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() + 1)
        self.statusSender.sendStatus()

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() - 1)
        self.statusSender.sendStatus()

    def allocateZone(self, owner=None):
        zoneId = self.zoneAllocator.allocate()
        if owner:
            self.zoneId2owner[zoneId] = owner
        return zoneId

    def deallocateZone(self, zone):
        if self.zoneId2owner.get(zone):
            del self.zoneId2owner[zone]
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def createGlobals(self):
        """
        Create "global" objects, e.g. TimeManager et al.
        """
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
                                                     self.getGameDoId(), 3)

        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)

        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)

        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)

        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)

        if config.GetBool('want-parties', True):
            self.partyManager = DistributedPartyManagerAI(self)
            self.partyManager.generateWithRequired(2)
            self.globalPartyMgr = self.generateGlobalObject(OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        self.estateManager = EstateManagerAI(self)
        self.estateManager.generateWithRequired(2)

        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(2)

        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)

        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(2)

        self.codeRedemptionManager = TTCodeRedemptionMgrAI(self)
        self.codeRedemptionManager.generateWithRequired(2)

    def createZones(self):
        """
        Spawn safezone objects, streets, doors, NPCs, etc.
        """
        start = time.clock()
        def clearQueue():
            '''So the TCP window doesn't fill up and we get the axe'''
            while self.readerPollOnce():
                pass

        self.hoods.append(TTHoodAI.TTHoodAI(self))
        clearQueue()
        self.hoods.append(DDHoodAI.DDHoodAI(self))
        clearQueue()
        self.hoods.append(DGHoodAI.DGHoodAI(self))
        clearQueue()
        self.hoods.append(BRHoodAI.BRHoodAI(self))
        clearQueue()
        self.hoods.append(MMHoodAI.MMHoodAI(self))
        clearQueue()
        self.hoods.append(DLHoodAI.DLHoodAI(self))
        clearQueue()
        self.hoods.append(GSHoodAI.GSHoodAI(self))
        clearQueue()
        self.hoods.append(OZHoodAI.OZHoodAI(self))
        clearQueue()
        self.hoods.append(GZHoodAI.GZHoodAI(self))
        clearQueue()
        self.hoods.append(SellbotHQAI.SellbotHQAI(self))
        clearQueue()
        self.hoods.append(CashbotHQAI.CashbotHQAI(self))
        clearQueue()
        self.hoods.append(LawbotHQAI.LawbotHQAI(self))
        clearQueue()
        self.hoods.append(BossbotHQAI.BossbotHQAI(self))
        clearQueue()
        print('Done creating Zones!')

        for sp in self.suitPlanners.values():
            sp.assignInitialSuitBuildings()

    def genDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]

        return 'phase_%s/dna/%s_%s.xml' % (phase, hood, zoneId)

    def loadDNA(self, filename):
        with open('/' + filename) as f:
            tree = DNAParser.parse(f)

        return tree
Beispiel #8
0
class ToontownAIRepository(ToontownInternalRepository):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'ToontownAIRepository')

    def __init__(self, baseChannel, serverId, districtName):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            serverId,
                                            dcSuffix='AI')
        self.districtName = districtName
        self.doLiveUpdates = config.GetBool('want-live-updates', True)
        self.wantCogdominiums = config.GetBool('want-cogdominiums', True)
        self.useAllMinigames = config.GetBool('want-all-minigames', True)
        self.districtId = None
        self.district = None
        self.districtStats = None
        self.holidayManager = None
        self.zoneDataStore = None
        self.petMgr = None
        self.suitInvasionManager = None
        self.zoneAllocator = None
        self.zoneId2owner = {}
        self.questManager = None
        self.promotionMgr = None
        self.cogPageManager = None
        self.raceMgr = None
        self.countryClubMgr = None
        self.factoryMgr = None
        self.mintMgr = None
        self.lawMgr = None
        self.cogSuitMgr = None
        self.timeManager = None
        self.newsManager = None
        self.welcomeValleyManager = None
        self.inGameNewsMgr = None
        self.catalogManager = None
        self.trophyMgr = None
        self.zoneTable = {}
        self.dnaStoreMap = {}
        self.dnaDataMap = {}
        self.hoods = []
        self.buildingManagers = {}
        self.suitPlanners = {}

    def handleConnected(self):
        ToontownInternalRepository.handleConnected(self)

        # Generate our district...
        self.districtId = self.allocateChannel()
        self.district = ToontownDistrictAI(self)
        self.district.setName(self.districtName)
        self.district.generateWithRequiredAndId(self.districtId,
                                                self.getGameDoId(),
                                                OTP_ZONE_ID_DISTRICTS)

        # Claim ownership of that district...
        self.district.setAI(self.ourChannel)

        # Create our local objects.
        self.createLocals()

        # Create our global objects.
        self.createGlobals()

        # Create our zones.
        self.createZones()

        # Make our district available, and we're done.
        self.district.b_setAvailable(True)
        self.notify.info('Done.')

    def createLocals(self):
        """
        Creates "local" (non-distributed) objects.
        """

        # Create our holiday manager...
        self.holidayManager = HolidayManagerAI(self)

        # Create our zone data store...
        self.zoneDataStore = AIZoneDataStore()

        # Create our pet manager...
        self.petMgr = PetManagerAI(self)

        # Create our suit invasion manager...
        self.suitInvasionManager = SuitInvasionManagerAI(self)

        # Create our zone allocator...
        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)

        # Create our quest manager...
        self.questManager = QuestManagerAI(self)

        # Create our promotion manager...
        self.promotionMgr = PromotionManagerAI(self)

        # Create our Cog page manager...
        self.cogPageManager = CogPageManagerAI(self)

        # Create our race manager...
        self.raceMgr = RaceManagerAI(self)

        # Create our country club manager...
        self.countryClubMgr = CountryClubManagerAI(self)

        # Create our factory manager...
        self.factoryMgr = FactoryManagerAI(self)

        # Create our mint manager...
        self.mintMgr = MintManagerAI(self)

        # Create our law office manager...
        self.lawMgr = LawOfficeManagerAI(self)

        # Create our Cog suit manager...
        self.cogSuitMgr = CogSuitManagerAI(self)

    def createGlobals(self):
        """
        Creates "global" (distributed) objects.
        """

        # Generate our district stats...
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(
            self.allocateChannel(), self.district.getDoId(),
            OTP_ZONE_ID_DISTRICTS_STATS)

        # Generate our time manager...
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our news manager...
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our Welcome Valley manager...
        self.welcomeValleyManager = WelcomeValleyManagerAI(self)
        self.welcomeValleyManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our in-game news manager...
        self.inGameNewsMgr = DistributedInGameNewsMgrAI(self)
        self.inGameNewsMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our catalog manager...
        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

        # Generate our trophy manager...
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)

    def generateHood(self, hoodConstructor, zoneId):
        # Bossbot HQ doesn't use DNA, so we skip over that.
        if zoneId != ToontownGlobals.BossbotHQ:
            self.dnaStoreMap[zoneId] = DNAStorage()
            self.dnaDataMap[zoneId] = loadDNAFileAI(
                self.dnaStoreMap[zoneId], self.genDNAFileName(zoneId))
            if zoneId in ToontownGlobals.HoodHierarchy:
                for streetId in ToontownGlobals.HoodHierarchy[zoneId]:
                    self.dnaStoreMap[streetId] = DNAStorage()
                    self.dnaDataMap[streetId] = loadDNAFileAI(
                        self.dnaStoreMap[streetId],
                        self.genDNAFileName(streetId))

        hood = hoodConstructor(self, zoneId)
        hood.startup()
        self.hoods.append(hood)

    def createZones(self):
        # First, generate our zone2NpcDict...
        NPCToons.generateZone2NpcDict()

        # Donald's Dock
        self.zoneTable[ToontownGlobals.DonaldsDock] = (
            (ToontownGlobals.DonaldsDock, 1,
             0), (ToontownGlobals.BarnacleBoulevard, 1,
                  1), (ToontownGlobals.SeaweedStreet, 1,
                       1), (ToontownGlobals.LighthouseLane, 1, 1))
        self.generateHood(DDHoodDataAI, ToontownGlobals.DonaldsDock)

        # Toontown Central
        self.zoneTable[ToontownGlobals.ToontownCentral] = (
            (ToontownGlobals.ToontownCentral, 1,
             0), (ToontownGlobals.SillyStreet, 1,
                  1), (ToontownGlobals.LoopyLane, 1,
                       1), (ToontownGlobals.PunchlinePlace, 1, 1))
        self.generateHood(TTHoodDataAI, ToontownGlobals.ToontownCentral)

        # The Brrrgh
        self.zoneTable[ToontownGlobals.TheBrrrgh] = (
            (ToontownGlobals.TheBrrrgh, 1,
             0), (ToontownGlobals.WalrusWay, 1,
                  1), (ToontownGlobals.SleetStreet, 1,
                       1), (ToontownGlobals.PolarPlace, 1, 1))
        self.generateHood(BRHoodDataAI, ToontownGlobals.TheBrrrgh)

        # Minnie's Melodyland
        self.zoneTable[ToontownGlobals.MinniesMelodyland] = (
            (ToontownGlobals.MinniesMelodyland, 1,
             0), (ToontownGlobals.AltoAvenue, 1,
                  1), (ToontownGlobals.BaritoneBoulevard, 1,
                       1), (ToontownGlobals.TenorTerrace, 1, 1))
        self.generateHood(MMHoodDataAI, ToontownGlobals.MinniesMelodyland)

        # Daisy Gardens
        self.zoneTable[ToontownGlobals.DaisyGardens] = (
            (ToontownGlobals.DaisyGardens, 1,
             0), (ToontownGlobals.ElmStreet, 1,
                  1), (ToontownGlobals.MapleStreet, 1,
                       1), (ToontownGlobals.OakStreet, 1, 1))
        self.generateHood(DGHoodDataAI, ToontownGlobals.DaisyGardens)

        # Chip 'n Dale's Acorn Acres
        self.zoneTable[ToontownGlobals.OutdoorZone] = ((
            ToontownGlobals.OutdoorZone, 1, 0), )
        self.generateHood(OZHoodDataAI, ToontownGlobals.OutdoorZone)

        # Goofy Speedway
        self.zoneTable[ToontownGlobals.GoofySpeedway] = ((
            ToontownGlobals.GoofySpeedway, 1, 0), )
        self.generateHood(GSHoodDataAI, ToontownGlobals.GoofySpeedway)

        # Donald's Dreamland
        self.zoneTable[ToontownGlobals.DonaldsDreamland] = (
            (ToontownGlobals.DonaldsDreamland, 1,
             0), (ToontownGlobals.LullabyLane, 1,
                  1), (ToontownGlobals.PajamaPlace, 1, 1))
        self.generateHood(DLHoodDataAI, ToontownGlobals.DonaldsDreamland)

        # Bossbot HQ
        self.zoneTable[ToontownGlobals.BossbotHQ] = ((
            ToontownGlobals.BossbotHQ, 0, 0), )
        self.generateHood(BossbotHQDataAI, ToontownGlobals.BossbotHQ)

        # Sellbot HQ
        self.zoneTable[ToontownGlobals.SellbotHQ] = (
            (ToontownGlobals.SellbotHQ, 0,
             1), (ToontownGlobals.SellbotFactoryExt, 0, 1))
        self.generateHood(CSHoodDataAI, ToontownGlobals.SellbotHQ)

        # Cashbot HQ
        self.zoneTable[ToontownGlobals.CashbotHQ] = ((
            ToontownGlobals.CashbotHQ, 0, 1), )
        self.generateHood(CashbotHQDataAI, ToontownGlobals.CashbotHQ)

        # Lawbot HQ
        self.zoneTable[ToontownGlobals.LawbotHQ] = ((ToontownGlobals.LawbotHQ,
                                                     0, 1), )
        self.generateHood(LawbotHQDataAI, ToontownGlobals.LawbotHQ)

        # Chip 'n Dale's MiniGolf
        self.zoneTable[ToontownGlobals.GolfZone] = ((ToontownGlobals.GolfZone,
                                                     1, 0), )
        self.generateHood(GZHoodDataAI, ToontownGlobals.GolfZone)

        # Welcome Valley zones
        self.welcomeValleyManager.createWelcomeValleyZones()

        # Assign the initial suit buildings.
        for suitPlanner in list(self.suitPlanners.values()):
            suitPlanner.assignInitialSuitBuildings()

    def genDNAFileName(self, zoneId):
        canonicalZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        canonicalHoodId = ZoneUtil.getCanonicalHoodId(canonicalZoneId)
        hood = ToontownGlobals.dnaMap[canonicalHoodId]
        if canonicalHoodId == canonicalZoneId:
            canonicalZoneId = 'sz'
            phase = ToontownGlobals.phaseMap[canonicalHoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[canonicalHoodId]

        if 'outdoor_zone' in hood or 'golf_zone' in hood:
            phase = '6'

        return 'phase_%s/dna/%s_%s.dna' % (phase, hood, canonicalZoneId)

    def lookupDNAFileName(self, dnaFileName):
        searchPath = DSearchPath()
        searchPath.appendDirectory(Filename('resources/phase_3.5/dna'))
        searchPath.appendDirectory(Filename('resources/phase_4/dna'))
        searchPath.appendDirectory(Filename('resources/phase_5/dna'))
        searchPath.appendDirectory(Filename('resources/phase_5.5/dna'))
        searchPath.appendDirectory(Filename('resources/phase_6/dna'))
        searchPath.appendDirectory(Filename('resources/phase_8/dna'))
        searchPath.appendDirectory(Filename('resources/phase_9/dna'))
        searchPath.appendDirectory(Filename('resources/phase_10/dna'))
        searchPath.appendDirectory(Filename('resources/phase_11/dna'))
        searchPath.appendDirectory(Filename('resources/phase_12/dna'))
        searchPath.appendDirectory(Filename('resources/phase_13/dna'))
        filename = Filename(dnaFileName)
        found = vfs.resolveFilename(filename, searchPath)
        if not found:
            self.notify.warning('lookupDNAFileName - %s not found on:' %
                                dnaFileName)
            print(searchPath)
        else:
            return filename.getFullpath()

    def loadDNAFileAI(self, dnaStore, dnaFileName):
        return loadDNAFileAI(dnaStore, dnaFileName)

    def findFishingPonds(self, dnaData, zoneId, area):
        return [], []  # TODO

    def findPartyHats(self, dnaData, zoneId):
        return []  # TODO

    def findRacingPads(self,
                       dnaData,
                       zoneId,
                       area,
                       type='racing_pad',
                       overrideDNAZone=False):
        kartPads, kartPadGroups = [], []
        if type in dnaData.getName():
            if type == 'racing_pad':
                nameSplit = dnaData.getName().split('_')
                racePad = DistributedRacePadAI(self)
                racePad.setArea(area)
                racePad.index = int(nameSplit[2])
                racePad.genre = nameSplit[3]
                trackInfo = RaceGlobals.getNextRaceInfo(
                    -1, racePad.genre, racePad.index)
                racePad.setTrackInfo([trackInfo[0], trackInfo[1]])
                racePad.laps = trackInfo[2]
                racePad.generateWithRequired(zoneId)
                kartPads.append(racePad)
                kartPadGroups.append(dnaData)
            elif type == 'viewing_pad':
                viewPad = DistributedViewPadAI(self)
                viewPad.setArea(area)
                viewPad.generateWithRequired(zoneId)
                kartPads.append(viewPad)
                kartPadGroups.append(dnaData)

        for i in range(dnaData.getNumChildren()):
            foundKartPads, foundKartPadGroups = self.findRacingPads(
                dnaData.at(i), zoneId, area, type, overrideDNAZone)
            kartPads.extend(foundKartPads)
            kartPadGroups.extend(foundKartPadGroups)

        return kartPads, kartPadGroups

    def findStartingBlocks(self, dnaData, kartPad):
        startingBlocks = []
        for i in range(dnaData.getNumChildren()):
            groupName = dnaData.getName()
            block = dnaData.at(i)
            blockName = block.getName()
            if 'starting_block' in blockName:
                cls = DistributedStartingBlockAI if 'racing_pad' in groupName else DistributedViewingBlockAI
                x, y, z = block.getPos()
                h, p, r = block.getHpr()
                padLocationId = int(blockName[-1])
                startingBlock = cls(self, kartPad, x, y, z, h, p, r,
                                    padLocationId)
                startingBlock.generateWithRequired(kartPad.zoneId)
                startingBlocks.append(startingBlock)

        return startingBlocks

    def findLeaderBoards(self, dnaData, zoneId):
        leaderBoards = []
        if 'leaderBoard' in dnaData.getName():
            x, y, z = dnaData.getPos()
            h, p, r = dnaData.getHpr()
            leaderBoard = DistributedLeaderBoardAI(self, dnaData.getName(), x,
                                                   y, z, h, p, r)
            leaderBoard.generateWithRequired(zoneId)
            leaderBoards.append(leaderBoard)

        for i in range(dnaData.getNumChildren()):
            foundLeaderBoards = self.findLeaderBoards(dnaData.at(i), zoneId)
            leaderBoards.extend(foundLeaderBoards)

        return leaderBoards

    def getTrackClsends(self):
        return False

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def getAvatarDisconnectReason(self, avId):
        return self.timeManager.avId2disconnectcode.get(
            avId, ToontownGlobals.DisconnectUnknown)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)

    def allocateZone(self, owner=None):
        zoneId = self.zoneAllocator.allocate()
        if owner:
            self.zoneId2owner[zoneId] = owner

        return zoneId

    def deallocateZone(self, zone):
        if self.zoneId2owner.get(zone):
            del self.zoneId2owner[zone]

        self.zoneAllocator.free(zone)

    def trueUniqueName(self, idString):
        return self.uniqueName(idString)

    def sendQueryToonMaxHp(self, avId, callback):
        pass  # TODO?
Beispiel #9
0
class ToontownAIRepository(AIDistrict):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        "ToontownAIRepository")

    # The zone table determines which dnaStores are created and
    # whether bulding manager or suit planner ai objects are created.
    # The elements consist of:
    # (int the_zone_ID, bool create_building_manager, bool create_suit_planner)
    zoneTable = {
        ToontownCentral: (
            [ToontownCentral, 1, 0],
            [ToontownCentral + 100, 1, 1],
            [ToontownCentral + 200, 1, 1],
            [ToontownCentral + 300, 1, 1],
        ),
        DonaldsDock: (
            [DonaldsDock, 1, 0],
            [DonaldsDock + 100, 1, 1],
            [DonaldsDock + 200, 1, 1],
            [DonaldsDock + 300, 1, 1],
        ),
        MinniesMelodyland: (
            [MinniesMelodyland, 1, 0],
            [MinniesMelodyland + 100, 1, 1],
            [MinniesMelodyland + 200, 1, 1],
            [MinniesMelodyland + 300, 1, 1],
        ),
        TheBrrrgh: (
            [TheBrrrgh, 1, 0],
            [TheBrrrgh + 100, 1, 1],
            [TheBrrrgh + 200, 1, 1],
            [TheBrrrgh + 300, 1, 1],
        ),
        DonaldsDreamland: (
            [DonaldsDreamland, 1, 0],
            [DonaldsDreamland + 100, 1, 1],
            [DonaldsDreamland + 200, 1, 1],
        ),
        DaisyGardens: (
            [DaisyGardens, 1, 0],
            [DaisyGardens + 100, 1, 1],
            [DaisyGardens + 200, 1, 1],
            [DaisyGardens + 300, 1, 1],
        ),
        GoofySpeedway: ([GoofySpeedway, 1, 0], ),
        OutdoorZone: ([OutdoorZone, 0, 0], ),
        SellbotHQ: (
            [SellbotHQ, 0, 1],
            [SellbotHQ + 200, 0, 1],
        ),
        CashbotHQ: ([CashbotHQ, 0, 1], ),
        LawbotHQ: ([LawbotHQ, 0, 1], ),
        GolfZone: ([GolfZone, 0, 0], ),
        BossbotHQ: ([BossbotHQ, 0, 0], ),
    }

    def __init__(self, *args, **kw):
        AIDistrict.__init__(self, *args, **kw)
        self.setTimeWarning(
            ConfigVariableDouble('aimsg-time-warning', 4).getValue())

        self.dnaSearchPath = DSearchPath()
        if os.getenv('TTMODELS'):
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_3.5/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_4/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_5/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_5.5/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_6/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_8/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_9/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_10/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_11/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_12/dna'))
            self.dnaSearchPath.appendDirectory(
                Filename.expandFrom('$TTMODELS/built/phase_13/dna'))

            # In the publish environment, TTMODELS won't be on the model
            # path by default, so we always add it there.  In the dev
            # environment, it'll be on the model path already, but it
            # doesn't hurt to add it again.
            getModelPath().appendDirectory(Filename.expandFrom("$TTMODELS"))
        else:
            self.dnaSearchPath.appendDirectory(Filename('.'))
            self.dnaSearchPath.appendDirectory(Filename('ttmodels/src/dna'))

        # Initialize our query context.
        self.__queryEstateContext = 0
        self.__queryEstateFuncMap = {}

        # Set a hook so we can process queryToonMaxHp() requests.
        self.accept('queryToonMaxHp', self.__queryToonMaxHpResponse)

        # For debugging
        wantNewToonhall = ConfigVariableBool('want-new-toonhall', 1).getValue()
        if (not wantNewToonhall) or \
            (wantNewToonhall and not ConfigVariableBool('show-scientists', 0).getValue()):
            for i in range(3):
                npcId = 2018 + i
                if npcId in NPCToons.NPCToonDict:
                    del NPCToons.NPCToonDict[npcId]

        NPCToons.generateZone2NpcDict()

        if not ConfigVariableBool('want-suits-everywhere', 1).getValue():
            # This is a special mode for development: we don't want
            # suits walking around all over the world.  Turn off all
            # the SuitPlanner flags.
            for zones in list(self.zoneTable.values()):
                for zone in zones:
                    zone[2] = 0

            if not ConfigVariableBool('want-suits-nowhere', 1).getValue():
                # However, we do want them in at least one street.
                self.zoneTable[ToontownCentral][1][2] = 1

        # minigame debug flags
        self.wantMinigameDifficulty = ConfigVariableBool(
            'want-minigame-difficulty', 0).getValue()

        self.minigameDifficulty = ConfigVariableDouble('minigame-difficulty',
                                                       -1.).getValue()
        if self.minigameDifficulty == -1.:
            del self.minigameDifficulty
        self.minigameSafezoneId = ConfigVariableInt('minigame-safezone-id',
                                                    -1).getValue()
        if self.minigameSafezoneId == -1:
            del self.minigameSafezoneId

        # should we pick from the entire list of minigames regardless of
        # the number of participating toons? (for debugging)
        self.useAllMinigames = ConfigVariableBool('use-all-minigames',
                                                  0).getValue()

        self.wantCogdominiums = ConfigVariableBool('want-cogdominiums',
                                                   0).getValue()

        self.hoods = []
        self.buildingManagers = {}
        self.suitPlanners = {}

        # Guard for publish
        if simbase.wantBingo:
            self.bingoMgr = None

        self.toontownTimeManager = ToontownTimeManager.ToontownTimeManager()
        self.toontownTimeManager.updateLoginTimes(time.time(), time.time(),
                                                  globalClock.getRealTime())

        # turn on garbage-collection debugging to see if it's related
        # to the chugs we're seeing
        # eventually we will probably put in our own gc pump
        if ConfigVariableBool('gc-debug', 0).getValue():
            import gc
            gc.set_debug(gc.DEBUG_STATS)

        self.deliveryManager = self.generateGlobalObject(
            OtpDoGlobals.OTP_DO_ID_TOONTOWN_DELIVERY_MANAGER,
            "DistributedDeliveryManager")

        self.mailManager = self.generateGlobalObject(
            OtpDoGlobals.OTP_DO_ID_TOONTOWN_MAIL_MANAGER,
            "DistributedMailManager")

        #self.partyManager = self.generateGlobalObject(
        #    OtpDoGlobals.OTP_DO_ID_TOONTOWN_PARTY_MANAGER,
        #    "DistributedPartyManager")

        #self.codeRedemptionManager = self.generateGlobalObject(
        #    OtpDoGlobals.OTP_DO_ID_TOONTOWN_CODE_REDEMPTION_MANAGER,
        #    "TTCodeRedemptionMgr")

        #self.randomSourceManager = self.generateGlobalObject(
        #    OtpDoGlobals.OTP_DO_ID_TOONTOWN_NON_REPEATABLE_RANDOM_SOURCE,
        #    "NonRepeatableRandomSource")

        if ConfigVariableBool('want-ddsm', 1).getValue():
            self.dataStoreManager = self.generateGlobalObject(
                OtpDoGlobals.OTP_DO_ID_TOONTOWN_TEMP_STORE_MANAGER,
                "DistributedDataStoreManager")

        self.groupManager = ToontownGroupManager.ToontownGroupManager()

    def getGameDoId(self):
        return OTP_DO_ID_TOONTOWN

    def getDatabaseIdForClassName(self, className):
        return DatabaseIdFromClassName.get(className, DefaultDatabaseChannelId)

    def _isValidPlayerLocation(self, parentId, zoneId):
        # keep players out of parents that are smaller than N, where N is smaller than all district IDs
        # and N is random enough to be confusing for hackers
        if parentId < 900000:
            return False
        # keep players out of uberzones and zones up to 900 which are not used anyway, to confuse hackers
        if (OTPGlobals.UberZone <= zoneId <= 900):
            return False
        """
        # this doesn't work in the current TT LIVE publish, when teleporting, old district gets
        # setLocation on new district
        if parentId != self.districtId:
            return False
        if zoneId == 2:
            return False
            """
        return True

    def saveBuildings(self):
        """
        Saves the state of all the buildings on all the managed
        streets, so it will be restored on AI restart.
        """
        for mgr in list(self.buildingManagers.values()):
            mgr.save()

    def genDNAFileName(self, zoneId):
        """
        determines the name of the DNA file that should
        be loaded for the neighborhood.
        """
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = "sz"

        # Nowadays, we use a search path to find the DNA file, instead
        # of looking for it in only one place.  Not sure if this is a
        # great idea; but it makes it easier to run a test AI on
        # ttown.

        return self.lookupDNAFileName("%s_%s.dna" % (hood, zoneId))

    def lookupDNAFileName(self, filename):
        dnaFile = Filename(filename)
        found = vfs.resolveFilename(dnaFile, self.dnaSearchPath)

        return dnaFile.cStr()

##         phase = streetPhaseMap[hoodId]
##         if hoodId==zoneId:
##             zoneId="sz"
##             if hood=='toontown_central':
##                 phase-=1

##         try:
##             # There may be no simbase, if this is client code.
##             if simbase.aiService:
##                 return "./" + hood + "_" + str(zoneId) + ".dna"
##             else:
##                 return "phase_" + str(phase) + "/dna/" + hood + "_" + \
##                        str(zoneId) + ".dna"
##         except:
##             return "phase_" + str(phase) + "/dna/" + hood + "_" + \
##                    str(zoneId) + ".dna"

    def loadDNA(self):
        """
        Return a dictionary of zoneId to DNAStorage objects
        """
        self.dnaStoreMap = {}
        self.dnaDataMap = {}
        for zones in list(self.zoneTable.values()):
            for zone in zones:
                zoneId = zone[0]
                dnaStore = DNAStorage()
                dnaFileName = self.genDNAFileName(zoneId)
                dnaData = self.loadDNAFileAI(dnaStore, dnaFileName)
                self.dnaStoreMap[zoneId] = dnaStore
                self.dnaDataMap[zoneId] = dnaData

    def createObjects(self):
        # First, load up all of our DNA files for the world.
        self.loadDNA()

        # Create a new district (aka shard) for this AI:
        self.district = ToontownDistrictAI(self, self.districtName)
        self.district.generateOtpObject(OTP_DO_ID_TOONTOWN,
                                        OTP_ZONE_ID_DISTRICTS,
                                        doId=self.districtId)

        # The Time manager.  This negotiates a timestamp exchange for
        # the purposes of synchronizing clocks between client and
        # server with a more accurate handshaking protocol than we
        # would otherwise get.
        #
        # We must create this object first, so clients who happen to
        # come into the world while the AI is still coming up
        # (particularly likely if the AI crashed while players were
        # in) will get a chance to synchronize.
        self.timeManager = TimeManagerAI.TimeManagerAI(self)
        self.timeManager.generateOtpObject(self.district.getDoId(),
                                           OTPGlobals.UberZone)

        self.partyManager = DistributedPartyManagerAI.DistributedPartyManagerAI(
            self)
        self.partyManager.generateOtpObject(self.district.getDoId(),
                                            OTPGlobals.UberZone)

        self.inGameNewsMgr = DistributedInGameNewsMgrAI.DistributedInGameNewsMgrAI(
            self)
        self.inGameNewsMgr.generateOtpObject(self.district.getDoId(),
                                             OTPGlobals.UberZone)

        self.whitelistMgr = DistributedWhitelistMgrAI.DistributedWhitelistMgrAI(
            self)
        self.whitelistMgr.generateOtpObject(self.district.getDoId(),
                                            OTPGlobals.UberZone)

        self.cpuInfoMgr = DistributedCpuInfoMgrAI.DistributedCpuInfoMgrAI(self)
        self.cpuInfoMgr.generateOtpObject(self.district.getDoId(),
                                          OTPGlobals.UberZone)

        #self.securityMgr = DistributedSecurityMgrAI.DistributedSecurityMgrAI(self)
        #self.securityMgr.generateOtpObject(self.district.getDoId(), OTPGlobals.UberZone)

        #if ConfigVariableBool('want-code-redemption', 1).getValue():
        #    self.codeRedemptionManager = TTCodeRedemptionMgrAI(self)
        #    self.codeRedemptionManager.generateOtpObject(self.district.getDoId(), OTPGlobals.UberZone)

        self.randomSourceManager = NonRepeatableRandomSourceAI(self)
        # QuietZone so that the client doesn't get a generate
        self.randomSourceManager.generateOtpObject(self.district.getDoId(),
                                                   OTPGlobals.QuietZone)

        self.welcomeValleyManager = WelcomeValleyManagerAI.WelcomeValleyManagerAI(
            self)
        self.welcomeValleyManager.generateWithRequired(OTPGlobals.UberZone)

        # The trophy manager should be created before the building
        # managers.
        self.trophyMgr = DistributedTrophyMgrAI.DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(OTPGlobals.UberZone)

        # The bank manager handles banking transactions
        self.bankMgr = DistributedBankMgrAI.DistributedBankMgrAI(self)
        self.bankMgr.generateWithRequired(OTPGlobals.UberZone)

        # The Friend Manager
        self.friendManager = FriendManagerAI.FriendManagerAI(self)
        self.friendManager.generateWithRequired(OTPGlobals.UberZone)

        # The Delete Manager
        self.deleteManager = DeleteManagerAI.DeleteManagerAI(self)
        self.deleteManager.generateWithRequired(OTPGlobals.UberZone)

        # The Safe Zone manager
        self.safeZoneManager = SafeZoneManagerAI.SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(OTPGlobals.UberZone)

        # The Magic Word Manager
        magicWordString = ConfigVariableString('want-magic-words',
                                               '1').getValue()
        if magicWordString not in ('', '0', '#f'):
            self.magicWordManager = ToontownMagicWordManagerAI.ToontownMagicWordManagerAI(
                self)
            self.magicWordManager.generateWithRequired(OTPGlobals.UberZone)

        # The Tutorial manager
        self.tutorialManager = TutorialManagerAI.TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(OTPGlobals.UberZone)

        # The Catalog Manager
        self.catalogManager = CatalogManagerAI.CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(OTPGlobals.UberZone)

        # The Quest manager
        self.questManager = QuestManagerAI.QuestManagerAI(self)

        # The Fish manager
        self.fishManager = FishManagerAI.FishManagerAI(self)

        # The Cog Page manager
        self.cogPageManager = CogPageManagerAI.CogPageManagerAI(self)

        # The Suit Invasion Manager
        self.suitInvasionManager = SuitInvasionManagerAI.SuitInvasionManagerAI(
            self)

        # The Firework Manager: This object really only exists so we can
        # fire off fireworks with magic words. Normally this is a holiday
        # manager driven event and therefore the constructor needs a
        # holidayId. Pass in fourth of july as default.  To do: override
        # holiday ID with a magic word
        self.fireworkManager = FireworkManagerAI.FireworkManagerAI(
            self, NEWYEARS_FIREWORKS)

        # Create an NPC Dialogue manager that manages conversations
        # amongst a set of NPC's
        self.dialogueManager = NPCDialogueManagerAI.NPCDialogueManagerAI()

        # The News manager
        self.newsManager = NewsManagerAI.NewsManagerAI(self)
        self.newsManager.generateWithRequired(OTPGlobals.UberZone)

        # The Factory Manager
        self.factoryMgr = FactoryManagerAI.FactoryManagerAI(self)

        # The Mint Manager
        self.mintMgr = MintManagerAI.MintManagerAI(self)

        #the Law Office Manager
        self.lawMgr = LawOfficeManagerAI.LawOfficeManagerAI(self)

        # The Cog Country Club Manager
        self.countryClubMgr = CountryClubManagerAI.CountryClubManagerAI(self)

        if simbase.wantKarts:
            # The Race Manager
            self.raceMgr = RaceManagerAI.RaceManagerAI(self)

        self.cogSuitMgr = CogSuitManagerAI.CogSuitManagerAI(self)
        self.promotionMgr = PromotionManagerAI.PromotionManagerAI(self)

        # Housing
        self.estateMgr = EstateManagerAI.EstateManagerAI(self)
        self.estateMgr.generateWithRequired(OTPGlobals.UberZone)

        if simbase.wantPets:
            # Pets -- must be created after estateMgr
            self.petMgr = PetManagerAI.PetManagerAI(self)

        # Now create the neighborhood-specific objects.
        self.startupHood(TTHoodDataAI.TTHoodDataAI(self))
        self.startupHood(DDHoodDataAI.DDHoodDataAI(self))
        self.startupHood(MMHoodDataAI.MMHoodDataAI(self))
        self.startupHood(DGHoodDataAI.DGHoodDataAI(self))
        self.startupHood(BRHoodDataAI.BRHoodDataAI(self))
        self.startupHood(DLHoodDataAI.DLHoodDataAI(self))
        self.startupHood(CSHoodDataAI.CSHoodDataAI(self))
        self.startupHood(GSHoodDataAI.GSHoodDataAI(self))
        self.startupHood(OZHoodDataAI.OZHoodDataAI(self))
        self.startupHood(GZHoodDataAI.GZHoodDataAI(self))
        self.startupHood(CashbotHQDataAI.CashbotHQDataAI(self))
        self.startupHood(LawbotHQDataAI.LawbotHQDataAI(self))
        self.startupHood(BossbotHQDataAI.BossbotHQDataAI(self))

        # The Holiday Manager should be instantiated after the each
        # of the hoods and estateMgrAI are generated because Bingo Night
        # needs to reference the HoodDataAI and EstateMgrAI for pond
        # information. (JJT - 7/22/04)
        self.holidayManager = HolidayManagerAI.HolidayManagerAI(self)

        self.banManager = BanManagerAI.BanManagerAI()

        # Now that we've created all the suit planners, any one of
        # them can be used to fill the world with requests for suit
        # buildings.
        if self.suitPlanners:
            list(self.suitPlanners.values())[0].assignInitialSuitBuildings()

        # mark district as avaliable
        self.district.b_setAvailable(1)

        # Now that everything's created, start checking the leader
        # boards for correctness.  We only need to check every 30
        # seconds or so.
        self.__leaderboardFlush(None)
        taskMgr.doMethodLater(30,
                              self.__leaderboardFlush,
                              'leaderboardFlush',
                              appendTask=True)

    def __leaderboardFlush(self, task):
        messenger.send('leaderboardFlush')
        return Task.again

    def getWelcomeValleyCount(self):
        # avatars in Welcom Vally
        return self.welcomeValleyManager.getAvatarCount()

    def getHandleClassNames(self):
        # This function should return a tuple or list of string names
        # that represent distributed object classes for which we want
        # to make a special 'handle' class available.
        return ('DistributedToon', )

    def deleteObjects(self):
        # This function is where objects that manage DistributedObjectAI's
        # should be cleaned up. Since this is only called during a district
        # shutdown of some kind, it is not useful to delete the existing
        # DistributedObjectAI's, but rather to just make sure that they
        # are no longer referenced, and no new ones are created.
        for hood in self.hoods:
            hood.shutdown()
        self.hoods = []

        taskMgr.remove('leaderboardFlush')

    def queryToonMaxHp(self, toonId, callback, *args):
        """
        Looks up the maxHp of the given toon, and calls the given
        callback function, passing the maxHp as a parameter (or None
        if the toonId is unknown) followed by the given extra args.
        If the toon happens to be online and on the same shard, the
        callback is made immediately; otherwise, it will be made at
        some point in the future, after we have heard back from the
        database.
        """
        toon = self.doId2do.get(toonId, None)
        if toon != None:
            # The toon is online and on this shard.
            callback(toon.getMaxHp(), *args)
        else:
            # The toon is offline or on another shard; we have to
            # query the database.
            db = DatabaseObject.DatabaseObject(self, toonId)
            db.doneEvent = 'queryToonMaxHp'
            db.userCallback = callback
            db.userArgs = args
            db.getFields(['setMaxHp'])

    def __queryToonMaxHpResponse(self, db, retCode):
        maxHpDatagram = db.values.get('setMaxHp', None)
        if retCode == 0 and maxHpDatagram != None:
            di = PyDatagramIterator(maxHpDatagram)
            maxHp = di.getInt16()
        else:
            # The toonId is unknown or not a toon.
            maxHp = None

        db.userCallback(maxHp, *db.userArgs)

    def getMinDynamicZone(self):
        # Override this to return the minimum allowable value for a
        # dynamically-allocated zone id.
        return DynamicZonesBegin

    def getMaxDynamicZone(self):
        # Override this to return the maximum allowable value for a
        # dynamically-allocated zone id.

        # Note that each zone requires the use of the channel derived
        # by self.districtId + zoneId.  Thus, we cannot have any zones
        # greater than or equal to self.minChannel - self.districtId,
        # which is our first allocated doId.
        return min(self.minChannel - self.districtId, DynamicZonesEnd) - 1

    def findPartyHats(self, dnaGroup, zoneId, overrideDNAZone=0):
        """
        Recursively scans the given DNA tree for party hats.  These
        are defined as all the groups whose code includes the string
        "party_gate".  For each such group, creates a
        DistributedPartyGateAI.  Returns the list of distributed
        objects.
        """
        partyHats = []

        if ((isinstance(dnaGroup, DNAGroup)) and
                # If it is a DNAGroup, and the name has party_gate, count it
            (dnaGroup.getName().find('party_gate') >= 0)):
            # Here's a party hat!
            ph = DistributedPartyGateAI.DistributedPartyGateAI(self)
            ph.generateWithRequired(zoneId)
            partyHats.append(ph)
        else:
            # Now look in the children
            # Party hats cannot have other party hats in them,
            # so do not search the one we just found:
            # If we come across a visgroup, note the zoneId and then recurse
            if (isinstance(dnaGroup, DNAVisGroup) and not overrideDNAZone):
                # Make sure we get the real zone id, in case we are in welcome valley
                zoneId = ZoneUtil.getTrueZoneId(
                    int(dnaGroup.getName().split(':')[0]), zoneId)
            for i in range(dnaGroup.getNumChildren()):
                childPartyHats = self.findPartyHats(dnaGroup.at(i), zoneId,
                                                    overrideDNAZone)
                partyHats += childPartyHats

        return partyHats

    def findFishingPonds(self, dnaGroup, zoneId, area, overrideDNAZone=0):
        """
        Recursively scans the given DNA tree for fishing ponds.  These
        are defined as all the groups whose code includes the string
        "fishing_pond".  For each such group, creates a
        DistributedFishingPondAI.  Returns the list of distributed
        objects and a list of the DNAGroups so we can search them for
        spots and targets.
        """
        fishingPonds = []
        fishingPondGroups = []

        if ((isinstance(dnaGroup, DNAGroup)) and
                # If it is a DNAGroup, and the name starts with fishing_pond, count it
            (dnaGroup.getName().find('fishing_pond') >= 0)):
            # Here's a fishing pond!
            fishingPondGroups.append(dnaGroup)
            fp = DistributedFishingPondAI.DistributedFishingPondAI(self, area)
            fp.generateWithRequired(zoneId)
            fishingPonds.append(fp)
        else:
            # Now look in the children
            # Fishing ponds cannot have other ponds in them,
            # so do not search the one we just found:
            # If we come across a visgroup, note the zoneId and then recurse
            if (isinstance(dnaGroup, DNAVisGroup) and not overrideDNAZone):
                # Make sure we get the real zone id, in case we are in welcome valley
                zoneId = ZoneUtil.getTrueZoneId(
                    int(dnaGroup.getName().split(':')[0]), zoneId)
            for i in range(dnaGroup.getNumChildren()):
                childFishingPonds, childFishingPondGroups = self.findFishingPonds(
                    dnaGroup.at(i), zoneId, area, overrideDNAZone)
                fishingPonds += childFishingPonds
                fishingPondGroups += childFishingPondGroups
        return fishingPonds, fishingPondGroups

    def findFishingSpots(self, dnaPondGroup, distPond):
        """
        Scans the given DNAGroup pond for fishing spots.  These
        are defined as all the props whose code includes the string
        "fishing_spot".  Fishing spots should be the only thing under a pond
        node. For each such prop, creates a DistributedFishingSpotAI.
        Returns the list of distributed objects created.
        """
        fishingSpots = []
        # Search the children of the pond
        for i in range(dnaPondGroup.getNumChildren()):
            dnaGroup = dnaPondGroup.at(i)
            if ((isinstance(dnaGroup, DNAProp))
                    and (dnaGroup.getCode().find('fishing_spot') >= 0)):
                # Here's a fishing spot!
                pos = dnaGroup.getPos()
                hpr = dnaGroup.getHpr()
                fs = DistributedFishingSpotAI.DistributedFishingSpotAI(
                    self, distPond, pos[0], pos[1], pos[2], hpr[0], hpr[1],
                    hpr[2])
                fs.generateWithRequired(distPond.zoneId)
                fishingSpots.append(fs)
            else:
                self.notify.debug(
                    "Found dnaGroup that is not a fishing_spot under a pond group"
                )
        return fishingSpots

    def findRacingPads(self,
                       dnaGroup,
                       zoneId,
                       area,
                       overrideDNAZone=0,
                       type='racing_pad'):
        racingPads = []
        racingPadGroups = []
        if ((isinstance(dnaGroup, DNAGroup))
                and (dnaGroup.getName().find(type) >= 0)):
            racingPadGroups.append(dnaGroup)
            if (type == 'racing_pad'):
                nameInfo = dnaGroup.getName().split('_')
                #pdb.set_trace()
                #print("Name Info: ", nameInfo)
                #print("Race Info: ", raceInfo)
                racingPad = DistributedRacePadAI(self, area, nameInfo[3],
                                                 int(nameInfo[2]))
            else:
                racingPad = DistributedViewPadAI(self, area)
            racingPad.generateWithRequired(zoneId)
            racingPads.append(racingPad)
        else:
            if (isinstance(dnaGroup, DNAVisGroup) and not overrideDNAZone):
                zoneId = ZoneUtil.getTrueZoneId(
                    int(dnaGroup.getName().split(':')[0]), zoneId)
            for i in range(dnaGroup.getNumChildren()):
                childRacingPads, childRacingPadGroups = self.findRacingPads(
                    dnaGroup.at(i), zoneId, area, overrideDNAZone, type)
                racingPads += childRacingPads
                racingPadGroups += childRacingPadGroups
        return racingPads, racingPadGroups

    def getRacingPadList(self):
        list = []
        for do in list(self.doId2do.values()):
            if (isinstance(do, DistributedRacePadAI)):
                list.append(do.doId)
        return list

    def getViewPadList(self):
        list = []
        for do in list(self.doId2do.values()):
            if (isinstance(do, DistributedViewPadAI)):
                list.append(do.doId)
        return list

    def getStartingBlockDict(self):
        dict = {}
        for do in list(self.doId2do.values()):
            if (isinstance(do, DistributedStartingBlockAI)):
                if (isinstance(do.kartPad, DistributedRacePadAI)):
                    # Add the do to the dict
                    if (do.kartPad.doId in dict):
                        dict[do.kartPad.doId].append(do.doId)
                    else:
                        dict[do.kartPad.doId] = [do.doId]
        return dict

    def getViewingBlockDict(self):
        dict = {}
        for do in list(self.doId2do.values()):
            if (isinstance(do, DistributedStartingBlockAI)):
                if (isinstance(do.kartPad, DistributedViewPadAI)):
                    # Add the do to the dict
                    if (do.kartPad.doId in dict):
                        dict[do.kartPad.doId].append(do.doId)
                    else:
                        dict[do.kartPad.doId] = [do.doId]
        return dict

    def findStartingBlocks(self, dnaRacingPadGroup, distRacePad):
        """
        Comment goes here...
        """
        startingBlocks = []
        # Search the children of the racing pad
        for i in range(dnaRacingPadGroup.getNumChildren()):
            dnaGroup = dnaRacingPadGroup.at(i)

            # TODO - check if DNAProp instance
            if ((dnaGroup.getName().find('starting_block') >= 0)):
                padLocation = dnaGroup.getName().split('_')[2]
                pos = dnaGroup.getPos()
                hpr = dnaGroup.getHpr()

                if (isinstance(distRacePad, DistributedRacePadAI)):
                    sb = DistributedStartingBlockAI(self, distRacePad, pos[0],
                                                    pos[1], pos[2], hpr[0],
                                                    hpr[1], hpr[2],
                                                    int(padLocation))
                else:
                    sb = DistributedViewingBlockAI(self, distRacePad, pos[0],
                                                   pos[1], pos[2], hpr[0],
                                                   hpr[1], hpr[2],
                                                   int(padLocation))
                sb.generateWithRequired(distRacePad.zoneId)
                startingBlocks.append(sb)
            else:
                self.notify.debug(
                    "Found dnaGroup that is not a starting_block under a race pad group"
                )
        return startingBlocks

    def findLeaderBoards(self, dnaPool, zoneID):
        '''
        Find and return leader boards
        '''
        leaderBoards = []
        if (dnaPool.getName().find('leaderBoard') >= 0):
            #found a leader board
            pos = dnaPool.getPos()
            hpr = dnaPool.getHpr()

            lb = DistributedLeaderBoardAI(self, dnaPool.getName(), zoneID, [],
                                          pos, hpr)
            lb.generateWithRequired(zoneID)
            leaderBoards.append(lb)
        else:
            for i in range(dnaPool.getNumChildren()):
                result = self.findLeaderBoards(dnaPool.at(i), zoneID)
                if result:
                    leaderBoards += result

        return leaderBoards

    def loadDNAFileAI(self, dnaStore, dnaFile):
        return loadDNAFileAI(dnaStore, dnaFile, CSDefault)

    #AIGEOM
    def loadDNAFile(self, dnaStore, dnaFile, cs=CSDefault):
        """
        load everything, including geometry
        """
        return loadDNAFile(dnaStore, dnaFile, cs)

    def startupHood(self, hoodDataAI):
        hoodDataAI.startup()
        self.hoods.append(hoodDataAI)

    def shutdownHood(self, hoodDataAI):
        hoodDataAI.shutdown()
        self.hoods.remove(hoodDataAI)

    def getEstate(self, avId, zone, callback):
        """
        Asks the database to fill in details about this avatars
        estate.

        We make a request to the server and wait for its response.
        """
        context = self.__queryEstateContext
        self.__queryEstateContext += 1
        self.__queryEstateFuncMap[context] = callback
        self.__sendGetEstate(avId, context)

    def __sendGetEstate(self, avId, context):
        """
        Sends the query-object message to the server.  The return
        message will be handled by __handleGetEstateResp().
        See getEstate().
        """
        datagram = PyDatagram()
        datagram.addServerHeader(DBSERVER_ID, self.ourChannel,
                                 DBSERVER_GET_ESTATE)
        datagram.addUint32(context)
        # The avId we are querying.
        datagram.addUint32(avId)
        self.send(datagram)

    def __handleGetEstateResp(self, di):
        # Use the context to retrieve the callback parameter passed in
        # to getEstate().
        context = di.getUint32()
        callback = self.__queryEstateFuncMap.get(context)
        if callback == None:
            self.notify.warning("Got unexpected estate context: %s" %
                                (context))
            return
        del self.__queryEstateFuncMap[context]

        # return code = 0 if estate was returned without problems
        retCode = di.getUint8()

        estateVal = {}
        if (retCode == 0):
            estateId = di.getUint32()
            numFields = di.getUint16()

            for i in range(numFields):
                key = di.getString()
                #key = key[2:]
                #right why to do this???? ask Roger and/or Dave
                value = di.getString().encode("ISO-8859-1")
                found = di.getUint8()

                #print key;
                #print value;
                #print found;

                if found:
                    # create another datagram for this value
                    #vdg = PyDatagram(estateVal[i])
                    #vdgi = PyDatagramIterator(vdg)
                    # do something with this data
                    estateVal[key] = value

            numHouses = di.getUint16()
            self.notify.debug("numHouses = %s" % numHouses)
            houseId = [None] * numHouses
            for i in range(numHouses):
                houseId[i] = di.getUint32()
                self.notify.debug("houseId = %s" % houseId[i])

            numHouseKeys = di.getUint16()
            self.notify.debug("numHouseKeys = %s" % numHouseKeys)
            houseKey = [None] * numHouseKeys
            for i in range(numHouseKeys):
                houseKey[i] = di.getString()

            numHouseVal = di.getUint16()
            assert (numHouseVal == numHouseKeys)
            tempHouseVal = [None] * numHouseVal
            for i in range(numHouseVal):
                numHouses2 = di.getUint16()
                assert (numHouses2 == numHouses)
                tempHouseVal[i] = [None] * numHouses
                for j in range(numHouses):
                    tempHouseVal[i][j] = di.getString().encode("ISO-8859-1")
                    # do we need a check for "value found" here?

            #print houseKey
            #print tempHouseVal

            numHouseFound = di.getUint16()

            # keep track of which attributes are found
            foundVal = [None] * numHouses
            for i in range(numHouses):
                foundVal[i] = [None] * numHouseVal

            # create empty dictionaries for each house
            houseVal = []
            for i in range(numHouses):
                houseVal.append({})

            for i in range(numHouseVal):
                hvLen = di.getUint16()
                for j in range(numHouses):
                    found = di.getUint8()
                    if found:
                        houseVal[j][houseKey[i]] = tempHouseVal[i][j]
                        foundVal[j][i] = 1
                    else:
                        foundVal[j][i] = 0

            numPets = di.getUint16()
            petIds = []
            for i in range(numPets):
                petIds.append(di.getUint32())

            # create estate with houses
            # and call DistributedEstateAI's initEstateData func

            # call function originally passed to getEstate
            callback(estateId, estateVal, numHouses, houseId, houseVal, petIds,
                     estateVal)
        else:
            print("ret code != 0, something went wrong with estate creation")

    def getFirstBattle(self):
        # Return the first battle in the repository (for testing purposes)
        from toontown.battle import DistributedBattleBaseAI
        for dobj in list(self.doId2do.values()):
            if isinstance(dobj,
                          DistributedBattleBaseAI.DistributedBattleBaseAI):
                return dobj

    def handlePlayGame(self, msgType, di):
        # Handle Toontown specific message types before
        # calling the base class
        if msgType == DBSERVER_GET_ESTATE_RESP:
            self.__handleGetEstateResp(di)
        elif msgType == PARTY_MANAGER_UD_TO_ALL_AI:
            self.__handlePartyManagerUdToAllAi(di)
        elif msgType == IN_GAME_NEWS_MANAGER_UD_TO_ALL_AI:
            self.__handleInGameNewsManagerUdToAllAi(di)
        else:
            AIDistrict.handlePlayGame(self, msgType, di)

    def handleAvCatch(self, avId, zoneId, catch):
        """
        avId - ID of avatar to update
        zoneId - zoneId of the pond the catch was made in.
                This is used by the BingoManagerAI to
                determine which PBMgrAI needs to update
                the catch.
        catch - a fish tuple of (genus, species)
        returns: None

        This method instructs the BingoManagerAI to
        tell the appropriate PBMgrAI to update the
        catch of an avatar at the particular pond. This
        method is called in the FishManagerAI's
        RecordCatch method.
        """
        # Guard for publish
        if simbase.wantBingo:
            if self.bingoMgr:
                self.bingoMgr.setAvCatchForPondMgr(avId, zoneId, catch)

    def createPondBingoMgrAI(self, estate):
        """
        estate - the estate for which the PBMgrAI should
                be created.
        returns: None

        This method instructs the BingoManagerAI to
        create a new PBMgrAI for a newly generated
        estate.
        """
        # Guard for publish
        if simbase.wantBingo:
            if self.bingoMgr:
                self.notify.info(
                    'createPondBingoMgrAI: Creating a DPBMAI for Dynamic Estate'
                )
                self.bingoMgr.createPondBingoMgrAI(estate, 1)

    def __handlePartyManagerUdToAllAi(self, di):
        """Send all msgs of this type to the party manager on our district."""
        # we know the format is STATE_SERVER_OBJECT_UPDATE_FIELD
        # we just changed the msg type to PARTY_MANAGER_UD_TO_ALL_AI
        # so that it gets handled here
        # otherwise it just gets dropped on the floor
        do = self.partyManager
        if do:
            globalId = di.getUint32()
            if globalId != OtpDoGlobals.OTP_DO_ID_TOONTOWN_PARTY_MANAGER:
                self.notify.error(
                    '__handlePartyManagerUdToAllAi globalId=%d not equal to %d'
                    %
                    (globalId, OtpDoGlobals.OTP_DO_ID_TOONTOWN_PARTY_MANAGER))
            # Let the dclass finish the job
            do.dclass.receiveUpdate(do, di)

    def __handleInGameNewsManagerUdToAllAi(self, di):
        """Send all msgs of this type to the party manager on our district."""
        # we know the format is STATE_SERVER_OBJECT_UPDATE_FIELD
        # we just changed the msg type to PARTY_MANAGER_UD_TO_ALL_AI
        # so that it gets handled here
        # otherwise it just gets dropped on the floor
        do = self.inGameNewsMgr
        if do:
            globalId = di.getUint32()
            if globalId != OtpDoGlobals.OTP_DO_ID_TOONTOWN_IN_GAME_NEWS_MANAGER:
                self.notify.error(
                    '__handleInGameNewsManagerUdToAllAi  globalId=%d not equal to %d'
                    %
                    (globalId, OtpDoGlobals.OTP_DO_ID_TOONTOWN_PARTY_MANAGER))
            # Let the dclass finish the job
            do.dclass.receiveUpdate(do, di)

    def __handleWhitelistManagerUdToAllAi(self, di):
        """Send all msgs of this type to the party manager on our district."""
        # we know the format is STATE_SERVER_OBJECT_UPDATE_FIELD
        # we just changed the msg type to PARTY_MANAGER_UD_TO_ALL_AI
        # so that it gets handled here
        # otherwise it just gets dropped on the floor
        do = self.whitelistMgr
        if do:
            globalId = di.getUint32()
            if globalId != OtpDoGlobals.OTP_DO_ID_TOONTOWN_WHITELIST_MANAGER:
                self.notify.error(
                    '__handleWhitelistUdToAllAi  globalId=%d not equal to %d' %
                    (globalId, OtpDoGlobals.OTP_DO_ID_TOONTOWN_PARTY_MANAGER))
            # Let the dclass finish the job
            do.dclass.receiveUpdate(do, di)
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, serverId, districtName):
        ToontownInternalRepository.__init__(self, baseChannel, serverId, dcSuffix='AI')

        self.districtName = districtName

        self.zoneAllocator = UniqueIdAllocator(ToontownGlobals.DynamicZonesBegin,
                                               ToontownGlobals.DynamicZonesEnd)

        NPCToons.generateZone2NpcDict()
        
        self.use_libpandadna = simbase.config.GetBool('use-libpandadna', False)
        
        self.hoods = []
        self._dnaStoreMap = {}
        
        if self.use_libpandadna:
            self.__loader = DNALoader()
        
        self.zoneDataStore = AIZoneDataStore()

        self.useAllMinigames = self.config.GetBool('want-all-minigames', False)
        self.doLiveUpdates = True
        
        self.wantCogdominiums = self.config.GetBool('want-cogdo', False)
        self.wantParties = self.config.GetBool('want-parties', False)
        self.wantEmblems = self.config.GetBool('want-emblems', True)
        
        self.questManager = QuestManagerAI(self)
        self.promotionMgr = PromotionManagerAI(self)
        self.cogPageManager = CogPageManagerAI(self)
        self.cogSuitMgr = CogSuitManagerAI(self)

        self.trophyMgr = DistributedTrophyMgrAI(self)
        
        self.fishManager = FishManagerAI()
		
        self.dnaStoreMap = {}
        
        self.mintMgr = MintManagerAI.MintManagerAI(self)
        self.factoryMgr = FactoryManagerAI.FactoryManagerAI(self)
        self.lawMgr = LawOfficeManagerAI.LawOfficeManagerAI(self)
        self.countryClubMgr = CountryClubManagerAI.CountryClubManagerAI(self)
        
        self.buildingManagers = {}
        self.suitPlanners = {}
        
        self.wantMegaInvasions = str(self.ourChannel // 1000000) in self.config.GetString('mega-invasion-shards', '402 403').split()            

    def getTrackClsends(self):
        return False
        
    def handleConnected(self):
        self.districtId = self.allocateChannel()
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(simbase.air.districtId, self.getGameDoId(), 2)

        dg = PyDatagram()
        dg.addServerHeader(simbase.air.districtId, simbase.air.ourChannel, STATESERVER_OBJECT_SET_AI)
        dg.addChannel(simbase.air.ourChannel)
        simbase.air.send(dg)

        self.createGlobals()
        self.createZones()

    def __ready(self):
        dg = PyDatagram()
        dg.addServerHeader(self.districtStats.doId, self.ourChannel, STATESERVER_OBJECT_DELETE_RAM)
        dg.addUint32(self.districtStats.doId)
        self.addPostRemove(dg)
        
        self.apiMgr = self.generateGlobalObject(100001, "ShardAPIManager")
        self.apiMgr.start()
        self.apiMgr.d_setShardData()
        
        self.banMgr = self.generateGlobalObject(100002, "BanManager")
        
        self.trophyMgr.updateToonData()
        
    def gotUberdogAPISync(self):
        if not self.distributedDistrict.getAvailable():
            self.notify.info("Got UD API sync, opening shard...")
            messenger.send("startShardActivity")
            self.distributedDistrict.b_setAvailable(1)

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(self.districtStats.getAvatarCount() - 1)

    def allocateZone(self):
        return self.zoneAllocator.allocate()

    def deallocateZone(self, zone):
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def createGlobals(self):
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(), self.getGameDoId(), 2)
		
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)

        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)

        self.holidayManager = HolidayManagerAI(self)

        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)

        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(2)
		
        self.petMgr = PetManagerAI(self)

        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)

        self.partyManager = DistributedPartyManagerAI(self)
        self.partyManager.generateWithRequired(2)
		
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)
		
        self.globalPartyMgr = self.generateGlobalObject(OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        self.estateManager = EstateManagerAI(self)
        self.estateManager.generateWithRequired(2)
        
        self.suitInvasionManager = DistributedSuitInvasionManagerAI(self)
        self.suitInvasionManager.generateWithRequired(2)

        self.bankMgr = DistributedBankMgrAI(self)
        self.bankMgr.generateWithRequired(2)
        
        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(2)
        
        self.huntId = 0
        
        if self.holidayManager.isHolidayRunning(ToontownGlobals.TRICK_OR_TREAT):
            import DistributedTrickOrTreatTargetAI
            self.trickOrTreatMgr = DistributedTrickOrTreatTargetAI.DistributedTrickOrTreatTargetAI(self)
            self.trickOrTreatMgr.generateWithRequired(2)
            
        self.handleBlackCatMgr()
        self.handleBloodsuckerInvasion()
        self.handleSkelCogWeekInvasion()
        
        if config.GetBool('want-resistance-emote', True):
            self.resistanceMgr = DistributedResistanceEmoteMgrAI.DistributedResistanceEmoteMgrAI(self)
            self.resistanceMgr.generateWithRequired(9720)

        if config.GetBool('want-polar-effect', True):
            self.polarMgr = DistributedPolarPlaceEffectMgrAI.DistributedPolarPlaceEffectMgrAI(self)
            self.polarMgr.generateWithRequired(3821)
            
    def handleBlackCatMgr(self):
        today = datetime.datetime.now()
        start = datetime.datetime(today.year, 10, 31)
        end = datetime.datetime(today.year, 11, 3)
        
        def createBlackCatMgr(task=None):
            import DistributedBlackCatMgrAI
            self.blackCatMgr = DistributedBlackCatMgrAI.DistributedBlackCatMgrAI(self)
            self.blackCatMgr.generateWithRequired(2513)
            if not self.config.GetBool('force-black-cat-mgr', False):
                self.blackCatMgr.expire((end - today).total_seconds())
            return Task.done
        
        if start <= today < end or self.config.GetBool('force-black-cat-mgr', False):
            createBlackCatMgr(None)
            
        elif start >= today:
            taskMgr.doMethodLater((start - today).total_seconds(), createBlackCatMgr, 'air-createBlackCatMgr')
            
    def handleBloodsuckerInvasion(self):
        if not self.wantMegaInvasions:
            return
            
        today = datetime.datetime.now()
        start = datetime.datetime(today.year, 10, 31)
        end = datetime.datetime(today.year, 11, 3)
        
        if start <= today < end:
            self.startMegaInvasion(9, end=end)
            
        elif start > today:
            taskMgr.doMethodLater((start - today).total_seconds(), self.startMegaInvasion, 'air-mega-invasion-9', extraArgs=[9, False, end])
            
    def handleSkelCogWeekInvasion(self):
        if not self.wantMegaInvasions:
            return
            
        today = datetime.datetime.now()
        start = datetime.datetime(2014, 11, 10)
        end = datetime.datetime(2014, 11, 17)
        
        if start <= today < end:
            self.startMegaInvasion(-1, skel=True, end=end)
            
        elif start > today:
            taskMgr.doMethodLater((start - today).total_seconds(), self.startMegaInvasion, 'air-mega-invasion-skel', extraArgs=[-1, True, end])
            
    def startMegaInvasion(self, suitIndex, skel=False, end=None):
        if suitIndex >= 0:
            suitName = SuitDNA.suitHeadTypes[suitIndex]
            
        else:
            suitName = None
            
        if self.suitInvasionManager.hasInvading():
            if self.suitInvasionManager.isMega():
                return Task.done
                
            self.suitInvasionManager.abort()
            
        self.suitInvasionManager.startInvasion(suitName, skel, mega=True)
        if end:
            def doAbort(task):
                self.suitInvasionManager.abort()
                return task.done

            today = datetime.datetime.now()
            taskMgr.doMethodLater((end - today).total_seconds(), doAbort, 'air-abort-mega-invasion')
        
    def getStorage(self, zone):
        s = self._dnaStoreMap.get(zone)
        if not s:
            s = DNAStorage()
            self.loadDNAFileAI(s, self.genDNAFileName(zone))
            self._dnaStoreMap[zone] = s
        
        return s

    def createZones(self):
        self.zoneTable = {
                          1000: ((1000, 1, 0), (1100, 1, 1), (1200, 1, 1), (1300, 1, 1)),
                          2000: ((2000, 1, 0), (2100, 1, 1), (2200, 1, 1), (2300, 1, 1)),
                          3000: ((3000, 1, 0), (3100, 1, 1), (3200, 1, 1), (3300, 1, 1)),
                          4000: ((4000, 1, 0), (4100, 1, 1), (4200, 1, 1), (4300, 1, 1)),
                          5000: ((5000, 1, 0), (5100, 1, 1), (5200, 1, 1), (5300, 1, 1)),
                          9000: ((9000, 1, 0), (9100, 1, 1), (9200, 1, 1)),
                          
                          6000: (),
                          7000: ((7000, 1, 0), (7100, 1, 1)), # XXX to do: planner at 7100
                          8000: ((8000, 1, 0),),
                          10000: (),
                          11000: (),
                          12000: (),
                          13000: (),
                          17000: (),
                         }
        
        self.__nextHood(0)
                         
    def __nextHood(self, hoodIndex):
        if hoodIndex >= len(hoods):
            self.__ready()
            return Task.done
                         
        self.hoods.append(hoods[hoodIndex](self))
        taskMgr.doMethodLater(0, ToontownAIRepository.__nextHood, 'nextHood', [self, hoodIndex + 1])
        return Task.done

    def genDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]

        return 'phase_%s/dna/%s_%s.dna' % (phase, hood, zoneId)

    def loadDNAFileAI(self, dnastore, filename):
        if self.use_libpandadna:
            f = Filename('../resources/' + str(filename))
            f.setExtension('pdna')
            x = self.__loader.loadDNAFileAI(dnastore, f)
            
        else:
            f = Filename(filename)
            f = Filename('etc/dnabkp/' + f.getBasename())
            x = loadDNAFileAI(dnastore, str(f))
        
        return x

    def sendSetZone(self, obj, zoneId):
        obj.b_setLocation(obj.parentId, zoneId)
        
    def getDisconnectReason(self, avId):
        return self.timeManager.disconnectReasonMap.get(avId, 1) # Default: user closed window
        
    def killToon(self, avId, force = True):
        """
        Kills given toon if within this shard.
        If force is False, then checks getDisconnectReason.
        """
        toon = self.doId2do.get(avId)
        
        if not toon:
            self.notify.warning("Tried to kill non-existing toon %s" % avId)
            return False
            
        if not force:
            if self.getDisconnectReason(avId) == 3: # Python Error
                return False
            
        toon.b_setHp(0)
        
        inventory = toon.inventory
        inventory.zeroInv()
        toon.b_setInventory(inventory.makeNetString())
        
        self.notify.info("Killed toon %s, RIP!" % avId)
        return True
        
    def handleObjExit(self, di):
        doId = di.getUint32()

        if doId not in self.doId2do:
            self.notify.warning('Received AI exit for unknown object %d' % (doId))
            return

        do = self.doId2do[doId]
        do.sendDeleteEvent()
        self.removeDOFromTables(do)
        do.delete()
Beispiel #11
0
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, serverId, districtName):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            serverId,
                                            dcSuffix='AI')

        self.dnaSpawner = DNASpawnerAI(self)

        self.districtName = districtName

        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)
        self.zoneId2owner = {}

        NPCToons.generateZone2NpcDict()

        self.hoods = []
        self.zoneDataStore = AIZoneDataStore()

        self.useAllMinigames = self.config.GetBool('want-all-minigames', False)
        self.doLiveUpdates = self.config.GetBool('want-live-updates', True)
        self.baseXpMultiplier = self.config.GetFloat('base-xp-multiplier', 1.0)
        self.wantHalloween = self.config.GetBool('want-halloween', False)
        self.wantChristmas = self.config.GetBool('want-christmas', False)
        self.holidayManager = HolidayManagerAI(self)
        if config.GetBool('want-pets', True):
            self.PetManager = PetManagerAI(self)
        self.fishManager = FishManagerAI()
        self.questManager = QuestManagerAI(self)
        self.cogPageManager = CogPageManagerAI()
        self.factoryMgr = FactoryManagerAI(self)
        self.mintMgr = MintManagerAI(self)
        self.lawOfficeMgr = LawOfficeManagerAI(self)
        self.countryClubMgr = CountryClubManagerAI(self)
        self.promotionMgr = PromotionManagerAI(self)
        self.cogSuitMgr = CogSuitManagerAI(self)
        self.suitInvasionManager = SuitInvasionManagerAI(self)

        self.statusSender = ShardStatusSender(self)

        self.dnaStoreMap = {}

        self.buildingManagers = {}
        self.suitPlanners = {}

    def getTrackClsends(self):
        return False

    def handleConnected(self):
        self.notify.info('Yarn. Waking up (This may take a while!).')
        ToontownInternalRepository.handleConnected(self)
        self.districtId = self.allocateChannel()
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(
            self.districtId, self.getGameDoId(), 2)

        # Claim ownership of that district...
        dg = PyDatagram()
        dg.addServerHeader(self.districtId, self.ourChannel,
                           STATESERVER_OBJECT_SET_AI)
        dg.addChannel(self.ourChannel)
        self.send(dg)

        self.notify.info('Creating Global Managers')
        self.createGlobals()
        self.notify.info('Creating Toontown')
        self.createZones()

        self.statusSender.start()

        self.distributedDistrict.b_setAvailable(1)
        self.notify.info('District is now ready.')

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)
        self.statusSender.sendStatus()

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)
        self.statusSender.sendStatus()

    def allocateZone(self, owner=None):
        zoneId = self.zoneAllocator.allocate()
        if owner:
            self.zoneId2owner[zoneId] = owner
        return zoneId

    def deallocateZone(self, zone):
        if self.zoneId2owner.get(zone):
            del self.zoneId2owner[zone]
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def createGlobals(self):
        """
        Create "global" objects, e.g. TimeManager et al.
        """
        self.notify.info('Creating District Stats')
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
                                                     self.getGameDoId(), 3)
        self.notify.info('Creating Time Manager')
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)

        self.notify.info('Creating News Manager')
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)

        if config.GetBool('want-mw-manager', True):
            self.notify.info('Creating Magic Words Manager')
            self.magicWordManager = MagicWordManagerAI(self)
            self.magicWordManager.generateWithRequired(2)

        if config.GetBool('want-friends-manager', True):
            self.notify.info('Creating Friends Manager')
            self.friendManager = FriendManagerAI(self)
            self.friendManager.generateWithRequired(2)

        if config.GetBool('want-parties', True):
            self.notify.info('Creating Parties Manager')
            self.partyManager = DistributedPartyManagerAI(self)
            self.partyManager.generateWithRequired(2)

            # Setup our view of the global party manager ud
            self.globalPartyMgr = self.generateGlobalObject(
                OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        if config.GetBool('want-estates-manager', True):
            self.notify.info('Creating Estates')
            self.estateManager = EstateManagerAI(self)
            self.estateManager.generateWithRequired(2)

        self.notify.info('Creating TrophyMgr')
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(2)

        self.notify.info('Creating Toontorial Manager')
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)

        self.notify.info('Creating Catalog Manager')
        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(2)
        if config.GetBool('want-pets', True):
            self.notify.info('Creating Pets Manager')
            self.PetManager = PetManagerAI(self)

        self.notify.info('Creating Code Redemption Manager')
        self.codeRedemptionManager = TTCodeRedemptionMgrAI(self)
        self.codeRedemptionManager.generateWithRequired(2)

    def createZones(self):
        """
        Spawn safezone objects, streets, doors, NPCs, etc.
        """
        start = time.clock()

        def clearQueue():
            '''So the TCP window doesn't fill up and we get the axe'''
            while self.readerPollOnce():
                pass

        self.notify.info('Creating TTC (Toontown Central) ')
        self.hoods.append(TTHoodAI.TTHoodAI(self))
        clearQueue()
        self.notify.info('Creating DD (Donalds Dock)')
        self.hoods.append(DDHoodAI.DDHoodAI(self))
        clearQueue()
        self.notify.info('Creating DG (Daisy Gardens) ')
        self.hoods.append(DGHoodAI.DGHoodAI(self))
        clearQueue()
        self.notify.info('Creating BR (The Brrrgh) ')
        self.hoods.append(BRHoodAI.BRHoodAI(self))
        clearQueue()
        self.notify.info('Creating MML (Minnie Melody Land) ')
        self.hoods.append(MMHoodAI.MMHoodAI(self))
        clearQueue()
        self.notify.info('Creating DDL (Donalds Dream Land) ')
        self.hoods.append(DLHoodAI.DLHoodAI(self))
        clearQueue()
        self.notify.info('Creating GS (SpeedWay) ')
        self.hoods.append(GSHoodAI.GSHoodAI(self))
        clearQueue()
        self.notify.info('Creating OZ (Outdoor Zone)')
        self.hoods.append(OZHoodAI.OZHoodAI(self))
        clearQueue()
        self.notify.info('Creating GZ (Golf Zone) ')
        self.hoods.append(GZHoodAI.GZHoodAI(self))
        clearQueue()
        self.notify.info('Creating TF (Toonfest) ')
        self.hoods.append(TFHoodAI.TFHoodAI(self))
        clearQueue()

        if config.GetBool('want-sbhq', True):
            self.notify.info('Creating SBHQ (Sellbot HQ) ')
            self.hoods.append(SellbotHQAI.SellbotHQAI(self))
            clearQueue()

        if config.GetBool('want-cbhq', True):
            self.notify.info('Creating CBHQ (Cashbot HQ) ')
            self.hoods.append(CashbotHQAI.CashbotHQAI(self))
            clearQueue()

        if config.GetBool('want-lbhq', True):
            self.notify.info('Creating LBHQ (Lawbot HQ) ')
            self.hoods.append(LawbotHQAI.LawbotHQAI(self))
            clearQueue()

        if config.GetBool('want-bbhq', True):
            self.notify.info('Creating BBHQ (Bossbot HQ) ')
            self.hoods.append(BossbotHQAI.BossbotHQAI(self))
            clearQueue()

        for sp in self.suitPlanners.values():
            sp.assignInitialSuitBuildings()

    def genDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]

        return 'phase_%s/dna/%s_%s.xml' % (phase, hood, zoneId)

    def loadDNA(self, filename):
        with open('/' + filename) as f:
            tree = DNAParser.parse(f)

        return tree
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, serverId, districtName, holidayPasscode,
                 serverDescription, miniserverId):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            serverId,
                                            dcSuffix='AI')
        self.districtName = districtName
        self.holidayPasscode = holidayPasscode
        self.holidayValue = 0
        self.serverDescription = serverDescription
        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)
        self.zoneId2owner = {}
        NPCToons.generateZone2NpcDict()
        self.zoneTable = {}
        self.hoodArray = []
        self.hoods = []
        self._dnaStoreMap = {}
        self.zoneDataStore = AIZoneDataStore()
        self.useAllMinigames = self.config.GetBool('want-all-minigames', False)
        self.doLiveUpdates = self.config.GetBool('want-live-updates', True)
        self.reachedPlayerLimit = False
        self.fishManager = FishManagerAI()
        self.questManager = QuestManagerAI(self)
        self.cogPageManager = CogPageManagerAI()
        self.factoryMgr = FactoryManagerAI(self)
        self.mintMgr = MintManagerAI(self)
        self.lawOfficeMgr = LawOfficeManagerAI(self)
        self.countryClubMgr = CountryClubManagerAI(self)
        self.promotionMgr = PromotionManagerAI(self)
        self.cogSuitMgr = CogSuitManagerAI(self)
        self.wantCogdominiums = self.config.GetBool('want-cogdominums', False)
        self.buildingManagers = {}
        self.suitPlanners = {}
        self.inEpisode = False
        self.cutsceneActivated = False
        self.currentEpisode = None
        self.wantMiniServer = config.GetBool('want-mini-server', False)
        if not self.wantMiniServer:
            self.wantPrologue = config.GetBool('want-prologue', False)
        else:
            self.wantPrologue = False
        return

    def getTrackClsends(self):
        return False

    def handleConnected(self):
        ToontownInternalRepository.handleConnected(self)
        if self.holidayPasscode != '':
            self.initServerHoliday()
        self.districtId = self.allocateChannel()
        self.notify.info('Creating district (%d)...' % self.districtId)
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.setDescription(self.serverDescription)
        self.distributedDistrict.setHolidayPasscode(self.holidayValue)
        self.distributedDistrict.generateWithRequiredAndId(
            self.districtId, self.getGameDoId(), OTP_ZONE_ID_MANAGEMENT)
        self.notify.info('Claiming ownership of district (%d)...' %
                         self.districtId)
        dg = PyDatagram()
        dg.addServerHeader(self.districtId, self.ourChannel,
                           STATESERVER_OBJECT_SET_AI)
        dg.addChannel(self.ourChannel)
        self.send(dg)
        self.notify.info('Creating global objects...')
        self.createGlobals()
        self.notify.info('Creating zones (Playgrounds and Cog HQs)...')
        self.createZones()

    def districtReady(self):
        for sp in self.suitPlanners.values():
            sp.assignInitialSuitBuildings()

        self.notify.info('Making district available...')
        self.distributedDistrict.b_setAvailable(1)
        self.notify.info('District is now ready. Have fun in Toontown!')
        self.sendPing()
        taskMgr.doMethodLater(30, self.sendPing, 'pingWebsite')

    def HTTPReq(self, url, data=None):
        if type(data) == dict:
            data = urllib.urlencode(data)
            data = data.encode('utf-8')
        context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64)'}
        request = urllib2.Request(url, data, headers=headers)
        response = urllib2.urlopen(request, context=context)
        data = json.loads(response.read().decode())
        return data

    def sendPing(self, task=None):
        if self.wantMiniServer:
            serverId = config.GetString('server-id', '')
            if serverId != '':
                gameMode = 'Elections' if config.GetBool(
                    'want-doomsday', False) else 'Normal'
                try:
                    self.sendPingToAPI(
                        serverId,
                        name=self.districtName,
                        desc=self.serverDescription,
                        population=self.districtStats.getAvatarCount(),
                        mode=gameMode)
                except:
                    self.notify.info('Could not ping the website! ')

                return Task.again
        return Task.done

    def getColumns(self):
        data = self.HTTPReq('https://ttoffline.com/api/miniservers/columns')
        return data

    def sendPingToAPI(self, serverId, **kwargs):
        columns = self.getColumns()
        data = {'uniqueId': serverId}
        for arg in kwargs.keys():
            if arg in columns:
                data['%s' % arg] = kwargs[arg]
                continue
            self.notify.info('%s is not a valid argument!' % arg)

        resp = self.HTTPReq('https://ttoffline.com/api/miniservers/ping',
                            data=data)
        if not resp['success']:
            self.notify.info('Could not ping the website! (Message: %s)' %
                             resp['message'])

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)
        self.avatarCountCheck()
        self.sendPing()

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)
        self.avatarCountCheck()
        self.sendPing()

    def avatarCountCheck(self):
        if not self.reachedPlayerLimit and self.districtStats.getAvatarCount(
        ) >= config.GetInt('miniserver-player-limit',
                           ToontownGlobals.DefaultMiniserverLimit):
            self.reachedPlayerLimit = True
            self.notify.warning(
                'Reached player limit! Making district unavailable...')
            self.distributedDistrict.b_setAvailable(0)
            self.notify.warning(
                'District is now unavailable. Incoming connections will be rejected.'
            )
        if self.reachedPlayerLimit and self.districtStats.getAvatarCount(
        ) < config.GetInt('miniserver-player-limit',
                          ToontownGlobals.DefaultMiniserverLimit):
            self.reachedPlayerLimit = False
            self.notify.info(
                'Player count dropped! Making district available...')
            self.distributedDistrict.b_setAvailable(1)
            self.notify.info(
                'District is now available. Incoming connections will be accepted.'
            )

    def allocateZone(self, owner=None):
        zoneId = self.zoneAllocator.allocate()
        if owner:
            self.zoneId2owner[zoneId] = owner
        return zoneId

    def deallocateZone(self, zone):
        if self.zoneId2owner.get(zone):
            del self.zoneId2owner[zone]
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def getAvatarZoneChangeEvent(self, avId):
        return 'DOChangeZone-%d' % avId

    def avIsInEpisode(self):
        return self.currentEpisode is not None

    def createGlobals(self):
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
                                                     self.getGameDoId(),
                                                     OTP_ZONE_ID_DISTRICTS)
        self.notify.info('Created district stats AI (%d).' %
                         self.districtStats.doId)
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.suitInvasionManager = SuitInvasionManagerAI(self)
        self.holidayManager = HolidayManagerAI(self)
        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.sillyMeterMgr = DistributedSillyMeterMgrAI(self)
        self.sillyMeterMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        if config.GetBool('want-code-redemption', True):
            self.codeRedemptionMgr = TTCodeRedemptionMgrAI(self)
            self.codeRedemptionMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        if config.GetBool('want-parties', True):
            self.partyManager = DistributedPartyManagerAI(self)
            self.partyManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
            self.globalPartyMgr = self.generateGlobalObject(
                OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')
        if config.GetBool('want-estates', True):
            self.estateManager = EstateManagerAI(self)
            self.estateManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        if simbase.wantPets:
            self.petMgr = PetManagerAI(self)
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        if config.GetBool('want-event-manager', False):
            self.eventManager = DistributedEventManagerAI(self)
            self.eventManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        if config.GetBool('want-news-page', False):
            self.inGameNewsMgr = DistributedInGameNewsMgrAI(self)
            self.inGameNewsMgr.setLatestIssueStr('2013-08-22 23:49:46')
            self.inGameNewsMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.banManager = self.generateGlobalObject(OTP_DO_ID_BAN_MANAGER,
                                                    'BanManager')

    def createZones(self):
        if config.GetBool('want-playgrounds', True):
            if config.GetBool('want-toontown-central', True):
                self.hoodArray.append(TTHoodDataAI.TTHoodDataAI)
                self.zoneTable[2000] = ((2000, 1, 0), (2100, 1, 1),
                                        (2200, 1, 1), (2300, 1, 1))
            if config.GetBool('want-donalds-dock', True):
                self.hoodArray.append(DDHoodDataAI.DDHoodDataAI)
                self.zoneTable[1000] = ((1000, 1, 0), (1100, 1, 1),
                                        (1200, 1, 1), (1300, 1, 1))
            if config.GetBool('want-daisy-gardens', True):
                self.hoodArray.append(DGHoodDataAI.DGHoodDataAI)
                self.zoneTable[5000] = ((5000, 1, 0), (5100, 1, 1),
                                        (5200, 1, 1), (5300, 1, 1))
            if config.GetBool('want-minnies-melodyland', True):
                self.hoodArray.append(MMHoodDataAI.MMHoodDataAI)
                self.zoneTable[4000] = ((4000, 1, 0), (4100, 1, 1),
                                        (4200, 1, 1), (4300, 1, 1))
            if config.GetBool('want-the-brrrgh', True):
                self.hoodArray.append(BRHoodDataAI.BRHoodDataAI)
                self.zoneTable[3000] = ((3000, 1, 0), (3100, 1, 1),
                                        (3200, 1, 1), (3300, 1, 1))
            if config.GetBool('want-donalds-dreamland', True):
                self.hoodArray.append(DLHoodDataAI.DLHoodDataAI)
                self.zoneTable[9000] = ((9000, 1, 0), (9100, 1, 1), (9200, 1,
                                                                     1))
            if config.GetBool('want-goofy-speedway', True):
                self.hoodArray.append(GSHoodDataAI.GSHoodDataAI)
                self.zoneTable[8000] = ((8000, 1, 0), )
            if config.GetBool('want-acorn-acres', True):
                self.hoodArray.append(OZHoodDataAI.OZHoodDataAI)
                self.zoneTable[6000] = ((6000, 1, 0), )
            if config.GetBool('want-toonfest', True):
                self.hoodArray.append(TFHoodDataAI.TFHoodDataAI)
                self.zoneTable[ToontownGlobals.ToonFest] = ((
                    ToontownGlobals.ToonFest, 1, 0), )
            if config.GetBool('want-minigolf', True):
                self.hoodArray.append(GZHoodDataAI.GZHoodDataAI)
                self.zoneTable[17000] = ((17000, 1, 0), )
            if not self.wantMiniServer:
                if config.GetBool('want-scrooge-bank', True):
                    self.hoodArray.append(SBHoodDataAI.SBHoodDataAI)
                    self.zoneTable[1002000] = ()
                if config.GetBool('want-old-daisy-gardens', True):
                    self.hoodArray.append(ODGHoodDataAI.ODGHoodDataAI)
                    self.zoneTable[21000] = ((21000, 1, 0), (21300, 1, 1))
        if config.GetBool('want-cog-headquarters', True):
            if config.GetBool('want-sellbot-hq', True):
                self.hoodArray.append(CSHoodDataAI.CSHoodDataAI)
                self.zoneTable[11000] = ((11000, 1, 0), (11200, 1, 0))
            if config.GetBool('want-cashbot-hq', True):
                self.hoodArray.append(CashbotHQDataAI.CashbotHQDataAI)
                self.zoneTable[12000] = ((12000, 1, 0), )
            if config.GetBool('want-lawbot-hq', True):
                self.hoodArray.append(LawbotHQDataAI.LawbotHQDataAI)
                self.zoneTable[13000] = ((13000, 1, 0), )
            if config.GetBool('want-bossbot-hq', True):
                self.hoodArray.append(BossbotHQDataAI.BossbotHQDataAI)
                self.zoneTable[10000] = ((10000, 0, 0), (10900, 1, 0))
        self.__nextHood(0)

    def __nextHood(self, hoodIndex):
        if hoodIndex >= len(self.hoodArray):
            self.districtReady()
            return Task.done
        self.hoods.append(self.hoodArray[hoodIndex](self))
        taskMgr.doMethodLater(0, ToontownAIRepository.__nextHood, 'nextHood',
                              [self, hoodIndex + 1])
        return Task.done

    def dnaStoreMap(self, zone):
        dnaStore = self._dnaStoreMap.get(zone)
        if not dnaStore:
            dnaStore = DNAStorage()
            self.loadDNAFileAI(dnaStore, self.genDNAFileName(zone))
            self._dnaStoreMap[zone] = dnaStore
        return dnaStore

    def genDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]
        return 'phase_%s/dna/%s_%s.jazz' % (phase, hood, zoneId)

    def loadDNAFileAI(self, dnaStore, filename):
        return loadDNAFileAI(dnaStore, filename)

    def initServerHoliday(self):
        self.notify.info('Holiday Passcode detected. Initalizing Holiday...')
        holidayPasscodes = [
            'holidayHW2017811154', 'holidayHW2017421808',
            'holidayHW2017475201', 'holidayHW2017669818',
            'holidayHW2017001496', 'holidayHW2017139447'
        ]
        for passcode in holidayPasscodes:
            if passcode == self.holidayPasscode:
                self.holidayValue = holidayPasscodes.index(passcode) + 1

        if self.holidayPasscode in holidayPasscodes:
            self.notify.info(
                "Holdiay Passcode '%s' is active on this District!" %
                self.holidayPasscode)
        else:
            self.notify.info("Holdiay Passcode '%s' is not a valid Passcode!" %
                             self.holidayPasscode)
Beispiel #13
0
class ToontownAIRepository(ToontownInternalRepository):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'ToontownAIRepository')

    def __init__(self, baseChannel, serverId, expMultiplier, meritMultiplier,
                 doodleMultiplier, defaultMaxToon, defaultZone, districtName,
                 districtLimit, districtDescription, districtWebsiteId,
                 eventId, defaultAccessLevel):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            serverId,
                                            dcSuffix='AI')
        self.expMultiplier = expMultiplier
        self.meritMultiplier = meritMultiplier
        self.doodleMultiplier = doodleMultiplier
        self.defaultMaxToon = defaultMaxToon
        self.defaultZone = defaultZone
        self.districtName = districtName
        self.districtLimit = districtLimit
        if self.districtLimit < ToontownGlobals.MIN_POP:
            self.districtLimit = ToontownGlobals.MIN_POP
        elif self.districtLimit > ToontownGlobals.HIGH_POP:
            self.districtLimit = ToontownGlobals.HIGH_POP
        self.districtDescription = districtDescription
        self.districtWebsiteId = districtWebsiteId
        self.eventId = eventId
        self.defaultAccessLevel = defaultAccessLevel
        self.doLiveUpdates = self.config.GetBool('want-live-updates', True)
        self.wantCogdominiums = self.config.GetBool('want-cogdominiums', True)
        self.wantEmblems = self.config.GetBool('want-emblems', True)
        self.useAllMinigames = self.config.GetBool('want-all-minigames', True)
        self.wantEmblems = self.config.GetBool('want-emblems', True)
        self.districtId = None
        self.district = None
        self.districtStats = None
        self.districtFull = False
        self.timeManager = None
        self.newsManager = None
        self.holidayManager = None
        self.welcomeValleyManager = None
        self.catalogManager = None
        self.zoneDataStore = None
        self.inGameNewsMgr = None
        self.trophyMgr = None
        self.petMgr = None
        self.dnaStoreMap = {}
        self.dnaDataMap = {}
        self.zoneTable = {}
        self.hoods = []
        self.buildingManagers = {}
        self.suitPlanners = {}
        self.suitInvasionManager = None
        self.zoneAllocator = None
        self.zoneId2owner = {}
        self.questManager = None
        self.cogPageManager = None
        self.fishManager = None
        self.factoryMgr = None
        self.mintMgr = None
        self.lawMgr = None
        self.countryClubMgr = None
        self.promotionMgr = None
        self.cogSuitMgr = None
        self.partyManager = None
        self.safeZoneManager = None
        self.raceMgr = None
        self.polarPlaceEffectMgr = None
        self.resistanceEmoteMgr = None
        self.tutorialManager = None
        self.friendManager = None
        self.chatManager = None
        self.toontownTimeManager = None
        self.estateMgr = None
        self.magicWordManager = None
        self.deliveryManager = None
        self.cogSuitMessageSent = False
        self.propGenerators = {}
        self.propGeneratorsLocked = False
        self.moddingManager = None
        self.discordManager = None
        return

    def getTrackClsends(self):
        return False

    def handleConnected(self):
        ToontownInternalRepository.handleConnected(self)
        self.districtId = self.allocateChannel()
        self.notify.info('Creating district (%d)...' % self.districtId)
        self.district = ToontownDistrictAI(self)
        self.district.setName(self.districtName)
        self.district.setDescription(self.districtDescription)
        self.district.generateWithRequiredAndId(self.districtId,
                                                self.getGameDoId(),
                                                OTP_ZONE_ID_MANAGEMENT)
        self.notify.info('Claiming ownership of district (%d)...' %
                         self.districtId)
        datagram = PyDatagram()
        datagram.addServerHeader(self.districtId, self.ourChannel,
                                 STATESERVER_OBJECT_SET_AI)
        datagram.addChannel(self.ourChannel)
        self.send(datagram)
        self.notify.info('Creating local objects...')
        self.createLocals()
        self.notify.info('Creating global objects...')
        self.createGlobals()
        self.notify.info('Creating zones (Playgrounds and Cog HQs)...')
        self.createZones()
        self.notify.info('Making district available...')
        self.district.b_setAvailable(1)
        self.notify.info(
            'District is now ready. Have fun in Toontown Offline!')

    def createLocals(self):
        self.holidayManager = HolidayManagerAI(self)
        self.zoneDataStore = AIZoneDataStore()
        self.petMgr = PetManagerAI(self)
        self.suitInvasionManager = SuitInvasionManagerAI(self)
        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)
        self.questManager = QuestManagerAI(self)
        self.cogPageManager = CogPageManagerAI(self)
        self.fishManager = FishManagerAI(self)
        self.factoryMgr = FactoryManagerAI(self)
        self.mintMgr = MintManagerAI(self)
        self.lawMgr = LawOfficeManagerAI(self)
        self.countryClubMgr = CountryClubManagerAI(self)
        self.promotionMgr = PromotionManagerAI(self)
        self.cogSuitMgr = CogSuitManagerAI(self)
        self.raceMgr = RaceManagerAI(self)
        self.toontownTimeManager = ToontownTimeManager(
            serverTimeUponLogin=int(time.time()),
            globalClockRealTimeUponLogin=globalClock.getRealTime())

    def createGlobals(self):
        districtStatsId = self.allocateChannel()
        self.notify.info('Creating district stats AI (%d)...' %
                         districtStatsId)
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(districtStatsId,
                                                     self.getGameDoId(),
                                                     OTP_ZONE_ID_DISTRICTS)
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.newsManager.d_setExpMultiplier(self.expMultiplier)
        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.inGameNewsMgr = DistributedInGameNewsMgrAI(self)
        self.inGameNewsMgr.setLatestIssueStr('2013-08-22 23:49:46')
        self.inGameNewsMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.partyManager = DistributedPartyManagerAI(self)
        self.partyManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.polarPlaceEffectMgr = DistributedPolarPlaceEffectMgrAI(self)
        self.polarPlaceEffectMgr.generateWithRequired(3821)
        self.resistanceEmoteMgr = DistributedResistanceEmoteMgrAI(self)
        self.resistanceEmoteMgr.generateWithRequired(9720)
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.chatManager = TTOffChatManagerAI(self)
        self.chatManager.generateWithRequiredAndId(OTP_DO_ID_CHAT_MANAGER,
                                                   self.getGameDoId(),
                                                   OTP_ZONE_ID_MANAGEMENT)
        self.estateMgr = EstateManagerAI(self)
        self.estateMgr.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.magicWordManager = TTOffMagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(OTP_ZONE_ID_MANAGEMENT)
        self.deliveryManager = self.generateGlobalObject(
            OTP_DO_ID_TOONTOWN_DELIVERY_MANAGER, 'DistributedDeliveryManager')
        self.banManager = self.generateGlobalObject(OTP_DO_ID_BAN_MANAGER,
                                                    'BanManager')
        self.moddingManager = ModdingManagerAI(self)
        self.moddingManager.generateWithRequiredAndId(
            OTP_DO_ID_MODDING_MANAGER, self.getGameDoId(),
            OTP_ZONE_ID_MANAGEMENT)
        self.moddingManager.setColorsAiToUd(self.moddingManager.getColors())
        self.moddingManager.setCardsAiToUd(self.moddingManager.getCards())
        self.moddingManager.d_setDefaultMaxToon(self.defaultMaxToon)
        self.moddingManager.d_setDefaultZone(self.defaultZone)
        self.discordManager = DiscordManagerAI(self)
        self.discordManager.generateWithRequiredAndId(
            OTP_DO_ID_DISCORD_MANAGER, self.getGameDoId(),
            OTP_ZONE_ID_MANAGEMENT)

    def createHood(self, hoodCtr, zoneId):
        if zoneId != ToontownGlobals.BossbotHQ:
            self.dnaStoreMap[zoneId] = DNAStorage()
            self.dnaDataMap[zoneId] = self.loadDNAFileAI(
                self.dnaStoreMap[zoneId], self.genDNAFileName(zoneId))
            if zoneId in ToontownGlobals.HoodHierarchy:
                for streetId in ToontownGlobals.HoodHierarchy[zoneId]:
                    self.dnaStoreMap[streetId] = DNAStorage()
                    self.dnaDataMap[streetId] = self.loadDNAFileAI(
                        self.dnaStoreMap[streetId],
                        self.genDNAFileName(streetId))

        hood = hoodCtr(self, zoneId)
        hood.startup()
        self.hoods.append(hood)

    def createZones(self):
        NPCToons.generateZone2NpcDict()
        self.zoneTable[ToontownGlobals.ToontownCentral] = (
            (ToontownGlobals.ToontownCentral, 1,
             0), (ToontownGlobals.SillyStreet, 1,
                  1), (ToontownGlobals.LoopyLane, 1,
                       1), (ToontownGlobals.PunchlinePlace, 1, 1))
        self.createHood(TTHoodDataAI, ToontownGlobals.ToontownCentral)
        self.zoneTable[ToontownGlobals.DonaldsDock] = (
            (ToontownGlobals.DonaldsDock, 1,
             0), (ToontownGlobals.BarnacleBoulevard, 1,
                  1), (ToontownGlobals.SeaweedStreet, 1,
                       1), (ToontownGlobals.LighthouseLane, 1, 1))
        self.createHood(DDHoodDataAI, ToontownGlobals.DonaldsDock)
        self.zoneTable[ToontownGlobals.DaisyGardens] = (
            (ToontownGlobals.DaisyGardens, 1,
             0), (ToontownGlobals.ElmStreet, 1,
                  1), (ToontownGlobals.MapleStreet, 1,
                       1), (ToontownGlobals.OakStreet, 1, 1))
        self.createHood(DGHoodDataAI, ToontownGlobals.DaisyGardens)
        self.zoneTable[ToontownGlobals.MinniesMelodyland] = (
            (ToontownGlobals.MinniesMelodyland, 1,
             0), (ToontownGlobals.AltoAvenue, 1,
                  1), (ToontownGlobals.BaritoneBoulevard, 1,
                       1), (ToontownGlobals.TenorTerrace, 1, 1))
        self.createHood(MMHoodDataAI, ToontownGlobals.MinniesMelodyland)
        self.zoneTable[ToontownGlobals.TheBrrrgh] = (
            (ToontownGlobals.TheBrrrgh, 1,
             0), (ToontownGlobals.WalrusWay, 1,
                  1), (ToontownGlobals.SleetStreet, 1,
                       1), (ToontownGlobals.PolarPlace, 1, 1))
        self.createHood(BRHoodDataAI, ToontownGlobals.TheBrrrgh)
        self.zoneTable[ToontownGlobals.DonaldsDreamland] = (
            (ToontownGlobals.DonaldsDreamland, 1,
             0), (ToontownGlobals.LullabyLane, 1,
                  1), (ToontownGlobals.PajamaPlace, 1, 1))
        self.createHood(DLHoodDataAI, ToontownGlobals.DonaldsDreamland)
        self.zoneTable[ToontownGlobals.SellbotHQ] = (
            (ToontownGlobals.SellbotHQ, 0,
             1), (ToontownGlobals.SellbotFactoryExt, 0, 1))
        self.createHood(CSHoodDataAI, ToontownGlobals.SellbotHQ)
        self.zoneTable[ToontownGlobals.CashbotHQ] = ((
            ToontownGlobals.CashbotHQ, 0, 1), )
        self.createHood(CashbotHQDataAI, ToontownGlobals.CashbotHQ)
        self.zoneTable[ToontownGlobals.LawbotHQ] = ((ToontownGlobals.LawbotHQ,
                                                     0, 1), )
        self.createHood(LawbotHQDataAI, ToontownGlobals.LawbotHQ)
        self.zoneTable[ToontownGlobals.BossbotHQ] = ((
            ToontownGlobals.BossbotHQ, 0, 0), )
        self.createHood(BossbotHQDataAI, ToontownGlobals.BossbotHQ)
        self.zoneTable[ToontownGlobals.GoofySpeedway] = ((
            ToontownGlobals.GoofySpeedway, 1, 0), )
        self.createHood(GSHoodDataAI, ToontownGlobals.GoofySpeedway)
        self.zoneTable[ToontownGlobals.OutdoorZone] = ((
            ToontownGlobals.OutdoorZone, 1, 0), )
        self.createHood(OZHoodDataAI, ToontownGlobals.OutdoorZone)
        self.zoneTable[ToontownGlobals.GolfZone] = ((ToontownGlobals.GolfZone,
                                                     1, 0), )
        self.createHood(GZHoodDataAI, ToontownGlobals.GolfZone)
        self.zoneTable[ToontownGlobals.ToontownOutskirts] = (
            (ToontownGlobals.ToontownOutskirts, 1,
             0), (ToontownGlobals.TutorialTerrace, 1, 1))
        self.createHood(SpecialHoodDataAI, ToontownGlobals.ToontownOutskirts)
        self.zoneTable[ToontownGlobals.ToontownCentralBeta] = ((
            ToontownGlobals.ToontownCentralBeta, 1, 0), )
        self.createHood(TTBetaHoodDataAI, ToontownGlobals.ToontownCentralBeta)
        self.zoneTable[ToontownGlobals.DaisyGardensBeta] = (
            (ToontownGlobals.DaisyGardensBeta, 1,
             0), (ToontownGlobals.OakStreetBeta, 1, 0))
        self.createHood(DGBetaHoodDataAI, ToontownGlobals.DaisyGardensBeta)
        self.notify.info(
            'Assigning initial Cog buildings and Field Offices...')
        for suitPlanner in self.suitPlanners.values():
            suitPlanner.assignInitialSuitBuildings()

    def sendPing(self, task=None):
        if self.districtWebsiteId != '' and config.GetBool(
                'mini-server', False):
            gameMode = TTLocalizer.MiniserverLegit if self.defaultAccessLevel == 'NO_ACCESS' else TTLocalizer.MiniserverCheats
            try:
                self.sendPingToAPI(
                    self.districtWebsiteId,
                    name=self.districtName,
                    desc=self.districtDescription,
                    population=self.districtStats.getAvatarCount(),
                    mode=gameMode)
            except:
                self.notify.info(
                    'Could not ping the Toontown Offline website! Make sure you are connected to the Internet.'
                )

            return Task.again
        return Task.done

    def sendPingToAPI(self, serverId, **kwargs):
        columns = self.getColumns()
        data = {'uniqueId': serverId}
        for arg in kwargs.keys():
            if arg in columns:
                data['%s' % arg] = kwargs[arg]
                continue
            self.notify.info('%s is not a valid argument!' % arg)

        resp = self.HTTPReq('http://localhost/api/miniservers/ping', data=data)
        if not resp['success']:
            self.notify.info('Could not ping the website! (Message: %s)' %
                             resp['message'])
            return
        data = {'uniqueId': serverId}
        resp = self.HTTPReq('http://localhost/api/miniservers/id2icon',
                            data=data)
        if not resp['success']:
            self.notify.info('Could not retrieve server icon! (Message: %s)' %
                             resp['message'])
            return
        if resp['message']:
            self.district.b_setIconPath(resp['message'])

    def getColumns(self):
        data = self.HTTPReq('http://localhost/api/miniservers/columns')
        return data

    def HTTPReq(self, url, data=None):
        if type(data) == dict:
            data = urllib.urlencode(data)
            data = data.encode('utf-8')
        context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64)',
            'Authorization': 'Basic dHRvZmY6SmF6enlTdHVkaW9z'
        }
        request = urllib2.Request(url, data, headers=headers)
        response = urllib2.urlopen(request, context=context)
        data = json.loads(response.read().decode())
        return data

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)
        self.avatarCountCheck()

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)
        self.avatarCountCheck()

    def avatarCountCheck(self):
        self.sendPing()
        if not self.districtFull and self.districtStats.getAvatarCount(
        ) >= self.districtLimit:
            self.districtFull = True
            self.notify.warning(
                'Reached player limit! Making district unavailable...')
            self.district.b_setFull(0)
            self.notify.warning(
                'District is now unavailable. Incoming connections will be rejected.'
            )
        if self.districtFull and self.districtStats.getAvatarCount(
        ) < self.districtLimit:
            self.districtFull = False
            self.notify.info(
                'Player count dropped! Making district available...')
            self.district.b_setFull(1)
            self.notify.info(
                'District is now available. Incoming connections will be accepted.'
            )

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def getZoneDataStore(self):
        return self.zoneDataStore

    def genDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]
        if 'outdoor_zone' in hood or 'golf_zone' in hood:
            phase = '6'
        return 'phase_%s/dna/%s_%s.dna' % (phase, hood, zoneId)

    def findFishingPonds(self, dnaData, zoneId, area):
        fishingPonds = []
        fishingPondGroups = []
        if isinstance(dnaData,
                      DNAGroup) and 'fishing_pond' in dnaData.getName():
            fishingPondGroups.append(dnaData)
            pond = self.fishManager.generatePond(area, zoneId)
            fishingPonds.append(pond)
        else:
            if isinstance(dnaData, DNAVisGroup):
                zoneId = ZoneUtil.getTrueZoneId(
                    int(dnaData.getName().split(':')[0]), zoneId)
            for i in xrange(dnaData.getNumChildren()):
                foundFishingPonds, foundFishingPondGroups = self.findFishingPonds(
                    dnaData.at(i), zoneId, area)
                fishingPonds.extend(foundFishingPonds)
                fishingPondGroups.extend(foundFishingPondGroups)

        return (fishingPonds, fishingPondGroups)

    def findFishingSpots(self, dnaData, fishingPond):
        fishingSpots = []
        if isinstance(dnaData,
                      DNAGroup) and dnaData.getName()[:13] == 'fishing_spot_':
            spot = self.fishManager.generateSpots(dnaData, fishingPond)
            fishingSpots.append(spot)
        for i in xrange(dnaData.getNumChildren()):
            foundFishingSpots = self.findFishingSpots(dnaData.at(i),
                                                      fishingPond)
            fishingSpots.extend(foundFishingSpots)

        return fishingSpots

    def findClassicFishingSpots(self, dnaData, fishingPond):
        fishingSpots = []
        if isinstance(dnaData, DNAGroup) and dnaData.getName(
        )[:21] == 'classic_fishing_spot_':
            spot = self.fishManager.generateClassicSpots(dnaData, fishingPond)
            fishingSpots.append(spot)
        for i in xrange(dnaData.getNumChildren()):
            foundFishingSpots = self.findClassicFishingSpots(
                dnaData.at(i), fishingPond)
            fishingSpots.extend(foundFishingSpots)

        return fishingSpots

    def findPartyHats(self, dnaData, zoneId):
        return []

    def loadDNAFileAI(self, dnaStore, dnaFileName):
        return loadDNAFileAI(dnaStore, dnaFileName)

    def allocateZone(self, owner=None):
        zoneId = self.zoneAllocator.allocate()
        if owner:
            self.zoneId2owner[zoneId] = owner
        return zoneId

    def deallocateZone(self, zone):
        if self.zoneId2owner.get(zone):
            del self.zoneId2owner[zone]
        self.zoneAllocator.free(zone)

    def trueUniqueName(self, idString):
        return self.uniqueName(idString)

    def findRacingPads(self,
                       dnaData,
                       zoneId,
                       area,
                       type='racing_pad',
                       overrideDNAZone=False):
        racingPads, racingPadGroups = [], []
        if type in dnaData.getName():
            if type == 'racing_pad':
                nameSplit = dnaData.getName().split('_')
                racePad = DistributedRacePadAI(self)
                racePad.setArea(area)
                racePad.index = int(nameSplit[2])
                racePad.genre = nameSplit[3]
                trackInfo = RaceGlobals.getNextRaceInfo(
                    -1, racePad.genre, racePad.index)
                racePad.setTrackInfo([trackInfo[0], trackInfo[1]])
                racePad.laps = trackInfo[2]
                racePad.generateWithRequired(zoneId)
                racingPads.append(racePad)
                racingPadGroups.append(dnaData)
            elif type == 'viewing_pad':
                viewPad = DistributedViewPadAI(self)
                viewPad.setArea(area)
                viewPad.generateWithRequired(zoneId)
                racingPads.append(viewPad)
                racingPadGroups.append(dnaData)
        for i in xrange(dnaData.getNumChildren()):
            foundRacingPads, foundRacingPadGroups = self.findRacingPads(
                dnaData.at(i), zoneId, area, type, overrideDNAZone)
            racingPads.extend(foundRacingPads)
            racingPadGroups.extend(foundRacingPadGroups)

        return (racingPads, racingPadGroups)

    def findStartingBlocks(self, dnaData, pad):
        startingBlocks = []
        for i in xrange(dnaData.getNumChildren()):
            groupName = dnaData.getName()
            blockName = dnaData.at(i).getName()
            if 'starting_block' in blockName:
                cls = DistributedStartingBlockAI if 'racing_pad' in groupName else DistributedViewingBlockAI
                x, y, z = dnaData.at(i).getPos()
                h, p, r = dnaData.at(i).getHpr()
                padLocationId = int(dnaData.at(i).getName()[(-1)])
                startingBlock = cls(self, pad, x, y, z, h, p, r, padLocationId)
                startingBlock.generateWithRequired(pad.zoneId)
                startingBlocks.append(startingBlock)

        return startingBlocks

    def getAvatarDisconnectReason(self, avId):
        return self.timeManager.avId2disconnectcode.get(
            avId, ToontownGlobals.DisconnectUnknown)

    def findLeaderBoards(self, dnaData, zoneId):
        leaderboards = []
        if 'leaderBoard' in dnaData.getName():
            x, y, z = dnaData.getPos()
            h, p, r = dnaData.getHpr()
            leaderboard = DistributedLeaderBoardAI(self, dnaData.getName(), x,
                                                   y, z, h, p, r)
            leaderboard.generateWithRequired(zoneId)
            leaderboards.append(leaderboard)
        for i in xrange(dnaData.getNumChildren()):
            foundLeaderBoards = self.findLeaderBoards(dnaData.at(i), zoneId)
            leaderboards.extend(foundLeaderBoards)

        return leaderboards

    def systemMessage(self, message):
        for doId, do in self.doId2do.items():
            if isinstance(do, DistributedPlayerAI):
                if str(doId)[0] != str(self.districtId)[0]:
                    do.d_setSystemMessage(0, message, WhisperPopup.WTSystem)

    def announceMaintenance(self, reason, type, time):
        self.systemMessage(
            TTLocalizer.ServerShutdownAnnouncement.format(type, time))
        taskMgr.doMethodLater(time,
                              self.shutdownMaintenance,
                              'shutdownMaintenance',
                              extraArgs=[reason])
        if time - 60.0 > 1:
            taskMgr.doMethodLater(
                time - 60.0,
                self.systemMessage,
                'shutdownMaintenance',
                extraArgs=[TTLocalizer.ServerShutdownWarning.format(type)])

    def shutdownMaintenance(self, reason):
        for doId, do in self.doId2do.items():
            if isinstance(do, DistributedPlayerAI):
                if str(doId)[0] != str(self.districtId)[0]:
                    do.sendSetKick(reason=reason, target=do, silent=3)
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self, baseChannel, serverId, districtName):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            serverId,
                                            dcSuffix='AI')

        self.districtName = districtName

        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)

        NPCToons.generateZone2NpcDict()

        self.use_libpandadna = simbase.config.GetBool('use-libpandadna', False)

        self.hoods = []
        self._dnaStoreMap = {}

        if self.use_libpandadna:
            self.__loader = DNALoader()

        self.zoneDataStore = AIZoneDataStore()

        self.useAllMinigames = self.config.GetBool('want-all-minigames', False)
        self.doLiveUpdates = True

        self.wantCogdominiums = self.config.GetBool('want-cogdo', False)
        self.wantParties = self.config.GetBool('want-parties', False)
        self.wantEmblems = self.config.GetBool('want-emblems', True)

        self.questManager = QuestManagerAI(self)
        self.promotionMgr = PromotionManagerAI(self)
        self.cogPageManager = CogPageManagerAI(self)
        self.cogSuitMgr = CogSuitManagerAI(self)

        self.trophyMgr = DistributedTrophyMgrAI(self)

        self.fishManager = FishManagerAI()

        self.dnaStoreMap = {}

        self.mintMgr = MintManagerAI.MintManagerAI(self)
        self.factoryMgr = FactoryManagerAI.FactoryManagerAI(self)
        self.lawMgr = LawOfficeManagerAI.LawOfficeManagerAI(self)
        self.countryClubMgr = CountryClubManagerAI.CountryClubManagerAI(self)

        self.buildingManagers = {}
        self.suitPlanners = {}

        self.wantMegaInvasions = str(
            self.ourChannel // 1000000) in self.config.GetString(
                'mega-invasion-shards', '402 403').split()

    def getTrackClsends(self):
        return False

    def handleConnected(self):
        self.districtId = self.allocateChannel()
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(
            simbase.air.districtId, self.getGameDoId(), 2)

        dg = PyDatagram()
        dg.addServerHeader(simbase.air.districtId, simbase.air.ourChannel,
                           STATESERVER_OBJECT_SET_AI)
        dg.addChannel(simbase.air.ourChannel)
        simbase.air.send(dg)

        self.createGlobals()
        self.createZones()

    def __ready(self):
        dg = PyDatagram()
        dg.addServerHeader(self.districtStats.doId, self.ourChannel,
                           STATESERVER_OBJECT_DELETE_RAM)
        dg.addUint32(self.districtStats.doId)
        self.addPostRemove(dg)

        self.apiMgr = self.generateGlobalObject(100001, "ShardAPIManager")
        self.apiMgr.start()
        self.apiMgr.d_setShardData()

        self.banMgr = self.generateGlobalObject(100002, "BanManager")

        self.trophyMgr.updateToonData()

    def gotUberdogAPISync(self):
        if not self.distributedDistrict.getAvailable():
            self.notify.info("Got UD API sync, opening shard...")
            messenger.send("startShardActivity")
            self.distributedDistrict.b_setAvailable(1)

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)

    def allocateZone(self):
        return self.zoneAllocator.allocate()

    def deallocateZone(self, zone):
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % avId

    def createGlobals(self):
        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
                                                     self.getGameDoId(), 2)

        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)

        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)

        self.holidayManager = HolidayManagerAI(self)

        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)

        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(2)

        self.petMgr = PetManagerAI(self)

        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)

        self.partyManager = DistributedPartyManagerAI(self)
        self.partyManager.generateWithRequired(2)

        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)

        self.globalPartyMgr = self.generateGlobalObject(
            OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        self.estateManager = EstateManagerAI(self)
        self.estateManager.generateWithRequired(2)

        self.suitInvasionManager = DistributedSuitInvasionManagerAI(self)
        self.suitInvasionManager.generateWithRequired(2)

        self.bankMgr = DistributedBankMgrAI(self)
        self.bankMgr.generateWithRequired(2)

        self.catalogManager = CatalogManagerAI(self)
        self.catalogManager.generateWithRequired(2)

        self.huntId = 0

        if self.holidayManager.isHolidayRunning(
                ToontownGlobals.TRICK_OR_TREAT):
            import DistributedTrickOrTreatTargetAI
            self.trickOrTreatMgr = DistributedTrickOrTreatTargetAI.DistributedTrickOrTreatTargetAI(
                self)
            self.trickOrTreatMgr.generateWithRequired(2)

        self.handleBlackCatMgr()
        self.handleBloodsuckerInvasion()
        self.handleSkelCogWeekInvasion()

        if config.GetBool('want-resistance-emote', True):
            self.resistanceMgr = DistributedResistanceEmoteMgrAI.DistributedResistanceEmoteMgrAI(
                self)
            self.resistanceMgr.generateWithRequired(9720)

        if config.GetBool('want-top-toons', True):
            self.topToonsMgr = self.generateGlobalObject(
                OTP_DO_ID_TOONTOWN_TOP_TOONS_MGR, 'DistributedTopToonsManager')

        else:
            self.topToonsMgr = None

        if config.GetBool('want-polar-effect', True):
            self.polarMgr = DistributedPolarPlaceEffectMgrAI.DistributedPolarPlaceEffectMgrAI(
                self)
            self.polarMgr.generateWithRequired(3821)

    def handleBlackCatMgr(self):
        today = datetime.datetime.now()
        start = datetime.datetime(today.year, 10, 31)
        end = datetime.datetime(today.year, 11, 3)

        def createBlackCatMgr(task=None):
            import DistributedBlackCatMgrAI
            self.blackCatMgr = DistributedBlackCatMgrAI.DistributedBlackCatMgrAI(
                self)
            self.blackCatMgr.generateWithRequired(2513)
            if not self.config.GetBool('force-black-cat-mgr', False):
                self.blackCatMgr.expire((end - today).total_seconds())
            return Task.done

        if start <= today < end or self.config.GetBool('force-black-cat-mgr',
                                                       False):
            createBlackCatMgr(None)

        elif start >= today:
            taskMgr.doMethodLater((start - today).total_seconds(),
                                  createBlackCatMgr, 'air-createBlackCatMgr')

    def handleBloodsuckerInvasion(self):
        if not self.wantMegaInvasions:
            return

        today = datetime.datetime.now()
        start = datetime.datetime(today.year, 10, 31)
        end = datetime.datetime(today.year, 11, 3)

        if start <= today < end:
            self.startMegaInvasion(9, end=end)

        elif start > today:
            taskMgr.doMethodLater((start - today).total_seconds(),
                                  self.startMegaInvasion,
                                  'air-mega-invasion-9',
                                  extraArgs=[9, False, end])

    def handleSkelCogWeekInvasion(self):
        if not self.wantMegaInvasions:
            return

        today = datetime.datetime.now()
        start = datetime.datetime(2014, 11, 10)
        end = datetime.datetime(2014, 11, 17)

        if start <= today < end:
            self.startMegaInvasion(-1, skel=True, end=end)

        elif start > today:
            taskMgr.doMethodLater((start - today).total_seconds(),
                                  self.startMegaInvasion,
                                  'air-mega-invasion-skel',
                                  extraArgs=[-1, True, end])

    def startMegaInvasion(self, suitIndex, skel=False, end=None):
        if suitIndex >= 0:
            suitName = SuitDNA.suitHeadTypes[suitIndex]

        else:
            suitName = None

        if self.suitInvasionManager.hasInvading():
            if self.suitInvasionManager.isMega():
                return Task.done

            self.suitInvasionManager.abort()

        self.suitInvasionManager.startInvasion(suitName, skel, mega=True)
        if end:

            def doAbort(task):
                self.suitInvasionManager.abort()
                return task.done

            today = datetime.datetime.now()
            taskMgr.doMethodLater((end - today).total_seconds(), doAbort,
                                  'air-abort-mega-invasion')

    def getStorage(self, zone):
        s = self._dnaStoreMap.get(zone)
        if not s:
            s = DNAStorage()
            self.loadDNAFileAI(s, self.genDNAFileName(zone))
            self._dnaStoreMap[zone] = s

        return s

    def createZones(self):
        self.zoneTable = {
            1000: ((1000, 1, 0), (1100, 1, 1), (1200, 1, 1), (1300, 1, 1)),
            2000: ((2000, 1, 0), (2100, 1, 1), (2200, 1, 1), (2300, 1, 1)),
            3000: ((3000, 1, 0), (3100, 1, 1), (3200, 1, 1), (3300, 1, 1)),
            4000: ((4000, 1, 0), (4100, 1, 1), (4200, 1, 1), (4300, 1, 1)),
            5000: ((5000, 1, 0), (5100, 1, 1), (5200, 1, 1), (5300, 1, 1)),
            9000: ((9000, 1, 0), (9100, 1, 1), (9200, 1, 1)),
            6000: (),
            7000: ((7000, 1, 0), (7100, 1, 1)),  # XXX to do: planner at 7100
            8000: ((8000, 1, 0), ),
            10000: (),
            11000: (),
            12000: (),
            13000: (),
            17000: (),
        }

        self.__nextHood(0)

    def __nextHood(self, hoodIndex):
        if hoodIndex >= len(hoods):
            self.__ready()
            return Task.done

        self.hoods.append(hoods[hoodIndex](self))
        taskMgr.doMethodLater(0, ToontownAIRepository.__nextHood, 'nextHood',
                              [self, hoodIndex + 1])
        return Task.done

    def genDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phase = ToontownGlobals.phaseMap[hoodId]
        else:
            phase = ToontownGlobals.streetPhaseMap[hoodId]

        return 'phase_%s/dna/%s_%s.dna' % (phase, hood, zoneId)

    def loadDNAFileAI(self, dnastore, filename):
        if self.use_libpandadna:
            f = Filename('../resources/' + str(filename))
            f.setExtension('pdna')
            x = self.__loader.loadDNAFileAI(dnastore, f)

        else:
            f = Filename(filename)
            f = Filename('etc/dnabkp/' + f.getBasename())
            x = loadDNAFileAI(dnastore, str(f))

        return x

    def sendSetZone(self, obj, zoneId):
        obj.b_setLocation(obj.parentId, zoneId)

    def getDisconnectReason(self, avId):
        return self.timeManager.disconnectReasonMap.get(
            avId, 1)  # Default: user closed window

    def killToon(self, avId, force=True):
        """
        Kills given toon if within this shard.
        If force is False, then checks getDisconnectReason.
        """
        toon = self.doId2do.get(avId)

        if not toon:
            self.notify.warning("Tried to kill non-existing toon %s" % avId)
            return False

        if not force:
            if self.getDisconnectReason(avId) == 3:  # Python Error
                return False

        toon.b_setHp(0)

        inventory = toon.inventory
        inventory.zeroInv()
        toon.b_setInventory(inventory.makeNetString())

        self.notify.info("Killed toon %s, RIP!" % avId)
        return True

    def handleObjExit(self, di):
        doId = di.getUint32()

        if doId not in self.doId2do:
            self.notify.warning('Received AI exit for unknown object %d' %
                                (doId))
            return

        do = self.doId2do[doId]
        do.sendDeleteEvent()
        self.removeDOFromTables(do)
        do.delete()
Beispiel #15
0
class ToontownAIRepository(ToontownInternalRepository):
    def __init__(self,
                 baseChannel,
                 stateServerChannel,
                 districtName,
                 startTime=6):
        ToontownInternalRepository.__init__(self,
                                            baseChannel,
                                            stateServerChannel,
                                            dcSuffix='AI')

        self.districtName = districtName
        self.notify.setInfo(True)
        self.hoods = []
        self.cogHeadquarters = []
        self.dnaStoreMap = {}
        self.dnaDataMap = {}
        self.suitPlanners = {}
        self.buildingManagers = {}
        self.sillyMeterMgr = None
        self.factoryMgr = None
        self.mintMgr = None
        self.lawOfficeMgr = None
        self.countryClubMgr = None
        self.startTime = startTime

        self.zoneAllocator = UniqueIdAllocator(
            ToontownGlobals.DynamicZonesBegin, ToontownGlobals.DynamicZonesEnd)
        self.zoneDataStore = AIZoneDataStore()

        self.wantFishing = self.config.GetBool('want-fishing', True)
        self.wantHousing = self.config.GetBool('want-housing', True)
        self.wantPets = self.config.GetBool('want-pets', True)
        self.wantParties = self.config.GetBool('want-parties', True)
        self.wantCogbuildings = self.config.GetBool('want-cogbuildings', True)
        self.wantCogdominiums = self.config.GetBool('want-cogdominiums', True)
        self.doLiveUpdates = self.config.GetBool('want-live-updates', False)
        self.wantTrackClsends = self.config.GetBool('want-track-clsends',
                                                    False)
        self.wantAchievements = self.config.GetBool('want-achievements', True)
        self.wantCharityScreen = self.config.GetBool('want-charity-screen',
                                                     False)
        self.baseXpMultiplier = self.config.GetFloat('base-xp-multiplier', 1.0)
        self.wantHalloween = self.config.GetBool('want-halloween', False)
        self.wantChristmas = self.config.GetBool('want-christmas', False)
        self.cogSuitMessageSent = False
        self.weatherCycleDuration = self.config.GetInt(
            'weather-cycle-duration', 100)

    def createManagers(self):
        self.timeManager = TimeManagerAI(self)
        self.timeManager.generateWithRequired(2)
        self.magicWordManager = MagicWordManagerAI(self)
        self.magicWordManager.generateWithRequired(2)
        self.newsManager = NewsManagerAI(self)
        self.newsManager.generateWithRequired(2)
        self.safeZoneManager = SafeZoneManagerAI(self)
        self.safeZoneManager.generateWithRequired(2)
        self.tutorialManager = TutorialManagerAI(self)
        self.tutorialManager.generateWithRequired(2)
        self.friendManager = FriendManagerAI(self)
        self.friendManager.generateWithRequired(2)
        self.questManager = QuestManagerAI(self)
        self.banManager = BanManagerAI.BanManagerAI(self)
        self.achievementsManager = AchievementsManagerAI(self)
        self.suitInvasionManager = SuitInvasionManagerAI(self)
        self.trophyMgr = DistributedTrophyMgrAI(self)
        self.trophyMgr.generateWithRequired(2)
        self.cogSuitMgr = CogSuitManagerAI.CogSuitManagerAI(self)
        self.promotionMgr = PromotionManagerAI.PromotionManagerAI(self)
        self.experienceMgr = ExperienceRewardManagerAI.ExperienceRewardManagerAI(
            self)
        self.cogPageManager = CogPageManagerAI.CogPageManagerAI()
        self.sillyMeterMgr = DistributedSillyMeterMgrAI.DistributedSillyMeterMgrAI(
            self)
        self.sillyMeterMgr.generateWithRequired(2)
        self.hydrantZeroMgr = DistributedHydrantZeroMgrAI.DistributedHydrantZeroMgrAI(
            self)
        self.hydrantZeroMgr.generateWithRequired(2)
        self.mailboxZeroMgr = DistributedMailboxZeroMgrAI.DistributedMailboxZeroMgrAI(
            self)
        self.mailboxZeroMgr.generateWithRequired(2)
        self.trashcanZeroMgr = DistributedTrashcanZeroMgrAI.DistributedTrashcanZeroMgrAI(
            self)
        self.trashcanZeroMgr.generateWithRequired(2)
        self.dialogueManager = DialogueManagerAI(self)
        self.holidayManager = HolidayManagerAI(self)

        if self.wantFishing:
            self.fishManager = FishManagerAI(self)

        if self.wantHousing:
            self.estateManager = EstateManagerAI(self)
            self.estateManager.generateWithRequired(2)
            self.catalogManager = CatalogManagerAI(self)
            self.catalogManager.generateWithRequired(2)
            self.popularItemManager = PopularItemManagerAI(self)
            self.deliveryManager = self.generateGlobalObject(
                OTP_DO_ID_TOONTOWN_DELIVERY_MANAGER,
                'DistributedDeliveryManager')
            self.mailManager = self.generateGlobalObject(
                OTP_DO_ID_TOONTOWN_MAIL_MANAGER, 'DistributedMailManager')

        if self.wantPets:
            self.petMgr = PetManagerAI(self)

        if self.wantParties:
            self.partyManager = DistributedPartyManagerAI(self)
            self.partyManager.generateWithRequired(2)
            self.globalPartyMgr = self.generateGlobalObject(
                OTP_DO_ID_GLOBAL_PARTY_MANAGER, 'GlobalPartyManager')

        if self.wantCharityScreen:
            self.charityCounter = CharityScreenAI(self)
            self.charityCounter.generateWithRequired(2)
            self.charityCounter.start()

        self.codeRedemptionMgr = simbase.air.generateGlobalObject(
            OTP_DO_ID_TOONTOWN_CODE_REDEMPTION_MANAGER, 'TTCodeRedemptionMgr')
        self.chatAgent = simbase.air.generateGlobalObject(
            OTP_DO_ID_CHAT_MANAGER, 'ChatAgent')

    def createSafeZones(self):
        NPCToons.generateZone2NpcDict()
        if self.config.GetBool('want-toontown-central', True):
            self.hoods.append(TTHoodAI.TTHoodAI(self))
        if self.config.GetBool('want-donalds-dock', True):
            self.hoods.append(DDHoodAI.DDHoodAI(self))
        if self.config.GetBool('want-daisys-garden', True):
            self.hoods.append(DGHoodAI.DGHoodAI(self))
        if self.config.GetBool('want-minnies-melodyland', True):
            self.hoods.append(MMHoodAI.MMHoodAI(self))
        if self.config.GetBool('want-the-burrrgh', True):
            self.hoods.append(BRHoodAI.BRHoodAI(self))
        if self.config.GetBool('want-donalds-dreamland', True):
            self.hoods.append(DLHoodAI.DLHoodAI(self))
        if self.config.GetBool('want-goofy-speedway', True):
            self.hoods.append(GSHoodAI.GSHoodAI(self))
        if self.config.GetBool('want-outdoor-zone', True):
            self.hoods.append(OZHoodAI.OZHoodAI(self))
        if self.config.GetBool('want-golf-zone', True):
            self.hoods.append(GZHoodAI.GZHoodAI(self))

    def createCogHeadquarters(self):
        NPCToons.generateZone2NpcDict()
        if self.config.GetBool('want-sellbot-headquarters', True):
            self.factoryMgr = FactoryManagerAI.FactoryManagerAI(self)
            self.cogHeadquarters.append(SellbotHQAI.SellbotHQAI(self))
        if self.config.GetBool('want-cashbot-headquarters', True):
            self.mintMgr = MintManagerAI.MintManagerAI(self)
            self.cogHeadquarters.append(CashbotHQAI.CashbotHQAI(self))
        if self.config.GetBool('want-lawbot-headquarters', True):
            self.lawOfficeMgr = LawOfficeManagerAI.LawOfficeManagerAI(self)
            self.cogHeadquarters.append(LawbotHQAI.LawbotHQAI(self))
        if self.config.GetBool('want-bossbot-headquarters', True):
            self.countryClubMgr = CountryClubManagerAI.CountryClubManagerAI(
                self)
            self.cogHeadquarters.append(BossbotHQAI.BossbotHQAI(self))

    def handleConnected(self):
        self.districtId = self.allocateChannel()
        self.notify.info('Creating ToontownDistrictAI(%d)...' %
                         self.districtId)
        self.distributedDistrict = ToontownDistrictAI(self)
        self.distributedDistrict.setName(self.districtName)
        self.distributedDistrict.generateWithRequiredAndId(
            self.districtId, self.getGameDoId(), 2)

        self.notify.info('Claiming ownership of channel ID: %d...' %
                         self.districtId)
        self.setAI(self.districtId, self.ourChannel)

        self.districtStats = ToontownDistrictStatsAI(self)
        self.districtStats.settoontownDistrictId(self.districtId)
        self.districtStats.generateWithRequiredAndId(self.allocateChannel(),
                                                     self.getGameDoId(), 3)

        self.notify.info('Created ToontownDistrictStats(%d)' %
                         self.districtStats.doId)

        self.notify.info('Creating managers...')
        self.createManagers()
        if self.config.GetBool('want-safe-zones', True):
            self.notify.info('Creating safe zones...')
            self.createSafeZones()

        if self.config.GetBool('want-cog-headquarters', True):
            self.notify.info('Creating Cog headquarters...')
            self.createCogHeadquarters()

        self.notify.info('Making district available...')
        self.distributedDistrict.b_setAvailable(1)
        self.notify.info('Done.')

    def lookupDNAFileName(self, zoneId):
        zoneId = ZoneUtil.getCanonicalZoneId(zoneId)
        hoodId = ZoneUtil.getCanonicalHoodId(zoneId)
        hood = ToontownGlobals.dnaMap[hoodId]
        if hoodId == zoneId:
            zoneId = 'sz'
            phaseNum = ToontownGlobals.phaseMap[hoodId]
        else:
            phaseNum = ToontownGlobals.streetPhaseMap[hoodId]

        return 'phase_%s/dna/%s_%s.pdna' % (phaseNum, hood, zoneId)

    def loadDNAFileAI(self, dnastore, filename):
        return loadDNAFileAI(dnastore, filename)

    def incrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() + 1)

    def decrementPopulation(self):
        self.districtStats.b_setAvatarCount(
            self.districtStats.getAvatarCount() - 1)

    def setHour(self, hour):
        pass  # Todo: Hour on district page

    def allocateZone(self):
        return self.zoneAllocator.allocate()

    def deallocateZone(self, zone):
        self.zoneAllocator.free(zone)

    def getZoneDataStore(self):
        return self.zoneDataStore

    def getTrackClsends(self):
        return self.wantTrackClsends

    def getAvatarExitEvent(self, avId):
        return 'distObjDelete-%d' % (avId)

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