Example #1
0
 def createTreasurePlanner(self):
     spawnInfo = TreasureGlobals.SafeZoneTreasureSpawns.get(
         self.canonicalHoodId)
     if not spawnInfo:
         return
     treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = spawnInfo
     self.treasurePlanner = SZTreasurePlannerAI(self.canonicalHoodId,
                                                treasureType, healAmount,
                                                spawnPoints, spawnRate,
                                                maxTreasures)
     self.treasurePlanner.start()
 def createTreasurePlanner(self):
     spawnInfo = TreasureGlobals.SafeZoneTreasureSpawns.get(self.canonicalHoodId)
     if not spawnInfo:
         return
     treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = spawnInfo
     self.treasurePlanner = SZTreasurePlannerAI(
         self.canonicalHoodId, treasureType, healAmount, spawnPoints,
         spawnRate, maxTreasures)
     self.treasurePlanner.start()
    def generate(self):
        DistributedObjectAI.generate(self)
        
        self.pond = DistributedFishingPondAI(simbase.air)
        self.pond.setArea(ToontownGlobals.MyEstate)
        self.pond.generateWithRequired(self.zoneId)
        self.pond.start()

        self.pond.bingoMgr = DistributedPondBingoManagerAI(simbase.air)
        self.pond.bingoMgr.setPondDoId(self.pond.getDoId())
        self.pond.bingoMgr.generateWithRequired(self.zoneId)
        self.pond.bingoMgr.initTasks()

        treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = TreasureGlobals.SafeZoneTreasureSpawns[ToontownGlobals.MyEstate]
        self.treasurePlanner = SZTreasurePlannerAI(self.zoneId, treasureType, healAmount, spawnPoints, spawnRate, maxTreasures)
        self.treasurePlanner.start()

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(49.1029, -124.805, 0.344704, 90, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(46.5222, -134.739, 0.390713, 75, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(41.31, -144.559, 0.375978, 45, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(46.8254, -113.682, 0.46015, 135, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)
        
        self.jukebox = DistributedPartyJukeboxActivityAI(self.air, self.doId, (0, 0, 0, 0))
        self.jukebox.generateWithRequired(self.zoneId)
        self.jukebox.sendUpdate('setX', [-21.8630])
        self.jukebox.sendUpdate('setY', [-154.669])
        self.jukebox.sendUpdate('setH', [148.7050])
        self.jukebox.sendUpdate('unloadSign')

        ButterflyGlobals.generateIndexes(self.zoneId, ButterflyGlobals.ESTATE)
        for i in xrange(0, ButterflyGlobals.NUM_BUTTERFLY_AREAS[ButterflyGlobals.ESTATE]):
            for j in xrange(0, ButterflyGlobals.NUM_BUTTERFLIES[ButterflyGlobals.ESTATE]):
                butterfly = DistributedButterflyAI.DistributedButterflyAI(self.air, ButterflyGlobals.ESTATE, i, self.zoneId)
                butterfly.generateWithRequired(self.zoneId)
                butterfly.start()
                self.butterflies.append(butterfly)
    def generate(self):
        DistributedObjectAI.generate(self)

        self.pond = DistributedFishingPondAI(simbase.air)
        self.pond.setArea(ToontownGlobals.MyEstate)
        self.pond.generateWithRequired(self.zoneId)
        self.pond.start()

        self.pond.bingoMgr = DistributedPondBingoManagerAI(simbase.air)
        self.pond.bingoMgr.setPondDoId(self.pond.getDoId())
        self.pond.bingoMgr.generateWithRequired(self.zoneId)
        self.pond.bingoMgr.initTasks()

        treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = TreasureGlobals.SafeZoneTreasureSpawns[
            ToontownGlobals.MyEstate]
        self.treasurePlanner = SZTreasurePlannerAI(self.zoneId, treasureType,
                                                   healAmount, spawnPoints,
                                                   spawnRate, maxTreasures)
        self.treasurePlanner.start()

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(49.1029, -124.805, 0.344704, 90, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(46.5222, -134.739, 0.390713, 75, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(41.31, -144.559, 0.375978, 45, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(46.8254, -113.682, 0.46015, 135, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        self.jukebox = DistributedPartyJukeboxActivityAI(
            self.air, self.doId, (0, 0, 0, 0))
        self.jukebox.generateWithRequired(self.zoneId)
        self.jukebox.sendUpdate('setX', [-21.8630])
        self.jukebox.sendUpdate('setY', [-154.669])
        self.jukebox.sendUpdate('setH', [148.7050])
        self.jukebox.sendUpdate('unloadSign')

        ButterflyGlobals.generateIndexes(self.zoneId, ButterflyGlobals.ESTATE)
        for i in xrange(
                0,
                ButterflyGlobals.NUM_BUTTERFLY_AREAS[ButterflyGlobals.ESTATE]):
            for j in xrange(
                    0,
                    ButterflyGlobals.NUM_BUTTERFLIES[ButterflyGlobals.ESTATE]):
                butterfly = DistributedButterflyAI.DistributedButterflyAI(
                    self.air, ButterflyGlobals.ESTATE, i, self.zoneId)
                butterfly.generateWithRequired(self.zoneId)
                butterfly.start()
                self.butterflies.append(butterfly)
class DistributedEstateAI(DistributedObjectAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedEstateAI')

    def __init__(self, air):
        DistributedObjectAI.__init__(self, air)
        self.toons = [0, 0, 0, 0, 0, 0]
        self.items = [[], [], [], [], [], []]
        self.estateType = 0
        self.cloudType = 0
        self.dawnTime = 0
        self.lastEpochTimestamp = 0
        self.rentalTimestamp = 0
        self.houses = [None] * 6
        self.rentalType = 0
        self.rentalHandle = None

        self.pond = None
        self.jukebox = None
        self.spots = []
        self.butterflies = []

        self.owner = None

        self.gardenManager = GardenManager(self)
        self.__pendingGardens = {}

    @property
    def hostId(self):
        return 1000000001

    def generate(self):
        DistributedObjectAI.generate(self)

        self.pond = DistributedFishingPondAI(simbase.air)
        self.pond.setArea(ToontownGlobals.MyEstate)
        self.pond.generateWithRequired(self.zoneId)
        self.pond.start()

        self.pond.bingoMgr = DistributedPondBingoManagerAI(simbase.air)
        self.pond.bingoMgr.setPondDoId(self.pond.getDoId())
        self.pond.bingoMgr.generateWithRequired(self.zoneId)
        self.pond.bingoMgr.initTasks()

        treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = TreasureGlobals.SafeZoneTreasureSpawns[
            ToontownGlobals.MyEstate]
        self.treasurePlanner = SZTreasurePlannerAI(self.zoneId, treasureType,
                                                   healAmount, spawnPoints,
                                                   spawnRate, maxTreasures)
        self.treasurePlanner.start()

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(49.1029, -124.805, 0.344704, 90, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(46.5222, -134.739, 0.390713, 75, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(41.31, -144.559, 0.375978, 45, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(46.8254, -113.682, 0.46015, 135, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        self.jukebox = DistributedPartyJukeboxActivityAI(
            self.air, self.doId, (0, 0, 0, 0))
        self.jukebox.generateWithRequired(self.zoneId)
        self.jukebox.sendUpdate('setX', [-21.8630])
        self.jukebox.sendUpdate('setY', [-154.669])
        self.jukebox.sendUpdate('setH', [148.7050])
        self.jukebox.sendUpdate('unloadSign')

        ButterflyGlobals.generateIndexes(self.zoneId, ButterflyGlobals.ESTATE)
        for i in xrange(
                0,
                ButterflyGlobals.NUM_BUTTERFLY_AREAS[ButterflyGlobals.ESTATE]):
            for j in xrange(
                    0,
                    ButterflyGlobals.NUM_BUTTERFLIES[ButterflyGlobals.ESTATE]):
                butterfly = DistributedButterflyAI.DistributedButterflyAI(
                    self.air, ButterflyGlobals.ESTATE, i, self.zoneId)
                butterfly.generateWithRequired(self.zoneId)
                butterfly.start()
                self.butterflies.append(butterfly)

    def destroy(self):
        for house in self.houses:
            if house:
                house.requestDelete()
        for butterfly in self.butterflies:
            if butterfly:
                butterfly.requestDelete()
        del self.houses[:]
        if self.pond:
            for spot in self.spots:
                spot.requestDelete()
            self.spots = []
            self.pond.requestDelete()
            self.pond = None
        if self.jukebox:
            self.jukebox.requestDelete()
        if self.treasurePlanner:
            self.treasurePlanner.stop()

        self.gardenManager.destroy()
        if self.rentalHandle:
            self.rentalHandle.destroy()
            self.rentalHandle = None

        self.requestDelete()

    def addDistObj(self, distObj):
        self.doId2do[distObj.doId] = distObj

    def setClientReady(self):
        self.sendUpdate('setEstateReady', [])

    def setEstateType(self, type):
        self.estateType = type

    def d_setEstateType(self, type):
        self.sendUpdate('setEstateType', [type])

    def b_setEstateType(self, type):
        self.setEstateType(type)
        self.d_setEstateType(type)

    def getEstateType(self):
        return self.estateType

    def requestServerTime(self):
        avId = self.air.getAvatarIdFromSender()
        self.sendUpdateToAvatarId(
            avId, 'setServerTime',
            [time.time() % HouseGlobals.DAY_NIGHT_PERIOD])

    def setDawnTime(self, dawnTime):
        self.dawnTime = dawnTime

    def d_setDawnTime(self, dawnTime):
        self.sendUpdate('setDawnTime', [dawnTime])

    def b_setDawnTime(self, dawnTime):
        self.setDawnTime(dawnTime)
        self.d_setDawnTime(dawnTime)

    def getDawnTime(self):
        return self.dawnTime

    def setLastEpochTimeStamp(self, last):
        self.lastEpochTimestamp = last

    def d_setLastEpochTimeStamp(self, last):
        self.sendUpdate('setLastEpochTimeStamp', [last])

    def b_setLastEpochTimeStamp(self, last):
        self.setLastEpochTimeStamp(last)
        self.d_setLastEpochTimeStamp(last)

    def getLastEpochTimeStamp(self):
        return self.lastEpochTimestamp

    def setRentalTimeStamp(self, rental):
        self.rentalTimestamp = rental

    def d_setRentalTimeStamp(self, rental):
        self.sendUpdate('setRentalTimeStamp', [rental])

    def b_setRentalTimeStamp(self, rental):
        self.setRentalTimeStamp(rental)
        self.d_setRentalTimeStamp(rental)

    def getRentalTimeStamp(self):
        return self.rentalTimestamp

    def b_setRentalType(self, type):
        self.d_setRentalType(type)
        self.setRentalType(type)

    def d_setRentalType(self, type):
        self.sendUpdate('setRentalType', [type])

    def setRentalType(self, type):
        expirestamp = self.getRentalTimeStamp()
        if expirestamp == 0:
            expire = 0

        else:
            expire = int(expirestamp - time.time())

        if expire < 0:
            self.rentalType = 0
            self.d_setRentalType(0)
            self.b_setRentalTimeStamp(0)

        else:
            if self.rentalType == type:
                return

            self.rentalType = type
            if self.rentalHandle:
                self.rentalHandle.destroy()
                self.rentalHandle = None

            if self.rentalType == ToontownGlobals.RentalCannon:
                self.rentalHandle = CannonRental(self)

            else:
                self.notify.warning('Unknown rental %s' % self.rentalType)
                return

            self.rentalHandle.generateObjects()

    def getRentalType(self):
        return self.rentalType

    def rentItem(self, rentType, duration):
        self.b_setRentalTimeStamp(time.time() + duration * 60)
        self.b_setRentalType(rentType)

    def setSlot0ToonId(self, id):
        self.toons[0] = id

    def d_setSlot0ToonId(self, id):
        self.sendUpdate('setSlot0ToonId', [id])

    def b_setSlot0ToonId(self, id):
        self.setSlot0ToonId(id)
        self.d_setSlot0ToonId(id)

    def getSlot0ToonId(self):
        return self.toons[0]

    def setSlot0Items(self, items):
        self.items[0] = items

    def d_setSlot0Items(self, items):
        self.sendUpdate('setSlot5Items', [items])

    def b_setSlot0Items(self, items):
        self.setSlot0Items(items)
        self.d_setSlot0Items(items)

    def getSlot0Items(self):
        return self.items[0]

    def setSlot1ToonId(self, id):
        self.toons[1] = id

    def d_setSlot1ToonId(self, id):
        self.sendUpdate('setSlot1ToonId', [id])

    def b_setSlot1ToonId(self, id):
        self.setSlot1ToonId(id)
        self.d_setSlot1ToonId(id)

    def getSlot1ToonId(self):
        return self.toons[1]

    def setSlot1Items(self, items):
        self.items[1] = items

    def d_setSlot1Items(self, items):
        self.sendUpdate('setSlot2Items', [items])

    def b_setSlot1Items(self, items):
        self.setSlot2Items(items)
        self.d_setSlot2Items(items)

    def getSlot1Items(self):
        return self.items[1]

    def setSlot2ToonId(self, id):
        self.toons[2] = id

    def d_setSlot2ToonId(self, id):
        self.sendUpdate('setSlot2ToonId', [id])

    def b_setSlot2ToonId(self, id):
        self.setSlot2ToonId(id)
        self.d_setSlot2ToonId(id)

    def getSlot2ToonId(self):
        return self.toons[2]

    def setSlot2Items(self, items):
        self.items[2] = items

    def d_setSlot2Items(self, items):
        self.sendUpdate('setSlot2Items', [items])

    def b_setSlot2Items(self, items):
        self.setSlot2Items(items)
        self.d_setSlot2Items(items)

    def getSlot2Items(self):
        return self.items[2]

    def setSlot3ToonId(self, id):
        self.toons[3] = id

    def d_setSlot3ToonId(self, id):
        self.sendUpdate('setSlot3ToonId', [id])

    def b_setSlot3ToonId(self, id):
        self.setSlot3ToonId(id)
        self.d_setSlot3ToonId(id)

    def getSlot3ToonId(self):
        return self.toons[3]

    def setSlot3Items(self, items):
        self.items[3] = items

    def d_setSlot3Items(self, items):
        self.sendUpdate('setSlot3Items', [items])

    def b_setSlot3Items(self, items):
        self.setSlot3Items(items)
        self.d_setSlot3Items(items)

    def getSlot3Items(self):
        return self.items[3]

    def setSlot4ToonId(self, id):
        self.toons[4] = id

    def d_setSlot4ToonId(self, id):
        self.sendUpdate('setSlot4ToonId', [id])

    def b_setSlot5ToonId(self, id):
        self.setSlot4ToonId(id)
        self.d_setSlot4ToonId(id)

    def getSlot4ToonId(self):
        return self.toons[4]

    def setSlot4Items(self, items):
        self.items[4] = items

    def d_setSlot4Items(self, items):
        self.sendUpdate('setSlot4Items', [items])

    def b_setSlot4Items(self, items):
        self.setSlot4Items(items)
        self.d_setSlot4Items(items)

    def getSlot4Items(self):
        return self.items[4]

    def setSlot5ToonId(self, id):
        self.toons[5] = id

    def d_setSlot5ToonId(self, id):
        self.sendUpdate('setSlot5ToonId', [id])

    def b_setSlot5ToonId(self, id):
        self.setSlot5ToonId(id)
        self.d_setSlot5ToonId(id)

    def getSlot5ToonId(self):
        return self.toons[5]

    def setSlot5Items(self, items):
        self.items[5] = items

    def d_setSlot5Items(self, items):
        self.sendUpdate('setSlot5Items', [items])

    def b_setSlot5Items(self, items):
        self.setSlot5Items(items)
        self.d_setSlot5Items(items)

    def getSlot5Items(self):
        return self.items[5]

    def setIdList(self, idList):
        for i in xrange(len(idList)):
            if i >= 6:
                return
            self.toons[i] = idList[i]

    def d_setIdList(self, idList):
        self.sendUpdate('setIdList', [idList])

    def b_setIdList(self, idList):
        self.setIdList(idList)
        self.d_setIdLst(idList)

    def completeFlowerSale(self, flag):
        if not flag:
            return

        avId = self.air.getAvatarIdFromSender()
        av = self.air.doId2do.get(avId)
        if not av:
            return

        collection = av.flowerCollection

        earning = 0
        newSpecies = 0
        for flower in av.flowerBasket.getFlower():
            if collection.collectFlower(
                    flower) == GardenGlobals.COLLECT_NEW_ENTRY:
                newSpecies += 1

            earning += flower.getValue()

        av.b_setFlowerBasket([], [])
        av.d_setFlowerCollection(*av.flowerCollection.getNetLists())
        av.addMoney(earning)

        oldSpecies = len(collection) - newSpecies
        dt = abs(len(collection) // 10 - oldSpecies // 10)
        if dt:
            self.notify.info('%d is getting a gardening trophy!' % avId)

            maxHp = av.getMaxHp()
            maxHp = min(ToontownGlobals.MaxHpLimit, maxHp + dt)
            av.b_setMaxHp(maxHp)
            av.toonUp(maxHp)

            self.sendUpdate('awardedTrophy', [avId])

        av.b_setGardenTrophies(range(len(collection) // 10))

    def completeFishSale(self):
        avId = self.air.getAvatarIdFromSender()
        av = self.air.doId2do.get(avId)

        if not av:
            return

        if self.air.fishManager.creditFishTank(av):
            self.sendUpdateToAvatarId(avId, 'thankSeller', [
                ToontownGlobals.FISHSALE_TROPHY,
                len(av.fishCollection),
                FishGlobals.getTotalNumFish()
            ])
        else:
            self.sendUpdateToAvatarId(
                avId, 'thankSeller', [ToontownGlobals.FISHSALE_COMPLETE, 0, 0])

    def setClouds(self, clouds):
        self.cloudType = clouds

    def d_setClouds(self, clouds):
        self.sendUpdate('setClouds', [clouds])

    def b_setClouds(self, clouds):
        self.setClouds(clouds)
        self.d_setClouds(clouds)

    def getClouds(self):
        return self.cloudType

    # Garden methods
    def getToonSlot(self, avId):
        if avId not in self.toons:
            return

        return self.toons.index(avId)

    def setSlot0Garden(self, flag):
        self.__pendingGardens[0] = flag

    def setSlot1Garden(self, flag):
        self.__pendingGardens[1] = flag

    def setSlot2Garden(self, flag):
        self.__pendingGardens[2] = flag

    def setSlot3Garden(self, flag):
        self.__pendingGardens[3] = flag

    def setSlot4Garden(self, flag):
        self.__pendingGardens[4] = flag

    def setSlot5Garden(self, flag):
        self.__pendingGardens[5] = flag

    def placeStarterGarden(self, avId, record=1):
        av = self.air.doId2do.get(avId)
        if not av:
            return

        slot = self.getToonSlot(avId)
        if slot is None:
            return

        if record:
            av.b_setGardenStarted(1)
            self.sendUpdate('setSlot%dGarden' % slot, ['started'])

        self.notify.info('placeStarterGarden %d %d' % (avId, slot))
        self.gardenManager.handleSingleGarden(avId)

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        self.sendUpdate('setIdList', [self.toons])

        for index, started in self.__pendingGardens.items():
            if started:
                self.gardenManager.handleSingleGarden(self.toons[index])

        self.__pendingGardens = {}
        if config.GetBool('fake-garden-started-ai', False):
            self.placeStarterGarden(100000002, 0)
Example #6
0
class HoodAI:
    notify = directNotify.newCategory('HoodAI')
    notify.setInfo(True)

    def __init__(self, air, zoneId, canonicalHoodId):
        self.air = air
        self.zoneId = zoneId
        self.canonicalHoodId = canonicalHoodId

        self.fishingPonds = []
        self.partyGates = []
        self.treasurePlanner = None
        self.buildingManagers = []
        self.suitPlanners = []

        for zoneId in self.getZoneTable():
            self.notify.info('Creating objects... ' +
                             self.getLocationName(zoneId))
            dnaFileName = self.air.lookupDNAFileName(zoneId)
            dnaStore = DNAStorage()
            dnaData = simbase.air.loadDNAFileAI(dnaStore, dnaFileName)
            self.air.dnaStoreMap[zoneId] = dnaStore
            self.air.dnaDataMap[zoneId] = dnaData

    def getZoneTable(self):
        zoneTable = [self.zoneId]
        zoneTable.extend(
            ToontownGlobals.HoodHierarchy.get(self.canonicalHoodId, []))
        return zoneTable

    def getLocationName(self, zoneId):
        lookupTable = ToontownGlobals.hoodNameMap
        isStreet = (zoneId % 1000) != 0
        if isStreet:
            lookupTable = TTLocalizer.GlobalStreetNames
        name = lookupTable.get(zoneId, '')
        if isStreet:
            return '%s, %s' % (self.getLocationName(self.zoneId), name[2])
        return name[2]

    def startup(self):
        if self.air.wantFishing:
            self.createFishingPonds()
        if self.air.wantParties:
            self.createPartyPeople()
        if simbase.config.GetBool('want-treasure-planners', True):
            self.createTreasurePlanner()
        self.createBuildingManagers()
        if simbase.config.GetBool('want-suit-planners', True):
            self.createSuitPlanners()

    def shutdown(self):
        if self.treasurePlanner:
            self.treasurePlanner.stop()
            self.treasurePlanner.deleteAllTreasuresNow()
            self.treasurePlanner = None
        for suitPlanner in self.suitPlanners:
            suitPlanner.requestDelete()
            del self.air.suitPlanners[suitPlanner.zoneId]
        self.suitPlanners = []
        for buildingManager in self.buildingManagers:
            buildingManager.cleanup()
            del self.air.buildingManagers[buildingManager.branchId]
        self.buildingManagers = []
        del self.fishingPonds
        for distObj in self.doId2do.values():
            distObj.requestDelete()

    def findFishingPonds(self, dnaGroup, zoneId, area):
        fishingPonds = []
        fishingPondGroups = []
        if isinstance(dnaGroup, DNAGroup) and ('fishing_pond'
                                               in dnaGroup.getName()):
            fishingPondGroups.append(dnaGroup)

            fishingPond = DistributedFishingPondAI(simbase.air)
            fishingPond.setArea(area)
            fishingPond.generateWithRequired(zoneId)
            fishingPond.start()

            fishingPond.bingoMgr = DistributedPondBingoManagerAI(simbase.air)
            fishingPond.bingoMgr.setPondDoId(fishingPond.getDoId())
            fishingPond.bingoMgr.generateWithRequired(zoneId)
            fishingPond.bingoMgr.initTasks()

            fishingPonds.append(fishingPond)
        elif isinstance(dnaGroup, DNAVisGroup):
            zoneId = int(dnaGroup.getName().split(':')[0])
        for i in xrange(dnaGroup.getNumChildren()):
            (foundFishingPonds,
             foundFishingPondGroups) = self.findFishingPonds(
                 dnaGroup.at(i), zoneId, area)
            fishingPonds.extend(foundFishingPonds)
            fishingPondGroups.extend(foundFishingPondGroups)
        return (fishingPonds, fishingPondGroups)

    def findFishingSpots(self, dnaGroup, fishingPond):
        fishingSpots = []
        if isinstance(dnaGroup, DNAGroup) and ('fishing_spot'
                                               in dnaGroup.getName()):
            fishingSpot = DistributedFishingSpotAI(simbase.air)
            fishingSpot.setPondDoId(fishingPond.doId)
            x, y, z = dnaGroup.getPos()
            h, p, r = dnaGroup.getHpr()
            fishingSpot.setPosHpr(x, y, z, h, p, r)
            fishingSpot.generateWithRequired(fishingPond.zoneId)

            fishingSpots.append(fishingSpot)
        for i in xrange(dnaGroup.getNumChildren()):
            foundFishingSpots = self.findFishingSpots(dnaGroup.at(i),
                                                      fishingPond)
            fishingSpots.extend(foundFishingSpots)
        return fishingSpots

    def createFishingPonds(self):
        self.fishingPonds = []
        fishingPondGroups = []
        for zoneId in self.getZoneTable():
            dnaData = self.air.dnaDataMap.get(zoneId, None)
            if dnaData.getName() == 'root':
                area = ZoneUtil.getCanonicalZoneId(zoneId)
                (foundFishingPonds,
                 foundFishingPondGroups) = self.findFishingPonds(
                     dnaData, zoneId, area)
                self.fishingPonds.extend(foundFishingPonds)
                fishingPondGroups.extend(foundFishingPondGroups)
        for fishingPond in self.fishingPonds:
            NPCToons.createNpcsInZone(self.air, fishingPond.zoneId)
        fishingSpots = []
        for (dnaGroup, fishingPond) in zip(fishingPondGroups,
                                           self.fishingPonds):
            fishingSpots.extend(self.findFishingSpots(dnaGroup, fishingPond))

    def findPartyGates(self, dnaGroup, zoneId):
        partyGates = []
        if isinstance(dnaGroup, DNAGroup) and ('prop_party_gate'
                                               in dnaGroup.getName()):
            partyGate = DistributedPartyGateAI(simbase.air)
            partyGate.setArea(zoneId)
            partyGate.generateWithRequired(zoneId)

            partyGates.append(partyGates)
        for i in xrange(dnaGroup.getNumChildren()):
            foundPartyGates = self.findPartyGates(dnaGroup.at(i), zoneId)
            partyGates.extend(foundPartyGates)
        return partyGates

    def createPartyPeople(self):
        self.partyGates = []
        for zoneId in self.getZoneTable():
            dnaData = self.air.dnaDataMap.get(zoneId, None)
            if dnaData.getName() == 'root':
                foundPartyGates = self.findPartyGates(dnaData, zoneId)
                self.partyGates.extend(foundPartyGates)

    def createTreasurePlanner(self):
        spawnInfo = TreasureGlobals.SafeZoneTreasureSpawns.get(
            self.canonicalHoodId)
        if not spawnInfo:
            return
        treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = spawnInfo
        self.treasurePlanner = SZTreasurePlannerAI(self.canonicalHoodId,
                                                   treasureType, healAmount,
                                                   spawnPoints, spawnRate,
                                                   maxTreasures)
        self.treasurePlanner.start()

    def createBuildingManagers(self):
        for zoneId in self.getZoneTable():
            dnaStore = self.air.dnaStoreMap[zoneId]
            buildingManager = DistributedBuildingMgrAI.DistributedBuildingMgrAI(
                self.air, zoneId, dnaStore, self.air.trophyMgr)
            self.buildingManagers.append(buildingManager)
            self.air.buildingManagers[zoneId] = buildingManager

    def createSuitPlanners(self):
        for zoneId in self.getZoneTable():
            if zoneId == self.zoneId:
                continue
            suitPlanner = DistributedSuitPlannerAI.DistributedSuitPlannerAI(
                self.air, zoneId)
            suitPlanner.generateWithRequired(zoneId)
            suitPlanner.d_setZoneId(zoneId)
            suitPlanner.initTasks()
            self.suitPlanners.append(suitPlanner)
            self.air.suitPlanners[zoneId] = suitPlanner
class HoodAI:
    notify = directNotify.newCategory('HoodAI')
    notify.setInfo(True)

    def __init__(self, air, zoneId, canonicalHoodId):
        self.air = air
        self.zoneId = zoneId
        self.canonicalHoodId = canonicalHoodId

        self.fishingPonds = []
        self.partyGates = []
        self.treasurePlanner = None
        self.buildingManagers = []
        self.suitPlanners = []

        for zoneId in self.getZoneTable():
            self.notify.info('Creating objects... ' + self.getLocationName(zoneId))
            dnaFileName = self.air.lookupDNAFileName(zoneId)
            dnaStore = DNAStorage()
            dnaData = simbase.air.loadDNAFileAI(dnaStore, dnaFileName)
            self.air.dnaStoreMap[zoneId] = dnaStore
            self.air.dnaDataMap[zoneId] = dnaData

    def getZoneTable(self):
        zoneTable = [self.zoneId]
        zoneTable.extend(ToontownGlobals.HoodHierarchy.get(self.canonicalHoodId, []))
        return zoneTable

    def getLocationName(self, zoneId):
        lookupTable = ToontownGlobals.hoodNameMap
        isStreet = (zoneId%1000) != 0
        if isStreet:
            lookupTable = TTLocalizer.GlobalStreetNames
        name = lookupTable.get(zoneId, '')
        if isStreet:
            return '%s, %s' % (self.getLocationName(self.zoneId), name[2])
        return name[2]

    def startup(self):
        if self.air.wantFishing:
            self.createFishingPonds()
        if self.air.wantParties:
            self.createPartyPeople()
        if simbase.config.GetBool('want-treasure-planners', True):
            self.createTreasurePlanner()
        self.createBuildingManagers()
        if simbase.config.GetBool('want-suit-planners', True):
            self.createSuitPlanners()

    def shutdown(self):
        if self.treasurePlanner:
            self.treasurePlanner.stop()
            self.treasurePlanner.deleteAllTreasuresNow()
            self.treasurePlanner = None
        for suitPlanner in self.suitPlanners:
            suitPlanner.requestDelete()
            del self.air.suitPlanners[suitPlanner.zoneId]
        self.suitPlanners = []
        for buildingManager in self.buildingManagers:
            buildingManager.cleanup()
            del self.air.buildingManagers[buildingManager.branchId]
        self.buildingManagers = []
        del self.fishingPonds
        for distObj in self.doId2do.values():
            distObj.requestDelete()

    def findFishingPonds(self, dnaGroup, zoneId, area):
        fishingPonds = []
        fishingPondGroups = []
        if isinstance(dnaGroup, DNAGroup) and ('fishing_pond' in dnaGroup.getName()):
            fishingPondGroups.append(dnaGroup)

            fishingPond = DistributedFishingPondAI(simbase.air)
            fishingPond.setArea(area)
            fishingPond.generateWithRequired(zoneId)
            fishingPond.start()

            fishingPond.bingoMgr = DistributedPondBingoManagerAI(simbase.air)
            fishingPond.bingoMgr.setPondDoId(fishingPond.getDoId())
            fishingPond.bingoMgr.generateWithRequired(zoneId)
            fishingPond.bingoMgr.initTasks()

            fishingPonds.append(fishingPond)
        elif isinstance(dnaGroup, DNAVisGroup):
            zoneId = int(dnaGroup.getName().split(':')[0])
        for i in xrange(dnaGroup.getNumChildren()):
            (foundFishingPonds, foundFishingPondGroups) = self.findFishingPonds(dnaGroup.at(i), zoneId, area)
            fishingPonds.extend(foundFishingPonds)
            fishingPondGroups.extend(foundFishingPondGroups)
        return (fishingPonds, fishingPondGroups)

    def findFishingSpots(self, dnaGroup, fishingPond):
        fishingSpots = []
        if isinstance(dnaGroup, DNAGroup) and ('fishing_spot' in dnaGroup.getName()):
            fishingSpot = DistributedFishingSpotAI(simbase.air)
            fishingSpot.setPondDoId(fishingPond.doId)
            x, y, z = dnaGroup.getPos()
            h, p, r = dnaGroup.getHpr()
            fishingSpot.setPosHpr(x, y, z, h, p, r)
            fishingSpot.generateWithRequired(fishingPond.zoneId)

            fishingSpots.append(fishingSpot)
        for i in xrange(dnaGroup.getNumChildren()):
            foundFishingSpots = self.findFishingSpots(dnaGroup.at(i), fishingPond)
            fishingSpots.extend(foundFishingSpots)
        return fishingSpots

    def createFishingPonds(self):
        self.fishingPonds = []
        fishingPondGroups = []
        for zoneId in self.getZoneTable():
            dnaData = self.air.dnaDataMap.get(zoneId, None)
            if dnaData.getName() == 'root':
                area = ZoneUtil.getCanonicalZoneId(zoneId)
                (foundFishingPonds, foundFishingPondGroups) = self.findFishingPonds(dnaData, zoneId, area)
                self.fishingPonds.extend(foundFishingPonds)
                fishingPondGroups.extend(foundFishingPondGroups)
        for fishingPond in self.fishingPonds:
            NPCToons.createNpcsInZone(self.air, fishingPond.zoneId)
        fishingSpots = []
        for (dnaGroup, fishingPond) in zip(fishingPondGroups, self.fishingPonds):
            fishingSpots.extend(self.findFishingSpots(dnaGroup, fishingPond))

    def findPartyGates(self, dnaGroup, zoneId):
        partyGates = []
        if isinstance(dnaGroup, DNAGroup) and ('prop_party_gate' in dnaGroup.getName()):
            partyGate = DistributedPartyGateAI(simbase.air)
            partyGate.setArea(zoneId)
            partyGate.generateWithRequired(zoneId)

            partyGates.append(partyGates)
        for i in xrange(dnaGroup.getNumChildren()):
            foundPartyGates = self.findPartyGates(dnaGroup.at(i), zoneId)
            partyGates.extend(foundPartyGates)
        return partyGates

    def createPartyPeople(self):
        self.partyGates = []
        for zoneId in self.getZoneTable():
            dnaData = self.air.dnaDataMap.get(zoneId, None)
            if dnaData.getName() == 'root':
                foundPartyGates = self.findPartyGates(dnaData, zoneId)
                self.partyGates.extend(foundPartyGates)

    def createTreasurePlanner(self):
        spawnInfo = TreasureGlobals.SafeZoneTreasureSpawns.get(self.canonicalHoodId)
        if not spawnInfo:
            return
        treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = spawnInfo
        self.treasurePlanner = SZTreasurePlannerAI(
            self.canonicalHoodId, treasureType, healAmount, spawnPoints,
            spawnRate, maxTreasures)
        self.treasurePlanner.start()

    def createBuildingManagers(self):
        for zoneId in self.getZoneTable():
            dnaStore = self.air.dnaStoreMap[zoneId]
            buildingManager = DistributedBuildingMgrAI.DistributedBuildingMgrAI(
                self.air, zoneId, dnaStore, self.air.trophyMgr)
            self.buildingManagers.append(buildingManager)
            self.air.buildingManagers[zoneId] = buildingManager

    def createSuitPlanners(self):
        for zoneId in self.getZoneTable():
            if zoneId == self.zoneId:
                continue
            suitPlanner = DistributedSuitPlannerAI.DistributedSuitPlannerAI(self.air, zoneId)
            suitPlanner.generateWithRequired(zoneId)
            suitPlanner.d_setZoneId(zoneId)
            suitPlanner.initTasks()
            self.suitPlanners.append(suitPlanner)
            self.air.suitPlanners[zoneId] = suitPlanner
class DistributedEstateAI(DistributedObjectAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedEstateAI')
    
    def __init__(self, air):
        DistributedObjectAI.__init__(self, air)
        self.toons = [0, 0, 0, 0, 0, 0]
        self.items = [[], [], [], [], [], []]
        self.estateType = 0
        self.cloudType = 0
        self.dawnTime = 0
        self.lastEpochTimestamp = 0
        self.rentalTimestamp = 0
        self.houses = [None] * 6
        self.rentalType = 0
        self.rentalHandle = None
        
        self.pond = None
        self.jukebox = None
        self.spots = []
        self.butterflies = []

        self.owner = None
        
        self.gardenManager = GardenManager(self)
        self.__pendingGardens = {}
    
    @property
    def hostId(self):
        return 1000000001
        
    def generate(self):
        DistributedObjectAI.generate(self)
        
        self.pond = DistributedFishingPondAI(simbase.air)
        self.pond.setArea(ToontownGlobals.MyEstate)
        self.pond.generateWithRequired(self.zoneId)
        self.pond.start()

        self.pond.bingoMgr = DistributedPondBingoManagerAI(simbase.air)
        self.pond.bingoMgr.setPondDoId(self.pond.getDoId())
        self.pond.bingoMgr.generateWithRequired(self.zoneId)
        self.pond.bingoMgr.initTasks()

        treasureType, healAmount, spawnPoints, spawnRate, maxTreasures = TreasureGlobals.SafeZoneTreasureSpawns[ToontownGlobals.MyEstate]
        self.treasurePlanner = SZTreasurePlannerAI(self.zoneId, treasureType, healAmount, spawnPoints, spawnRate, maxTreasures)
        self.treasurePlanner.start()

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(49.1029, -124.805, 0.344704, 90, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(46.5222, -134.739, 0.390713, 75, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(41.31, -144.559, 0.375978, 45, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)

        spot = DistributedFishingSpotAI(self.air)
        spot.setPondDoId(self.pond.getDoId())
        spot.setPosHpr(46.8254, -113.682, 0.46015, 135, 0, 0)
        spot.generateWithRequired(self.zoneId)
        self.spots.append(spot)
        
        self.jukebox = DistributedPartyJukeboxActivityAI(self.air, self.doId, (0, 0, 0, 0))
        self.jukebox.generateWithRequired(self.zoneId)
        self.jukebox.sendUpdate('setX', [-21.8630])
        self.jukebox.sendUpdate('setY', [-154.669])
        self.jukebox.sendUpdate('setH', [148.7050])
        self.jukebox.sendUpdate('unloadSign')

        ButterflyGlobals.generateIndexes(self.zoneId, ButterflyGlobals.ESTATE)
        for i in xrange(0, ButterflyGlobals.NUM_BUTTERFLY_AREAS[ButterflyGlobals.ESTATE]):
            for j in xrange(0, ButterflyGlobals.NUM_BUTTERFLIES[ButterflyGlobals.ESTATE]):
                butterfly = DistributedButterflyAI.DistributedButterflyAI(self.air, ButterflyGlobals.ESTATE, i, self.zoneId)
                butterfly.generateWithRequired(self.zoneId)
                butterfly.start()
                self.butterflies.append(butterfly)

    def destroy(self):
        for house in self.houses:
            if house:
                house.requestDelete()
        for butterfly in self.butterflies:
            if butterfly:
                butterfly.requestDelete()
        del self.houses[:]
        if self.pond:
            for spot in self.spots:
                spot.requestDelete()
            self.spots = []
            self.pond.requestDelete()
            self.pond = None
        if self.jukebox:
            self.jukebox.requestDelete()
        if self.treasurePlanner:
            self.treasurePlanner.stop()
                
        self.gardenManager.destroy()
        if self.rentalHandle:
            self.rentalHandle.destroy()
            self.rentalHandle = None
                
        self.requestDelete()

    def addDistObj(self, distObj):
        self.doId2do[distObj.doId] = distObj

    def setClientReady(self):
        self.sendUpdate('setEstateReady', [])

    def setEstateType(self, type):
        self.estateType = type
        
    def d_setEstateType(self, type):
        self.sendUpdate('setEstateType', [type])
        
    def b_setEstateType(self, type):
        self.setEstateType(type)
        self.d_setEstateType(type)

    def getEstateType(self):
        return self.estateType

    def requestServerTime(self):
        avId = self.air.getAvatarIdFromSender()
        self.sendUpdateToAvatarId(avId, 'setServerTime', [time.time() % HouseGlobals.DAY_NIGHT_PERIOD])

    def setDawnTime(self, dawnTime):
        self.dawnTime = dawnTime
        
    def d_setDawnTime(self, dawnTime):
        self.sendUpdate('setDawnTime', [dawnTime])
        
    def b_setDawnTime(self, dawnTime):
        self.setDawnTime(dawnTime)
        self.d_setDawnTime(dawnTime)
        
    def getDawnTime(self):
        return self.dawnTime

    def setLastEpochTimeStamp(self, last):
        self.lastEpochTimestamp = last
        
    def d_setLastEpochTimeStamp(self, last):
        self.sendUpdate('setLastEpochTimeStamp', [last])
        
    def b_setLastEpochTimeStamp(self, last):
        self.setLastEpochTimeStamp(last)
        self.d_setLastEpochTimeStamp(last)
        
    def getLastEpochTimeStamp(self):
        return self.lastEpochTimestamp

    def setRentalTimeStamp(self, rental):
        self.rentalTimestamp = rental
        
    def d_setRentalTimeStamp(self, rental):
        self.sendUpdate('setRentalTimeStamp', [rental])
        
    def b_setRentalTimeStamp(self, rental):
        self.setRentalTimeStamp(rental)
        self.d_setRentalTimeStamp(rental)
        
    def getRentalTimeStamp(self):
        return self.rentalTimestamp

    def b_setRentalType(self, type):
        self.d_setRentalType(type)
        self.setRentalType(type)
        
    def d_setRentalType(self, type):
        self.sendUpdate('setRentalType', [type])
        
    def setRentalType(self, type):
        expirestamp = self.getRentalTimeStamp()
        if expirestamp == 0:
            expire = 0
            
        else:
            expire = int(expirestamp - time.time())
            
        if expire < 0:
            self.rentalType = 0
            self.d_setRentalType(0)
            self.b_setRentalTimeStamp(0)
        
        else:
            if self.rentalType == type:
                return
                
            self.rentalType = type
            if self.rentalHandle:
                self.rentalHandle.destroy()
                self.rentalHandle = None
                
            if self.rentalType == ToontownGlobals.RentalCannon:
                self.rentalHandle = CannonRental(self)
                
            else:
                self.notify.warning('Unknown rental %s' % self.rentalType)
                return
                
            self.rentalHandle.generateObjects()
        
    def getRentalType(self):
        return self.rentalType
        
    def rentItem(self, rentType, duration):
        self.b_setRentalTimeStamp(time.time() + duration * 60)
        self.b_setRentalType(rentType)
        
    def setSlot0ToonId(self, id):
        self.toons[0] = id
        
    def d_setSlot0ToonId(self, id):
        self.sendUpdate('setSlot0ToonId', [id])
        
    def b_setSlot0ToonId(self, id):
        self.setSlot0ToonId(id)
        self.d_setSlot0ToonId(id)
        
    def getSlot0ToonId(self):
        return self.toons[0]

    def setSlot0Items(self, items):
        self.items[0] = items

    def d_setSlot0Items(self, items):
        self.sendUpdate('setSlot5Items', [items])
        
    def b_setSlot0Items(self, items):
        self.setSlot0Items(items)
        self.d_setSlot0Items(items)
        
    def getSlot0Items(self):
        return self.items[0]
        
    def setSlot1ToonId(self, id):
        self.toons[1] = id

    def d_setSlot1ToonId(self, id):
        self.sendUpdate('setSlot1ToonId', [id])
        
    def b_setSlot1ToonId(self, id):
        self.setSlot1ToonId(id)
        self.d_setSlot1ToonId(id)
        
    def getSlot1ToonId(self):
        return self.toons[1]
        
    def setSlot1Items(self, items):
        self.items[1] = items
        
    def d_setSlot1Items(self, items):
        self.sendUpdate('setSlot2Items', [items])
        
    def b_setSlot1Items(self, items):
        self.setSlot2Items(items)
        self.d_setSlot2Items(items)
        
    def getSlot1Items(self):
        return self.items[1]

    def setSlot2ToonId(self, id):
        self.toons[2] = id

    def d_setSlot2ToonId(self, id):
        self.sendUpdate('setSlot2ToonId', [id])
        
    def b_setSlot2ToonId(self, id):
        self.setSlot2ToonId(id)
        self.d_setSlot2ToonId(id)
        
    def getSlot2ToonId(self):
        return self.toons[2]

    def setSlot2Items(self, items):
        self.items[2] = items

    def d_setSlot2Items(self, items):
        self.sendUpdate('setSlot2Items', [items])
        
    def b_setSlot2Items(self, items):
        self.setSlot2Items(items)
        self.d_setSlot2Items(items)
        
    def getSlot2Items(self):
        return self.items[2]

    def setSlot3ToonId(self, id):
        self.toons[3] = id
        
    def d_setSlot3ToonId(self, id):
        self.sendUpdate('setSlot3ToonId', [id])
        
    def b_setSlot3ToonId(self, id):
        self.setSlot3ToonId(id)
        self.d_setSlot3ToonId(id)
        
    def getSlot3ToonId(self):
        return self.toons[3]

    def setSlot3Items(self, items):
        self.items[3] = items
        
    def d_setSlot3Items(self, items):
        self.sendUpdate('setSlot3Items', [items])
        
    def b_setSlot3Items(self, items):
        self.setSlot3Items(items)
        self.d_setSlot3Items(items)
        
    def getSlot3Items(self):
        return self.items[3]

    def setSlot4ToonId(self, id):
        self.toons[4] = id
        
    def d_setSlot4ToonId(self, id):
        self.sendUpdate('setSlot4ToonId', [id])
        
    def b_setSlot5ToonId(self, id):
        self.setSlot4ToonId(id)
        self.d_setSlot4ToonId(id)
        
    def getSlot4ToonId(self):
        return self.toons[4]

    def setSlot4Items(self, items):
        self.items[4] = items
        
    def d_setSlot4Items(self, items):
        self.sendUpdate('setSlot4Items', [items])
        
    def b_setSlot4Items(self, items):
        self.setSlot4Items(items)
        self.d_setSlot4Items(items)
        
    def getSlot4Items(self):
        return self.items[4]

    def setSlot5ToonId(self, id):
        self.toons[5] = id
        
    def d_setSlot5ToonId(self, id):
        self.sendUpdate('setSlot5ToonId', [id])
        
    def b_setSlot5ToonId(self, id):
        self.setSlot5ToonId(id)
        self.d_setSlot5ToonId(id)
        
    def getSlot5ToonId(self):
        return self.toons[5]

    def setSlot5Items(self, items):
        self.items[5] = items
        
    def d_setSlot5Items(self, items):
        self.sendUpdate('setSlot5Items', [items])
        
    def b_setSlot5Items(self, items):
        self.setSlot5Items(items)
        self.d_setSlot5Items(items)
        
    def getSlot5Items(self):
        return self.items[5]

    def setIdList(self, idList):
        for i in xrange(len(idList)):
            if i >= 6:
                return
            self.toons[i] = idList[i]
        
    def d_setIdList(self, idList):
        self.sendUpdate('setIdList', [idList])
    
    def b_setIdList(self, idList):
        self.setIdList(idList)
        self.d_setIdLst(idList)
        
    def completeFlowerSale(self, flag):
        if not flag:
            return
            
        avId = self.air.getAvatarIdFromSender()
        av = self.air.doId2do.get(avId)
        if not av:
            return
            
        collection = av.flowerCollection
        
        earning = 0
        newSpecies = 0
        for flower in av.flowerBasket.getFlower():
            if collection.collectFlower(flower) == GardenGlobals.COLLECT_NEW_ENTRY:
                newSpecies += 1
                
            earning += flower.getValue()
        
        av.b_setFlowerBasket([], [])
        av.d_setFlowerCollection(*av.flowerCollection.getNetLists())
        av.addMoney(earning)
        
        oldSpecies = len(collection) - newSpecies
        dt = abs(len(collection) // 10 - oldSpecies // 10)
        if dt:
            self.notify.info('%d is getting a gardening trophy!' % avId)
            
            maxHp = av.getMaxHp()
            maxHp = min(ToontownGlobals.MaxHpLimit, maxHp + dt)
            av.b_setMaxHp(maxHp)
            av.toonUp(maxHp)
            
            self.sendUpdate('awardedTrophy', [avId])
        
        av.b_setGardenTrophies(range(len(collection) // 10))
    
    def completeFishSale(self):
        avId = self.air.getAvatarIdFromSender()
        av = self.air.doId2do.get(avId)
        
        if not av:
            return

        if self.air.fishManager.creditFishTank(av):
            self.sendUpdateToAvatarId(avId, 'thankSeller', [ToontownGlobals.FISHSALE_TROPHY, len(av.fishCollection), FishGlobals.getTotalNumFish()])
        else:
            self.sendUpdateToAvatarId(avId, 'thankSeller', [ToontownGlobals.FISHSALE_COMPLETE, 0, 0])
                         
    def setClouds(self, clouds):
        self.cloudType = clouds
        
    def d_setClouds(self, clouds):
        self.sendUpdate('setClouds', [clouds])
        
    def b_setClouds(self, clouds):
        self.setClouds(clouds)
        self.d_setClouds(clouds)
        
    def getClouds(self):
        return self.cloudType
        
    # Garden methods
    def getToonSlot(self, avId):
        if avId not in self.toons:
            return
            
        return self.toons.index(avId)
     
    def setSlot0Garden(self, flag):
        self.__pendingGardens[0] = flag

    def setSlot1Garden(self, flag):
        self.__pendingGardens[1] = flag

    def setSlot2Garden(self, flag):
        self.__pendingGardens[2] = flag
       
    def setSlot3Garden(self, flag):
        self.__pendingGardens[3] = flag
   
    def setSlot4Garden(self, flag):
        self.__pendingGardens[4] = flag

    def setSlot5Garden(self, flag):
        self.__pendingGardens[5] = flag
    
    def placeStarterGarden(self, avId, record=1):
        av = self.air.doId2do.get(avId)
        if not av:
            return

        slot = self.getToonSlot(avId)
        if slot is None:
            return
            
        if record:
            av.b_setGardenStarted(1)
            self.sendUpdate('setSlot%dGarden' % slot, ['started'])
        
        self.notify.info('placeStarterGarden %d %d' % (avId, slot))
        self.gardenManager.handleSingleGarden(avId)
        
    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        self.sendUpdate('setIdList', [self.toons])
        
        for index, started in self.__pendingGardens.items():
            if started:
                self.gardenManager.handleSingleGarden(self.toons[index])
            
        self.__pendingGardens = {}
        if config.GetBool('fake-garden-started-ai', False):
            self.placeStarterGarden(100000002, 0)