def getItems(self):
        items = CatalogItemList(store=CatalogItem.Customization|CatalogItem.Location)

        for item in self.items:
            items.append(item.catalogItem)

        return items.getBlob()
Example #2
0
    def buildList(self):
        self.itemList = CatalogItemList(store=CatalogItem.Customization
                                        | CatalogItem.Location)
        for i in xrange(self.dnaData.getNumChildren()):
            child = self.dnaData.at(i)
            if child.getName() == 'interior':
                interior = child
                break
        else:
            self.notify.error('Could not find "interior" in DNA!')

        for i in xrange(interior.getNumChildren()):
            child = interior.at(i)
            code = child.getCode()
            if code not in DNA2Furniture:
                self.notify.warning('Unrecognized furniture code %r!' % code)
                continue
            itemId = DNA2Furniture[code]
            if itemId is None:
                continue
            x, y, z = child.getPos()
            h, p, r = child.getHpr()
            self.itemList.append(
                CatalogFurnitureItem(itemId, posHpr=(x, y, z, h, p, r)))

        return
    def buildList(self):
        self.itemList = CatalogItemList(store=(CatalogItem.Customization
                                               | CatalogItem.Location))

        # Find the interior node:
        for i in xrange(self.dnaData.getNumChildren()):
            child = self.dnaData.at(i)
            if child.getName() == 'interior':
                interior = child
                break
        else:
            self.notify.error('Could not find "interior" in DNA!')

        self.itemList.append(CatalogFurnitureItem(1399, posHpr=self.phonePos))
        # Every child in the interior node is a prop, thus:
        for i in xrange(interior.getNumChildren()):
            child = interior.at(i)
            code = child.getCode()

            if code not in DNA2Furniture:
                self.notify.warning('Unrecognized furniture code %r!' % code)
                continue

            itemId = DNA2Furniture[code]
            if itemId is None:
                continue
            if hasattr(itemId, '__getitem__'):
                itemId = itemId[self.gender]

            x, y, z = child.getPos()
            h, p, r = child.getHpr()
            self.itemList.append(
                CatalogFurnitureItem(itemId, posHpr=(x, y, z, h, p, r)))
    def buildList(self):
        self.itemList = CatalogItemList(store=(CatalogItem.Customization
                                               | CatalogItem.Location))

        # Find the interior node:
        for child in self.dnaData.children:
            if child.getName() == 'interior':
                interior = child
                break
        else:
            self.notify.error('Could not find "interior" in DNA!')

        # Every child in the interior node is a prop, thus:
        for child in interior.children:
            code = child.getCode()

            if code not in DNA2Furniture:
                self.notify.warning('Unrecognized furniture code %r!' % code)
                continue

            itemId = DNA2Furniture[code]
            if itemId is None:
                continue

            x, y, z = child.getPos()
            h, p, r = child.getHpr()
            self.itemList.append(
                CatalogFurnitureItem(itemId, posHpr=(x, y, z, h, p, r)))
Example #5
0
    def getItems(self):
        items = CatalogItemList(store=CatalogItem.Customization|CatalogItem.Location)

        for item in self.items:
            items.append(item.catalogItem)

        return items.getBlob()
 def loadFromHouse(self):
     self.b_setAtticItems(self.house.getAtticItems())
     self.b_setAtticWallpaper(self.house.getAtticWallpaper())
     self.b_setAtticWindows(self.house.getAtticWindows())
     self.b_setDeletedItems(self.house.getDeletedItems())
     self.wallpaper = CatalogItemList(self.house.getInteriorWallpaper(), store=CatalogItem.Customization)
     self.applyWallpaper()
     self.windows = CatalogItemList(self.house.getInteriorWindows(), store=CatalogItem.Customization | CatalogItem.WindowPlacement)
     self.applyWindows()
     self.setItems(self.house.getInteriorItems())
Example #7
0
 def loadFromHouse(self):
     self.b_setAtticItems(self.house.getAtticItems())
     self.b_setAtticWallpaper(self.house.getAtticWallpaper())
     self.b_setAtticWindows(self.house.getAtticWindows())
     self.b_setDeletedItems(self.house.getDeletedItems())
     self.wallpaper = CatalogItemList(self.house.getInteriorWallpaper(), store=CatalogItem.Customization)
     self.applyWallpaper()
     self.windows = CatalogItemList(self.house.getInteriorWindows(), store=CatalogItem.Customization | CatalogItem.WindowPlacement)
     self.applyWindows()
     self.setItems(self.house.getInteriorItems())
class DNAFurnitureReaderAI:
    # This object processes the house_interior*.dna files and produces a
    # CatalogItemList representing the furniture in the DNA file. The resulting
    # list is passed to the FurnitureManager in order to initialize a blank
    # house to the default furniture arrangement.
    notify = directNotify.newCategory("DNAFurnitureReaderAI")

    def __init__(self, dnaData, gender, phonePos):
        self.dnaData = dnaData
        self.gender = gender
        self.phonePos = phonePos
        self.itemList = None

    def buildList(self):
        self.itemList = CatalogItemList(store=(CatalogItem.Customization
                                               | CatalogItem.Location))

        # Find the interior node:
        for i in xrange(self.dnaData.getNumChildren()):
            child = self.dnaData.at(i)
            if child.getName() == 'interior':
                interior = child
                break
        else:
            self.notify.error('Could not find "interior" in DNA!')

        self.itemList.append(CatalogFurnitureItem(1399, posHpr=self.phonePos))
        # Every child in the interior node is a prop, thus:
        for i in xrange(interior.getNumChildren()):
            child = interior.at(i)
            code = child.getCode()

            if code not in DNA2Furniture:
                self.notify.warning('Unrecognized furniture code %r!' % code)
                continue

            itemId = DNA2Furniture[code]
            if itemId is None:
                continue
            if hasattr(itemId, '__getitem__'):
                itemId = itemId[self.gender]

            x, y, z = child.getPos()
            h, p, r = child.getHpr()
            self.itemList.append(
                CatalogFurnitureItem(itemId, posHpr=(x, y, z, h, p, r)))

    def getList(self):
        if not self.itemList:
            self.buildList()
        return self.itemList

    def getBlob(self):
        return self.getList().getBlob()
class DNAFurnitureReaderAI:
    # This object processes the house_interior*.dna files and produces a
    # CatalogItemList representing the furniture in the DNA file. The resulting
    # list is passed to the FurnitureManager in order to initialize a blank
    # house to the default furniture arrangement.
    notify = directNotify.newCategory("DNAFurnitureReaderAI")

    def __init__(self, dnaData, gender, phonePos):
        self.dnaData = dnaData
        self.gender = gender
        self.phonePos = phonePos
        self.itemList = None

    def buildList(self):
        self.itemList = CatalogItemList(store=(CatalogItem.Customization |
                                               CatalogItem.Location))

        # Find the interior node:
        for i in xrange(self.dnaData.getNumChildren()):
            child = self.dnaData.at(i)
            if child.getName() == 'interior':
                interior = child
                break
        else:
            self.notify.error('Could not find "interior" in DNA!')

        self.itemList.append(CatalogFurnitureItem(1399, posHpr=self.phonePos))
        # Every child in the interior node is a prop, thus:
        for i in xrange(interior.getNumChildren()):
            child = interior.at(i)
            code = child.getCode()

            if code not in DNA2Furniture:
                self.notify.warning('Unrecognized furniture code %r!' % code)
                continue

            itemId = DNA2Furniture[code]
            if itemId is None:
                continue
            if hasattr(itemId, '__getitem__'):
                itemId = itemId[self.gender]

            x, y, z = child.getPos()
            h, p, r = child.getHpr()
            self.itemList.append(CatalogFurnitureItem(itemId,
                                                      posHpr=(x, y, z, h, p, r)))

    def getList(self):
        if not self.itemList:
            self.buildList()
        return self.itemList

    def getBlob(self):
        return self.getList().getBlob()
Example #10
0
    def createInterior(self):
        self.houseInterior = random.choice(HouseGlobals.interiors)
        self.dnaData = self.air.loadDNAFileAI(self.dnaStore,
                                              self.houseInterior[0])
        furnitureData = {}
        for i in xrange(self.dnaData.getNumChildren()):
            node = self.dnaData.at(i)
            if node.getName() == 'interior':
                for j in xrange(node.getNumChildren()):
                    obj = node.at(j)
                    objName = obj.getName()
                    x, y, z = obj.getPos()
                    h, p, r = obj.getHpr()
                    code = obj.getCode()
                    furnitureData[objName] = {
                        'code': code,
                        'posHpr': (x, y, z, h, 0, 0),
                        'scale': obj.getScale(),
                        'itemId': code2furnitureId.get(code, 0)
                    }

        furnitureData['phone'] = {
            'code': 'phone',
            'posHpr': (-11, 2, 0, 0, 0, 0),
            'scale': 'phone',
            'itemId': code2furnitureId.get('phone', 0)
        }
        interiorItems = CatalogItemList(store=CatalogItem.Customization
                                        | CatalogItem.Location)
        ignoredItems = ['house_interiorA_DNARoot', 'GardenA_DNARoot']
        for name, data in furnitureData.iteritems():
            itemId = data.get('itemId', 0)
            if itemId == 0:
                if name not in ignoredItems:
                    self.notify.warning(
                        'Tried to generate item %s but the ID was not found!' %
                        name)
                continue
            if name == 'closetBoy_DNARoot' and self.gender == 'f':
                itemId += 10
            newItem = CatalogFurnitureItem(itemId, posHpr=data.get('posHpr'))
            interiorItems.append(newItem)

        self.house.b_setInteriorItems(interiorItems.getBlob())
        self.house.b_setInteriorWindows(defaultWindows.getBlob())
        self.house.b_setInteriorWallpaper(defaultWallpaper.getBlob())
        self.furnitureManager.wallpaper = self.house.interiorWallpaper
        self.furnitureManager.windows = self.house.interiorWindows
        self.furnitureManager.loadFurniture()
        self.furnitureManager.saveFurniture()
    def setItems(self, items):
        # Decode the blob:
        items = CatalogItemList(items,
                                store=CatalogItem.Customization
                                | CatalogItem.Location)

        # Throw out our old items:
        for item in self.items:
            item.destroy()
        self.items = []

        # Due to a bug, some people are missing their closets...
        hasCloset = False
        for item in items:
            if item.getFlags() & FLCloset:
                hasCloset = True
                break

        if not hasCloset and self.ownerId != 0:
            item = CatalogFurnitureItem(500)  # the basic closet...
            item.posHpr = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
            items.append(item)
            # Since we have modified the items list, should we save it back to the house?

        for item in items:
            if item.getFlags() & FLTrunk:
                if self.house.gender is 0:
                    if item.furnitureType - 4000 < 10:
                        item.furnitureType += 10
                elif item.furnitureType - 4000 > 10:
                    item.furnitureType -= 10
                do = DistributedTrunkAI(self.air, self, item)
            elif item.getFlags() & FLCloset:
                if self.house.gender is 0:
                    if item.furnitureType - 500 < 10:
                        item.furnitureType += 10
                elif item.furnitureType - 500 > 10:
                    item.furnitureType -= 10
                do = DistributedClosetAI(self.air, self, item)
            elif item.getFlags() & FLBank:
                do = DistributedBankAI(self.air, self, item)
            elif item.getFlags() & FLPhone:
                do = DistributedPhoneAI(self.air, self, item)
            else:
                do = DistributedFurnitureItemAI(self.air, self, item)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)
    def setItems(self, items):
        # Decode the blob:
        items = CatalogItemList(items, store=CatalogItem.Customization|CatalogItem.Location)

        # Throw out our old items:
        for item in self.items:
            item.destroy()
        self.items = []

        items.removeDuplicates(FLCloset)

        # Due to a bug, some people are missing their closets...
        hasCloset = False
        for item in items:
            if item.getFlags() & FLCloset:
                hasCloset = True
                break

        if not hasCloset and self.ownerId != 0:
            item = CatalogFurnitureItem(500)  # the basic closet...
            item.posHpr = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
            items.append(item)
            # Since we have modified the items list, should we save it back to the house?

        for item in items:
            if item.getFlags() & FLTrunk:
                if self.house.gender is 0:
                    if item.furnitureType - 4000 < 10:
                        item.furnitureType += 10
                elif item.furnitureType - 4000 > 10:
                    item.furnitureType -= 10
                do = DistributedTrunkAI(self.air, self, item)
            elif item.getFlags() & FLCloset:
                if self.house.gender is 0:
                    if item.furnitureType - 500 < 10:
                        item.furnitureType += 10
                elif item.furnitureType - 500 > 10:
                    item.furnitureType -= 10
                do = DistributedClosetAI(self.air, self, item)
            elif item.getFlags() & FLBank:
                continue # We dont want banks in the estates.
            elif item.getFlags() & FLPhone:
                do = DistributedPhoneAI(self.air, self, item)
            else:
                do = DistributedFurnitureItemAI(self.air, self, item)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)
    def __gotHouse(self, dclass, fields): # PY3 needs work on Python3
        # I think what this is doing, is actually calculating the items you currently have in your house?
        if dclass != self.air.dclassesByName['DistributedHouseAI']:
            return

        numItems = len(CatalogItemList(fields['setInteriorItems'][0], store=CatalogItem.Customization)) + len(CatalogItemList(fields['setAtticItems'][0], store=CatalogItem.Customization)) + len(CatalogItemList(fields['setAtticWallpaper'][0], store=CatalogItem.Customization)) + len(CatalogItemList(fields['setAtticWindows'][0], store=CatalogItem.Customization)) + len(CatalogItemList(fields['setInteriorWallpaper'][0], store=CatalogItem.Customization)) + len(CatalogItemList(fields['setInteriorWindows'][0], store=CatalogItem.Customization))
        self.sendUpdateToAvatarId(fields['setAvatarId'][0], 'setLimits', [numItems])
    def setItems(self, items):
        items = CatalogItemList(items,
                                store=CatalogItem.Customization
                                | CatalogItem.Location)
        for item in self.items:
            item.destroy()

        self.items = []
        for item in items:
            if item.getHashContents() in (1300, 1310, 1320, 1330, 1340, 1350):
                do = DistributedBankAI(self.air, self, item)
            else:
                if item.getHashContents() >= 500 and item.getHashContents(
                ) <= 518:
                    do = DistributedClosetAI(self.air, self, item)
                    do.setOwnerId(self.avId)
                else:
                    if item.getHashContents() == 1399:
                        do = DistributedPhoneAI(self.air, self, item)
                    else:
                        if item.getHashContents() in (4000, 4010):
                            do = DistributedTrunkAI(self.air, self, item)
                            do.setOwnerId(self.avId)
                        else:
                            do = DistributedFurnitureItemAI(
                                self.air, self, item)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)
    def setItems(self, items):
        # Decode the blob:
        items = CatalogItemList(items,
                                store=CatalogItem.Customization
                                | CatalogItem.Location)

        # Throw out our old items:
        for item in self.items:
            item.destroy()
        self.items = []

        for item in items:
            if item.getFlags() & FLCloset:
                if self.house.gender is 0:
                    # If they have a male closet, we need to make it a female closet.
                    if item.furnitureType - 500 < 10:
                        item.furnitureType += 10
                elif item.furnitureType - 500 > 10:
                    # If they have a female closet, we need to make it a male closet.
                    item.furnitureType -= 10
                do = DistributedClosetAI(self.air, self, item)
            elif item.getFlags() & FLBank:
                do = DistributedBankAI(self.air, self, item)
            elif item.getFlags() & FLPhone:
                do = DistributedPhoneAI(self.air, self, item)
            else:
                do = DistributedFurnitureItemAI(self.air, self, item)

            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)
    def buildList(self):
        self.itemList = CatalogItemList(store=(CatalogItem.Customization |
                                               CatalogItem.Location))

        # Find the interior node:
        for i in xrange(self.dnaData.getNumChildren()):
            child = self.dnaData.at(i)
            if child.getName() == 'interior':
                interior = child
                break
        else:
            self.notify.error('Could not find "interior" in DNA!')

        self.itemList.append(CatalogFurnitureItem(1399, posHpr=self.phonePos))
        # Every child in the interior node is a prop, thus:
        for i in xrange(interior.getNumChildren()):
            child = interior.at(i)
            code = child.getCode()

            if code not in DNA2Furniture:
                self.notify.warning('Unrecognized furniture code %r!' % code)
                continue

            itemId = DNA2Furniture[code]
            if itemId is None:
                continue

            x, y, z = child.getPos()
            h, p, r = child.getHpr()
            self.itemList.append(CatalogFurnitureItem(itemId,
                                                      posHpr=(x, y, z, h, p, r)))
Example #17
0
    def loadFurniture(self):
        for item in CatalogItemList(self.house.getInteriorItems(),
                                    store=CatalogItem.Customization
                                    | CatalogItem.Location):
            self.generateItem(item)

        self.wallpaper = CatalogItemList(self.house.getInteriorWallpaper(),
                                         store=CatalogItem.Customization)
        self.house.b_setInteriorWallpaper(self.house.getInteriorWallpaper())
        self.interior.b_setWallpaper(self.house.getInteriorWallpaper())
        self.windows = CatalogItemList(self.house.getInteriorWindows(),
                                       store=CatalogItem.Customization
                                       | CatalogItem.WindowPlacement)
        self.house.b_setInteriorWindows(self.house.getInteriorWindows())
        self.interior.b_setWindows(self.house.getInteriorWindows())
        self.b_setAtticItems(self.house.getAtticItems())
        self.b_setAtticWallpaper(self.house.getAtticWallpaper())
        self.b_setAtticWindows(self.house.getAtticWindows())
        self.b_setDeletedItems(self.house.getDeletedItems())
Example #18
0
class DNAFurnitureReaderAI:
    notify = DirectNotifyGlobal.directNotify.newCategory(
        'DNAFurnitureReaderAI')

    def __init__(self, dnaData):
        self.dnaData = dnaData
        self.itemList = None
        return

    def buildList(self):
        self.itemList = CatalogItemList(store=CatalogItem.Customization
                                        | CatalogItem.Location)
        for i in xrange(self.dnaData.getNumChildren()):
            child = self.dnaData.at(i)
            if child.getName() == 'interior':
                interior = child
                break
        else:
            self.notify.error('Could not find "interior" in DNA!')

        for i in xrange(interior.getNumChildren()):
            child = interior.at(i)
            code = child.getCode()
            if code not in DNA2Furniture:
                self.notify.warning('Unrecognized furniture code %r!' % code)
                continue
            itemId = DNA2Furniture[code]
            if itemId is None:
                continue
            x, y, z = child.getPos()
            h, p, r = child.getHpr()
            self.itemList.append(
                CatalogFurnitureItem(itemId, posHpr=(x, y, z, h, p, r)))

        return

    def getList(self):
        if not self.itemList:
            self.buildList()
        return self.itemList

    def getBlob(self):
        return self.getList().getBlob()
    def setItems(self, items):
        items = CatalogItemList(items,
                                store=CatalogItem.Customization
                                | CatalogItem.Location)

        for item in self.items:
            item.destroy()

        self.items = []

        for item in items:
            self.generateItem(item)
Example #20
0
    def __gotHouse(self, dclass, fields):
        if dclass != self.air.dclassesByName['DistributedHouseAI']:
            return

        numItems = len(
            CatalogItemList(fields['setInteriorItems'][0],
                            store=CatalogItem.Customization)
        ) + len(
            CatalogItemList(fields['setAtticItems'][0],
                            store=CatalogItem.Customization)
        ) + len(
            CatalogItemList(
                fields['setAtticWallpaper'][0],
                store=CatalogItem.Customization)) + len(
                    CatalogItemList(
                        fields['setAtticWindows'][0],
                        store=CatalogItem.Customization)) + len(
                            CatalogItemList(
                                fields['setInteriorWallpaper'][0],
                                store=CatalogItem.Customization)) + len(
                                    CatalogItemList(
                                        fields['setInteriorWindows'][0],
                                        store=CatalogItem.Customization))
        self.sendUpdateToAvatarId(fields['setAvatarId'][0], 'setLimits',
                                  [numItems])
Example #21
0
    def requestPopularItems(self):
        # Load the current popularItems
        try:
            self.popularItemDict = simbase.backups.load('catalog',
                                                        ('popular-items', ),
                                                        default=({}))
        except ValueError:
            pass

        sortedItems = [(x, y) for y, x in sorted(
            [(y, x) for x, y in self.popularItemDict.items()], reverse=True)]

        finalItems = []
        if len(sortedItems) <= 12:
            for item in sortedItems:
                item = eval(item[0])
                finalItems.append(item)
        else:
            for i in xrange(12):
                item = eval(sortedItems[i][0])
                finalItems.append(item)

        catalog = CatalogItemList(finalItems)
        return catalog.getBlob()
    def setItems(self, items):
        # Decode the blob:
        items = CatalogItemList(items,
                                store=CatalogItem.Customization
                                | CatalogItem.Location)

        # Throw out our old items:
        for item in self.items:
            item.destroy()
        self.items = []

        for item in items:
            do = DistributedFurnitureItemAI(self.air, self, item)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)
Example #23
0
 def calcHouseItems(self, avatar):
     houseId = avatar.houseId
     
     if not houseId:
         self.notify.warning('Avatar %s has no houseId associated.' % avatar.doId)
         return 0
         
     house = simbase.air.doId2do.get(houseId)
     if not house:
         self.notify.warning('House %s (for avatar %s) not instantiated.' % (houseId, avatar.doId))
         return 0
         
     mgr = house.interior.furnitureManager
     attic = (mgr.atticItems, mgr.atticWallpaper, mgr.atticWindows)
     numHouseItems = len(CatalogItemList(house.getInteriorItems(), store=CatalogItem.Customization | CatalogItem.Location))
     numAtticItems = sum(len(x) for x in attic)
     
     return numHouseItems + numAtticItems
 def __init__(self, air):
     DistributedObjectAI.__init__(self, air)
     self.houseType = 0
     self.gardenPos = 0
     self.avatarId = 0
     self.name = ''
     self.color = 0
     self.housePos = 0
     self.gender = 1
     self.isInteriorInitialized = 1
     self.atticItems = CatalogItemList(store=Customization)
     self.interiorItems = CatalogItemList(store=Customization)
     self.interiorWallpaper = CatalogItemList(store=Customization)
     self.atticWallpaper = CatalogItemList(store=Customization)
     self.interiorWindows = CatalogItemList(store=Customization)
     self.atticWindows = CatalogItemList(store=Customization)
     self.deletedItems = CatalogItemList(store=Customization)
    def __init__(self, air):
        DistributedObjectAI.__init__(self, air)

        self.houseType = 0
        self.gardenPos = 0
        self.avatarId = 0
        self.name = ""
        self.color = 0
        self.housePos = 0
        self.gender = 1
        self.isInteriorInitialized = 1  # Only fresh DB houses are not inited.

        # FIXME: Now I think I did this wrong...
        self.atticItems = CatalogItemList(store=Customization)
        self.interiorItems = CatalogItemList(store=Customization)
        self.interiorWallpaper = CatalogItemList(store=Customization)
        self.atticWallpaper = CatalogItemList(store=Customization)
        self.interiorWindows = CatalogItemList(store=Customization)
        self.atticWindows = CatalogItemList(store=Customization)
        self.deletedItems = CatalogItemList(store=Customization)
 def setAtticItems(self, atticItems):
     self.atticItems = CatalogItemList(atticItems, store=Customization)
class DistributedHouseAI(DistributedObjectAI):
    notify = directNotify.newCategory('DistributedHouseAI')

    def __init__(self, air):
        DistributedObjectAI.__init__(self, air)

        self.houseType = 0
        self.gardenPos = 0
        self.avatarId = 0
        self.name = ''
        self.color = 0
        self.housePos = 0
        self.gender = 1
        self.isInteriorInitialized = 1
        self.gardenManager = None
        self.gardenData = ''

        self.atticItems = CatalogItemList(store=Customization)
        self.interiorItems = CatalogItemList(store=Customization)
        self.interiorWallpaper = CatalogItemList(store=Customization)
        self.atticWallpaper = CatalogItemList(store=Customization)
        self.interiorWindows = CatalogItemList(store=Customization)
        self.atticWindows = CatalogItemList(store=Customization)
        self.deletedItems = CatalogItemList(store=Customization)

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        self.interiorZone = self.air.allocateZone()

        self.door = DistributedHouseDoorAI(self.air, self.getDoId(), DoorTypes.EXT_STANDARD)
        self.door.setSwing(3)
        self.door.generateWithRequired(self.zoneId)

        self.interiorDoor = DistributedHouseDoorAI(self.air, self.getDoId(), DoorTypes.INT_STANDARD)
        self.interiorDoor.setSwing(3)
        self.interiorDoor.setOtherDoor(self.door)
        self.interiorDoor.generateWithRequired(self.interiorZone)

        self.door.setOtherDoor(self.interiorDoor)

        self.interior = DistributedHouseInteriorAI(self.air, self)
        self.interior.setHouseIndex(self.housePos)
        self.interior.setHouseId(self.getDoId())
        self.interior.generateWithRequired(self.interiorZone)

        if self.avatarId:
            self.mailbox = DistributedMailboxAI(self.air, self)
            self.mailbox.generateWithRequired(self.zoneId)

        if config.GetBool('want-gardening', False):
            self.createGardenManager()

        if not self.isInteriorInitialized:
            self.notify.info('Initializing interior...')
            self.interior.initialize()
            self.b_setInteriorInitialized(1)

        self.sendUpdate('setHouseReady', [])

    def delete(self):
        self.door.requestDelete()
        self.interiorDoor.requestDelete()
        self.interior.requestDelete()

        if self.avatarId:
            self.mailbox.requestDelete()

        if self.gardenManager is not None:
            self.gardenManager.delete()

        self.air.deallocateZone(self.interiorZone)
        DistributedObjectAI.delete(self)

    def setHousePos(self, pos):
        self.housePos = pos

    def d_setHousePos(self, pos):
        self.sendUpdate('setHousePos', [pos])

    def b_setHousePos(self, pos):
        self.setHousePos(pos)
        self.d_setHousePos(pos)

    def getHousePos(self):
        return self.housePos

    def setHouseType(self, type):
        self.houseType = type

    def d_setHouseType(self, type):
        self.sendUpdate('setHouseType', [type])

    def b_setHouseType(self, type):
        self.setHouseType(type)
        self.d_setHouseType(type)

    def getHouseType(self):
        return self.houseType

    def setGardenPos(self, pos):
        self.gardenPos = pos

    def d_setGardenPos(self, pos):
        self.sendUpdate('setGardenPos', [pos])

    def b_setGardenPos(self, pos):
        self.setGardenPos(pos)
        self.d_setGardenPos(pos)

    def getGardenPos(self):
        return self.gardenPos

    def setAvatarId(self, avId):
        self.avatarId = avId

    def d_setAvatarId(self, avId):
        self.sendUpdate('setAvatarId', [avId])

    def b_setAvatarId(self, avId):
        self.setAvatarId(avId)
        self.d_setAvatarId(avId)

    def getAvatarId(self):
        return self.avatarId

    def setName(self, name):
        self.name = name

    def d_setName(self, name):
        self.sendUpdate('setName', [name])

    def b_setName(self, name):
        self.setName(name)
        self.d_setName(name)

    def getName(self):
        return self.name

    def setColor(self, color):
        self.color = color

    def d_setColor(self, color):
        self.sendUpdate('setColor', [color])

    def b_setColor(self, color):
        self.setColor(color)
        self.d_setColor(color)

    def getColor(self):
        return self.color

    def setGender(self, genderIndex):
        self.gender = genderIndex

    def getGender(self):
        return self.gender

    def setAtticItems(self, atticItems):
        self.atticItems = CatalogItemList(atticItems, store=Customization)

    def d_setAtticItems(self, atticItems):
        self.sendUpdate('setAtticItems', [atticItems])

    def b_setAtticItems(self, atticItems):
        self.setAtticItems(atticItems)
        self.d_setAtticItems(atticItems)

    def getAtticItems(self):
        return self.atticItems.getBlob()

    def setInteriorItems(self, interiorItems):
        self.interiorItems = CatalogItemList(interiorItems, store=Customization | Location)

    def d_setInteriorItems(self, interiorItems):
        self.sendUpdate('setInteriorItems', [interiorItems])

    def b_setInteriorItems(self, interiorItems):
        self.setInteriorItems(interiorItems)
        self.d_setInteriorItems(interiorItems)

    def getInteriorItems(self):
        return self.interiorItems.getBlob()

    def setAtticWallpaper(self, atticWallpaper):
        self.atticWallpaper = CatalogItemList(atticWallpaper, store=Customization)

    def d_setAtticWallpaper(self, atticWallpaper):
        self.sendUpdate('setAtticWallpaper', [atticWallpaper])

    def b_setAtticWallpaper(self, atticWallpaper):
        self.setAtticWallpaper(atticWallpaper)
        self.d_setAtticWallpaper(atticWallpaper)

    def getAtticWallpaper(self):
        return self.atticWallpaper.getBlob()

    def setInteriorWallpaper(self, interiorWallpaper):
        self.interiorWallpaper = CatalogItemList(interiorWallpaper, store=Customization)

    def d_setInteriorWallpaper(self, interiorWallpaper):
        self.sendUpdate('setInteriorWallpaper', [interiorWallpaper])

    def b_setInteriorWallpaper(self, interiorWallpaper):
        self.setInteriorWallpaper(interiorWallpaper)
        self.d_setInteriorWallpaper(interiorWallpaper)

    def getInteriorWallpaper(self):
        return self.interiorWallpaper.getBlob()

    def setAtticWindows(self, atticWindows):
        self.atticWindows = CatalogItemList(atticWindows, store=Customization)

    def d_setAtticWindows(self, atticWindows):
        self.sendUpdate('setAtticWindows', [atticWindows])

    def b_setAtticWindows(self, atticWindows):
        self.setAtticWindows(atticWindows)
        self.d_setAtticWindows(atticWindows)

    def getAtticWindows(self):
        return self.atticWindows.getBlob()

    def setInteriorWindows(self, interiorWindows):
        self.interiorWindows = CatalogItemList(interiorWindows, store=Customization | WindowPlacement)

    def d_setInteriorWindows(self, interiorWindows):
        self.sendUpdate('setInteriorWindows', [interiorWindows])

    def b_setInteriorWindows(self, interiorWindows):
        self.setInteriorWindows(interiorWindows)
        self.d_setInteriorWindows(interiorWindows)

    def getInteriorWindows(self):
        return self.interiorWindows.getBlob()

    def setDeletedItems(self, deletedItems):
        self.deletedItems = CatalogItemList(deletedItems, store=Customization)

    def d_setDeletedItems(self, deletedItems):
        self.sendUpdate('setDeletedItems', [deletedItems])

    def b_setDeletedItems(self, deletedItems):
        self.setDeletedItems(deletedItems)
        self.d_setDeletedItems(deletedItems)

    def getDeletedItems(self):
        return self.deletedItems.getBlob()

    def setInteriorInitialized(self, initialized):
        self.isInteriorInitialized = initialized

    def d_setInteriorInitialized(self, initialized):
        self.sendUpdate('setInteriorInitialized', [initialized])

    def b_setInteriorInitialized(self, initialized):
        self.setInteriorInitialized(initialized)
        self.d_setInteriorInitialized(initialized)

    def getInteriorInitialized(self):
        return self.isInteriorInitialized

    def setCannonEnabled(self, todo0):
        pass

    def getCannonEnabled(self):
        return 0

    def setHouseReady(self):
        pass

    def addAtticItem(self, item):
        self.interior.furnitureManager.saveToHouse()
        if item.getFlags() & FLTrunk:
            self.atticItems.append(item)
        elif item.replacesExisting() and item.hasExisting():
            if item.getFlags() & FLCloset:
                closets = ClosetToClothes.keys()
                for itItem in self.interiorItems:
                    if itItem.furnitureType in closets:
                        posHpr = itItem.posHpr
                        self.interiorItems.remove(itItem)
                        item.posHpr = posHpr
                        self.interiorItems.append(item)
                        break
                for itItem in self.atticItems:
                    if itItem.furnitureType in closets:
                        self.atticItems.remove(itItem)
                        self.atticItems.append(item)
                        break
        else:
            self.atticItems.append(item)
        self.d_setAtticItems(self.atticItems.getBlob())
        self.d_setInteriorItems(self.interiorItems.getBlob())
        self.interior.furnitureManager.loadFromHouse()

    def addWindow(self, item):
        self.interior.furnitureManager.saveToHouse()
        self.atticWindows.append(item)
        self.d_setAtticWindows(self.atticWindows.getBlob())
        self.interior.furnitureManager.loadFromHouse()

    def addWallpaper(self, item):
        self.interior.furnitureManager.saveToHouse()
        self.atticWallpaper.append(item)
        self.d_setAtticWallpaper(self.atticWallpaper.getBlob())
        self.interior.furnitureManager.loadFromHouse()

    def setGardenData(self, gardenData):
        self.gardenData = gardenData

    def d_setGardenData(self, gardenData):
        self.sendUpdate('setGardenData', [gardenData])

    def b_setGardenData(self, gardenData):
        self.setGardenData(gardenData)
        self.d_setGardenData(gardenData)

    def getGardenData(self):
        return self.gardenData

    def hasGardenData(self):
        return self.gardenData != ''

    def placeStarterGarden(self):
        av = self.air.doId2do.get(self.avatarId)
        if av is None:
            return

        if av.getGardenStarted():
            self.notify.warning('Avatar %s tried to start their garden twice!' % self.avatarId)
            return

        # State that the avatar has started gardening
        av.b_setGardenStarted(1)

        # Create the GardenManagerAI
        self.gardenManager = GardenManagerAI(self.air, self)
        self.gardenManager.loadGarden()

    def createGardenManager(self):
        if not self.avatarId:
            return

        av = self.air.doId2do.get(self.avatarId)
        if av is not None:
            if av.getGardenStarted():
                self.gardenManager = GardenManagerAI(self.air, self)
                self.gardenManager.loadGarden()
            return

        def __gotOwner(dclass, fields, self=self):
            if dclass != self.air.dclassesByName['DistributedToonAI']:
                return

            gardenStarted = fields['setGardenStarted'][0]
            if gardenStarted:
                self.gardenManager = GardenManagerAI(self.air, self)
                self.gardenManager.loadGarden()

        self.air.dbInterface.queryObject(self.air.dbId, self.avatarId, __gotOwner)
class DistributedHouseAI(DistributedObjectAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedHouseAI')

    def __init__(self, air):
        DistributedObjectAI.__init__(self, air)
        self.houseType = 0
        self.gardenPos = 0
        self.avatarId = 0
        self.name = ''
        self.color = 0
        self.housePos = 0
        self.gender = 1
        self.isInteriorInitialized = 1
        self.atticItems = CatalogItemList(store=Customization)
        self.interiorItems = CatalogItemList(store=Customization)
        self.interiorWallpaper = CatalogItemList(store=Customization)
        self.atticWallpaper = CatalogItemList(store=Customization)
        self.interiorWindows = CatalogItemList(store=Customization)
        self.atticWindows = CatalogItemList(store=Customization)
        self.deletedItems = CatalogItemList(store=Customization)

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        self.interiorZone = self.air.allocateZone(owner=self.air.estateManager)
        self.door = DistributedHouseDoorAI(self.air, self.getDoId(),
                                           DoorTypes.EXT_STANDARD)
        self.door.setSwing(3)
        self.door.generateWithRequired(self.zoneId)
        self.interiorDoor = DistributedHouseDoorAI(self.air, self.getDoId(),
                                                   DoorTypes.INT_STANDARD)
        self.interiorDoor.setSwing(3)
        self.interiorDoor.setOtherDoor(self.door)
        self.interiorDoor.generateWithRequired(self.interiorZone)
        self.door.setOtherDoor(self.interiorDoor)
        self.interior = DistributedHouseInteriorAI(self.air, self)
        self.interior.setHouseIndex(self.housePos)
        self.interior.setHouseId(self.getDoId())
        self.interior.generateWithRequired(self.interiorZone)
        if self.avatarId:
            self.mailbox = DistributedMailboxAI(self.air, self)
            self.mailbox.generateWithRequired(self.zoneId)
        if not self.isInteriorInitialized:
            self.notify.info('Initializing interior...')
            self.interior.initialize()
            self.b_setInteriorInitialized(1)
        self.sendUpdate('setHouseReady', [])

    def delete(self):
        self.door.requestDelete()
        self.interiorDoor.requestDelete()
        self.interior.requestDelete()
        if self.avatarId:
            self.mailbox.requestDelete()
        self.air.deallocateZone(self.interiorZone)
        DistributedObjectAI.delete(self)

    def setHousePos(self, pos):
        self.housePos = pos

    def d_setHousePos(self, pos):
        self.sendUpdate('setHousePos', [pos])

    def b_setHousePos(self, pos):
        self.setHousePos(pos)
        self.d_setHousePos(pos)

    def getHousePos(self):
        return self.housePos

    def setHouseType(self, type):
        self.houseType = type

    def d_setHouseType(self, type):
        self.sendUpdate('setHouseType', [type])

    def b_setHouseType(self, type):
        self.setHouseType(type)
        self.d_setHouseType(type)

    def getHouseType(self):
        return self.houseType

    def setGardenPos(self, pos):
        self.gardenPos = pos

    def d_setGardenPos(self, pos):
        self.sendUpdate('setGardenPos', [pos])

    def b_setGardenPos(self, pos):
        self.setGardenPow(pos)
        self.d_setGardenPos(pos)

    def getGardenPos(self):
        return self.gardenPos

    def setAvatarId(self, avId):
        self.avatarId = avId

    def d_setAvatarId(self, avId):
        self.sendUpdate('setAvatarId', [avId])

    def b_setAvatarId(self, avId):
        self.setAvatarId(avId)
        self.d_setAvatarId(avId)

    def getAvatarId(self):
        return self.avatarId

    def setName(self, name):
        self.name = name

    def d_setName(self, name):
        self.sendUpdate('setName', [name])

    def b_setName(self, name):
        self.setName(name)
        self.d_setName(name)

    def getName(self):
        return self.name

    def setColor(self, color):
        self.color = color

    def d_setColor(self, color):
        self.sendUpdate('setColor', [color])

    def b_setColor(self, color):
        self.setColor(color)
        self.d_setColor(color)

    def getColor(self):
        return self.color

    def setGender(self, genderIndex):
        self.gender = genderIndex

    def getGender(self):
        return self.gender

    def setAtticItems(self, atticItems):
        self.atticItems = CatalogItemList(atticItems, store=Customization)

    def d_setAtticItems(self, atticItems):
        self.sendUpdate('setAtticItems', [atticItems])

    def b_setAtticItems(self, atticItems):
        self.setAtticItems(atticItems)
        self.d_setAtticItems(atticItems)

    def getAtticItems(self):
        return self.atticItems.getBlob()

    def setInteriorItems(self, interiorItems):
        self.interiorItems = CatalogItemList(interiorItems,
                                             store=Customization | Location)

    def d_setInteriorItems(self, interiorItems):
        self.sendUpdate('setInteriorItems', [interiorItems])

    def b_setInteriorItems(self, interiorItems):
        self.setInteriorItems(interiorItems)
        self.d_setInteriorItems(interiorItems)

    def getInteriorItems(self):
        return self.interiorItems.getBlob()

    def setAtticWallpaper(self, atticWallpaper):
        self.atticWallpaper = CatalogItemList(atticWallpaper,
                                              store=Customization)

    def d_setAtticWallpaper(self, atticWallpaper):
        self.sendUpdate('setAtticWallpaper', [atticWallpaper])

    def b_setAtticWallpaper(self, atticWallpaper):
        self.setAtticWallpaper(atticWallpaper)
        self.d_setAtticWallpaper(atticWallpaper)

    def getAtticWallpaper(self):
        return self.atticWallpaper.getBlob()

    def setInteriorWallpaper(self, interiorWallpaper):
        self.interiorWallpaper = CatalogItemList(interiorWallpaper,
                                                 store=Customization)

    def d_setInteriorWallpaper(self, interiorWallpaper):
        self.sendUpdate('setInteriorWallpaper', [interiorWallpaper])

    def b_setInteriorWallpaper(self, interiorWallpaper):
        self.setInteriorWallpaper(interiorWallpaper)
        self.d_setInteriorWallpaper(interiorWallpaper)

    def getInteriorWallpaper(self):
        return self.interiorWallpaper.getBlob()

    def setAtticWindows(self, atticWindows):
        self.atticWindows = CatalogItemList(atticWindows, store=Customization)

    def d_setAtticWindows(self, atticWindows):
        self.sendUpdate('setAtticWindows', [atticWindows])

    def b_setAtticWindows(self, atticWindows):
        self.setAtticWindows(atticWindows)
        self.d_setAtticWindows(atticWindows)

    def getAtticWindows(self):
        return self.atticWindows.getBlob()

    def setInteriorWindows(self, interiorWindows):
        self.interiorWindows = CatalogItemList(interiorWindows,
                                               store=Customization
                                               | WindowPlacement)

    def d_setInteriorWindows(self, interiorWindows):
        self.sendUpdate('setInteriorWindows', [interiorWindows])

    def b_setInteriorWindows(self, interiorWindows):
        self.setInteriorWindows(interiorWindows)
        self.d_setInteriorWindows(interiorWindows)

    def getInteriorWindows(self):
        return self.interiorWindows.getBlob()

    def setDeletedItems(self, deletedItems):
        self.deletedItems = CatalogItemList(deletedItems, store=Customization)

    def d_setDeletedItems(self, deletedItems):
        self.sendUpdate('setDeletedItems', [deletedItems])

    def b_setDeletedItems(self, deletedItems):
        self.setDeletedItems(deletedItems)
        self.d_setDeletedItems(deletedItems)

    def getDeletedItems(self):
        return self.deletedItems.getBlob()

    def setInteriorInitialized(self, initialized):
        self.isInteriorInitialized = initialized

    def d_setInteriorInitialized(self, initialized):
        self.sendUpdate('setInteriorInitialized', [initialized])

    def b_setInteriorInitialized(self, initialized):
        self.setInteriorInitialized(initialized)
        self.d_setInteriorInitialized(initialized)

    def getInteriorInitialized(self):
        return self.isInteriorInitialized

    def setCannonEnabled(self, todo0):
        pass

    def getCannonEnabled(self):
        return 0

    def setHouseReady(self):
        pass

    def addAtticItem(self, item):
        self.interior.furnitureManager.saveToHouse()
        if item.getFlags() & FLTrunk:
            self.atticItems.append(item)

        if item.replacesExisting() and item.hasExisting():
            if item.getFlags() & FLCloset:
                closets = ClosetToClothes.keys()
                for itItem in self.interiorItems:
                    if itItem.furnitureType in closets:
                        posHpr = itItem.posHpr
                        self.interiorItems.remove(itItem)
                        item.posHpr = posHpr
                        self.interiorItems.append(item)
                        break

                for itItem in self.atticItems:
                    if itItem.furnitureType in closets:
                        self.atticItems.remove(itItem)
                        self.atticItems.append(item)
                        break

        else:
            self.atticItems.append(item)
        self.d_setAtticItems(self.atticItems.getBlob())
        self.d_setInteriorItems(self.interiorItems.getBlob())
        self.interior.furnitureManager.loadFromHouse()

    def addWindow(self, item):
        self.interior.furnitureManager.saveToHouse()
        self.atticWindows.append(item)
        self.d_setAtticWindows(self.atticWindows.getBlob())
        self.interior.furnitureManager.loadFromHouse()

    def addWallpaper(self, item):
        self.interior.furnitureManager.saveToHouse()
        self.atticWallpaper.append(item)
        self.d_setAtticWallpaper(self.atticWallpaper.getBlob())
        self.interior.furnitureManager.loadFromHouse()
class DistributedFurnitureManagerAI(DistributedObjectAI):
    notify = DirectNotifyGlobal.directNotify.newCategory("DistributedFurnitureManagerAI")

    def __init__(self, air, house, interior):
        DistributedObjectAI.__init__(self, air)

        self.house = house
        self.interior = interior

        self.director = None

        self.ownerId = house.avatarId
        self.ownerName = house.name

        self.atticItems = None
        self.atticWallpaper = None
        self.wallpaper = None
        self.atticWindows = None
        self.windows = None
        self.deletedItems = None

        self.items = []

        # Initialize the above variables:
        self.loadFromHouse()

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        for item in self.items:
            item.generateWithRequired(self.zoneId)

    def loadFromHouse(self):
        self.b_setAtticItems(self.house.getAtticItems())
        self.b_setAtticWallpaper(self.house.getAtticWallpaper())
        self.b_setAtticWindows(self.house.getAtticWindows())
        self.b_setDeletedItems(self.house.getDeletedItems())

        self.wallpaper = CatalogItemList(self.house.getInteriorWallpaper(),
                                         store=CatalogItem.Customization)
        self.applyWallpaper()
        self.windows = CatalogItemList(self.house.getInteriorWindows(),
                                       store=CatalogItem.Customization |
                                             CatalogItem.WindowPlacement)
        self.applyWindows()

        self.setItems(self.house.getInteriorItems())

    def saveToHouse(self):
        self.house.b_setAtticItems(self.getAtticItems())
        self.house.b_setAtticWallpaper(self.getAtticWallpaper())
        self.house.b_setAtticWindows(self.getAtticWindows())
        self.house.b_setDeletedItems(self.getDeletedItems())

        self.house.b_setInteriorWallpaper(self.wallpaper.getBlob())
        self.house.b_setInteriorWindows(self.windows.getBlob())

        self.house.b_setInteriorItems(self.getItems())

    def applyWallpaper(self):
        self.interior.b_setWallpaper(self.wallpaper.getBlob())

    def applyWindows(self):
        self.interior.b_setWindows(self.windows.getBlob())

    def setItems(self, items):
        # Decode the blob:
        items = CatalogItemList(items, store=CatalogItem.Customization|CatalogItem.Location)

        # Throw out our old items:
        for item in self.items:
            item.destroy()
        self.items = []

        for item in items:
            if item.furnitureType in furnitureId2Do:
                do = furnitureId2Do[item.furnitureType](self.air, self, item, self.ownerId)
                if self.isGenerated():
                    do.generateWithRequired(self.zoneId)
                self.items.append(do)
            else:
                do = DistributedFurnitureItemAI(self.air, self, item)
                if self.isGenerated():
                    do.generateWithRequired(self.zoneId)
                self.items.append(do)

    def getItems(self):
        items = CatalogItemList(store=CatalogItem.Customization|CatalogItem.Location)

        for item in self.items:
            items.append(item.catalogItem)

        return items.getBlob()

    def setOwnerId(self, ownerId):
        self.ownerId = ownerId

    def d_setOwnerId(self, ownerId):
        self.sendUpdate('setOwnerId', [ownerId])

    def b_setOwnerId(self, ownerId):
        self.setOwnerId(ownerId)
        self.d_setOwnerId(ownerId)

    def getOwnerId(self):
        return self.ownerId

    def setOwnerName(self, ownerName):
        self.ownerName = ownerName

    def d_setOwnerName(self, ownerName):
        self.sendUpdate('setOwnerName', [ownerName])

    def b_setOwnerName(self, ownerName):
        self.setOwnerName(ownerName)
        self.d_setOwnerName(ownerName)

    def getOwnerName(self):
        return self.ownerName

    def getInteriorId(self):
        return self.interior.doId

    def setAtticItems(self, items):
        self.atticItems = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticItems(self, items):
        self.sendUpdate('setAtticItems', [items])

    def b_setAtticItems(self, items):
        self.setAtticItems(items)
        if self.isGenerated():
            self.d_setAtticItems(items)

    def getAtticItems(self):
        return self.atticItems.getBlob()

    def setAtticWallpaper(self, items):
        self.atticWallpaper = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticWallpaper(self, items):
        self.sendUpdate('setAtticWallpaper', [items])

    def b_setAtticWallpaper(self, items):
        self.setAtticWallpaper(items)
        if self.isGenerated():
            self.d_setAtticWallpaper(items)

    def getAtticWallpaper(self):
        return self.atticWallpaper.getBlob()

    def setAtticWindows(self, items):
        self.atticWindows = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticWindows(self, items):
        self.sendUpdate('setAtticWindows', [items])

    def b_setAtticWindows(self, items):
        self.setAtticWindows(items)
        if self.isGenerated():
            self.d_setAtticWindows(items)

    def getAtticWindows(self):
        return self.atticWindows.getBlob()

    def setDeletedItems(self, items):
        self.deletedItems = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setDeletedItems(self, items):
        self.sendUpdate('setDeletedItems', [items])

    def b_setDeletedItems(self, items):
        self.setDeletedItems(items)
        if self.isGenerated():
            self.d_setDeletedItems(items)

    def getDeletedItems(self):
        return self.deletedItems.getBlob()

    def suggestDirector(self, directorId):
        senderId = self.air.getAvatarIdFromSender()

        if self.ownerId != senderId:
            self.air.writeServerEvent('suspicious', senderId,
                                      'Tried to move furniture, but not the house owner!')
            return

        if senderId != directorId and directorId != 0:
            self.air.writeServerEvent('suspicious', senderId,
                                      'Tried to make someone else (%d) move their furniture!' % directorId)
            return

        director = self.air.doId2do.get(directorId)
        if directorId and not director:
            self.air.writeServerEvent('suspicious', directorId,
                                      'Tried to move furniture without being on the shard!')
            return

        if self.director:
            self.director.b_setGhostMode(0)
        if director:
            director.b_setGhostMode(1)

        self.director = director
        self.sendUpdate('setDirector', [directorId])

        # Let's also save the furniture to the house (and thus to the DB) while
        # we're at it...
        self.saveToHouse()

    def avatarEnter(self):
        pass

    def avatarExit(self):
        pass


    # Furniture-manipulation:
    def moveItemToAttic(self, doId):
        item = self.getItemObject(doId)

        self.atticItems.append(item.catalogItem)
        self.d_setAtticItems(self.getAtticItems())

        item.destroy()
        self.items.remove(item)

        return ToontownGlobals.FM_MovedItem

    def moveItemFromAttic(self, index, x, y, z, h, p, r):
        item = self.getAtticFurniture(self.atticItems, index)

        self.atticItems.remove(item)
        self.d_setAtticItems(self.getAtticItems())

        item.posHpr = (x, y, z, h, p, r)

        
        if item.furnitureType in furnitureId2Do:
            do = furnitureId2Do[item.furnitureType](self.air, self, item, self.ownerId)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)
        else:
            do = DistributedFurnitureItemAI(self.air, self, item)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)

        return (ToontownGlobals.FM_MovedItem, do.doId)

    def deleteItemFromAttic(self, blob, index):
        pass

    def deleteItemFromRoom(self, blob, doId):
        pass

    def moveWallpaperFromAttic(self, index, room):
        pass

    def deleteWallpaperFromAttic(self, blob, index):
        pass

    def moveWindowToAttic(self, slot):
        window = self.getWindow(slot)
        if window is None:
            return ToontownGlobals.FM_InvalidIndex

        self.windows.remove(window)
        self.applyWindows()
        self.atticWindows.append(window)
        self.d_setAtticWindows(self.getAtticWindows())

        return ToontownGlobals.FM_MovedItem

    def moveWindowFromAttic(self, index, slot):
        retcode = ToontownGlobals.FM_MovedItem

        window = self.getAtticFurniture(self.atticWindows, index)

        if slot > 5:
            # This is not a valid slot! HACKER!!!
            self.air.writeServerEvent('suspicious', self.air.getAvatarIdFromSender(),
                                      'Tried to move window to invalid slot %d!' % slot)
            return ToontownGlobals.FM_HouseFull

        if self.getWindow(slot):
            # Already a window there, swap 'er out.
            self.moveWindowToAttic(slot)
            retcode = ToontownGlobals.FM_SwappedItem

        self.atticWindows.remove(window)
        self.d_setAtticWindows(self.getAtticWindows())
        window.placement = slot
        self.windows.append(window)
        self.applyWindows()

        return retcode

    def moveWindow(self, fromSlot, toSlot):
        retcode = ToontownGlobals.FM_MovedItem

        window = self.getWindow(fromSlot)
        if window is None:
            return ToontownGlobals.FM_InvalidIndex

        if toSlot > 5:
            # This is not a valid slot! HACKER!!!
            self.air.writeServerEvent('suspicious', self.air.getAvatarIdFromSender(),
                                      'Tried to move window to invalid slot %d!' % toSlot)
            return ToontownGlobals.FM_HouseFull

        if self.getWindow(toSlot):
            # Already a window there, swap 'er out.
            self.moveWindowToAttic(toSlot)
            retcode = ToontownGlobals.FM_SwappedItem

        window.placement = toSlot
        self.applyWindows()

        return retcode

    def deleteWindowFromAttic(self, blob, index):
        pass

    def recoverDeletedItem(self, blob, index):
        pass

    # Network handlers for the above:
    def handleMessage(self, func, response, *args):
        context = args[-1]
        args = args[:-1]

        senderId = self.air.getAvatarIdFromSender()
        if not self.director or senderId != self.director.doId:
            self.air.writeServerEvent('suspicious', senderId,
                                      'Sent furniture management request without'
                                      ' being the director.')
            retval = ToontownGlobals.FM_NotDirector
        else:
            try:
                retval = func(*args) or 0
            except FurnitureError as e:
                retval = e.code

        if response == 'moveItemFromAtticResponse':
            # This message actually includes a doId; we split the retval apart
            # if it's a tuple, otherwise it falls back to 0.
            if type(retval) == tuple:
                retval, doId = retval
            else:
                doId = 0

            # Brief delay; this is to give the State Server time to finish
            # processing the new furniture item appearing before we hit the
            # client with the doId:
            taskMgr.doMethodLater(5, self.sendUpdateToAvatarId,
                                  self.uniqueName('send-attic-response'),
                                  extraArgs=[senderId, response, [retval, doId, context]])
        else:
            self.sendUpdateToAvatarId(senderId, response, [retval, context])

    def moveItemToAtticMessage(self, doId, context):
        self.handleMessage(self.moveItemToAttic, 'moveItemToAtticResponse', doId, context)

    def moveItemFromAtticMessage(self, index, x, y, z, h, p, r, context):
        self.handleMessage(self.moveItemFromAttic, 'moveItemFromAtticResponse',
                           index, x, y, z, h, p, r, context)

    def deleteItemFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteItemFromAttic, 'deleteItemFromAtticResponse', blob, index, context)

    def deleteItemFromRoomMessage(self, blob, doId, context):
        self.handleMessage(self.deleteItemFromRoom, 'deleteItemFromRoomResponse', blob, doId, context)

    def moveWallpaperFromAtticMessage(self, index, room, context):
        self.handleMessage(self.moveWallpaperFromAttic, 'moveWallpaperFromAtticResponse', index, room, context)

    def deleteWallpaperFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteWallpaperFromAttic, 'deleteWallpaperFromAtticResponse', blob, index, context)

    def moveWindowToAtticMessage(self, slot, context):
        self.handleMessage(self.moveWindowToAttic, 'moveWindowToAtticResponse', slot, context)

    def moveWindowFromAtticMessage(self, index, slot, context):
        self.handleMessage(self.moveWindowFromAttic, 'moveWindowFromAtticResponse', index, slot, context)

    def moveWindowMessage(self, fromSlot, toSlot, context):
        self.handleMessage(self.moveWindow, 'moveWindowResponse', fromSlot, toSlot, context)

    def deleteWindowFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteWindowFromAttic, 'deleteWindowFromAtticResponse', blob, index, context)

    def recoverDeletedItemMessage(self, blob, index, context):
        self.handleMessage(self.recoverDeletedItem, 'recoverDeletedItemResponse', blob, index, context)

    # Functions to safely process data off the wire:
    def getItemObject(self, doId):
        item = self.air.doId2do.get(doId)

        if item is None:
            raise FurnitureError(ToontownGlobals.FM_InvalidItem)

        if item not in self.items:
            raise FurnitureError(ToontownGlobals.FM_InvalidItem)

        return item

    def getAtticFurniture(self, attic, index):
        if index >= len(attic):
            raise FurnitureError(ToontownGlobals.FM_InvalidIndex)

        return attic[index]

    def getWindow(self, slot):
        for window in self.windows:
            if window.placement == slot:
                return window

        return None
class DistributedFurnitureManagerAI(DistributedObjectAI):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedFurnitureManagerAI')

    def __init__(self, air, house, interior):
        DistributedObjectAI.__init__(self, air)
        self.house = house
        self.interior = interior
        self.director = None
        self.ownerId = house.avatarId
        self.ownerName = house.name
        self.avId = None
        self.atticItems = None
        self.atticWallpaper = None
        self.wallpaper = None
        self.atticWindows = None
        self.windows = None
        self.deletedItems = None
        self.items = []
        self.loadFromHouse()

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        for item in self.items:
            item.generateWithRequired(self.zoneId)

    def delete(self):
        for item in self.items:
            item.destroy()

        DistributedObjectAI.delete(self)

    def loadFromHouse(self):
        self.b_setAtticItems(self.house.getAtticItems())
        self.b_setAtticWallpaper(self.house.getAtticWallpaper())
        self.b_setAtticWindows(self.house.getAtticWindows())
        self.b_setDeletedItems(self.house.getDeletedItems())
        self.wallpaper = CatalogItemList(self.house.getInteriorWallpaper(), store=CatalogItem.Customization)
        self.applyWallpaper()
        self.windows = CatalogItemList(self.house.getInteriorWindows(), store=CatalogItem.Customization | CatalogItem.WindowPlacement)
        self.applyWindows()
        self.setItems(self.house.getInteriorItems())

    def saveToHouse(self):
        self.house.b_setAtticItems(self.getAtticItems())
        self.house.b_setAtticWallpaper(self.getAtticWallpaper())
        self.house.b_setAtticWindows(self.getAtticWindows())
        self.house.b_setDeletedItems(self.getDeletedItems())
        self.house.b_setInteriorWallpaper(self.wallpaper.getBlob())
        self.house.b_setInteriorWindows(self.windows.getBlob())
        self.house.b_setInteriorItems(self.getItems())

    def applyWallpaper(self):
        self.interior.b_setWallpaper(self.wallpaper.getBlob())

    def applyWindows(self):
        self.interior.b_setWindows(self.windows.getBlob())

    def setItems(self, items):
        items = CatalogItemList(items, store=CatalogItem.Customization | CatalogItem.Location)
        for item in self.items:
            item.destroy()

        self.items = []
        for item in items:
            if item.getHashContents() in (1300, 1310, 1320, 1330, 1340, 1350):
                do = DistributedBankAI(self.air, self, item)
            elif 500 <= item.getHashContents() <= 518:
                do = DistributedClosetAI(self.air, self, item)
                do.setOwnerId(self.avId)
            elif item.getHashContents() == 1399:
                do = DistributedPhoneAI(self.air, self, item)
            elif item.getHashContents() in (4000, 4010):
                do = DistributedTrunkAI(self.air, self, item)
                do.setOwnerId(self.avId)
            else:
                do = DistributedFurnitureItemAI(self.air, self, item)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)

    def getItems(self):
        items = CatalogItemList(store=CatalogItem.Customization | CatalogItem.Location)
        for item in self.items:
            items.append(item.catalogItem)

        return items.getBlob()

    def setOwnerId(self, ownerId):
        self.ownerId = ownerId

    def d_setOwnerId(self, ownerId):
        self.sendUpdate('setOwnerId', [ownerId])

    def b_setOwnerId(self, ownerId):
        self.setOwnerId(ownerId)
        self.d_setOwnerId(ownerId)

    def getOwnerId(self):
        return self.ownerId

    def setOwnerName(self, ownerName):
        self.ownerName = ownerName

    def d_setOwnerName(self, ownerName):
        self.sendUpdate('setOwnerName', [ownerName])

    def b_setOwnerName(self, ownerName):
        self.setOwnerName(ownerName)
        self.d_setOwnerName(ownerName)

    def getOwnerName(self):
        return self.ownerName

    def getInteriorId(self):
        return self.interior.doId

    def setAtticItems(self, items):
        self.atticItems = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticItems(self, items):
        self.sendUpdate('setAtticItems', [items])

    def b_setAtticItems(self, items):
        self.setAtticItems(items)
        if self.isGenerated():
            self.d_setAtticItems(items)

    def getAtticItems(self):
        return self.atticItems.getBlob()

    def setAtticWallpaper(self, items):
        self.atticWallpaper = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticWallpaper(self, items):
        self.sendUpdate('setAtticWallpaper', [items])

    def b_setAtticWallpaper(self, items):
        self.setAtticWallpaper(items)
        if self.isGenerated():
            self.d_setAtticWallpaper(items)

    def getAtticWallpaper(self):
        return self.atticWallpaper.getBlob()

    def setAtticWindows(self, items):
        self.atticWindows = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticWindows(self, items):
        self.sendUpdate('setAtticWindows', [items])

    def b_setAtticWindows(self, items):
        self.setAtticWindows(items)
        if self.isGenerated():
            self.d_setAtticWindows(items)

    def getAtticWindows(self):
        return self.atticWindows.getBlob()

    def setDeletedItems(self, items):
        self.deletedItems = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setDeletedItems(self, items):
        self.sendUpdate('setDeletedItems', [items])

    def b_setDeletedItems(self, items):
        self.setDeletedItems(items)
        if self.isGenerated():
            self.d_setDeletedItems(items)

    def getDeletedItems(self):
        return self.deletedItems.getBlob()

    def suggestDirector(self, directorId):
        senderId = self.air.getAvatarIdFromSender()
        if self.ownerId != senderId:
            self.air.writeServerEvent('suspicious', avId=senderId, issue='Tried to move furniture, but not the house owner!')
            return
        if senderId != directorId and directorId != 0:
            self.air.writeServerEvent('suspicious', avId=senderId, issue='Tried to make someone else (%d) move their furniture!' % directorId)
            return
        director = self.air.doId2do.get(directorId)
        if directorId and not director:
            self.air.writeServerEvent('suspicious', avId=directorId, issue='Tried to move furniture without being on the shard!')
            return
        if self.director:
            self.director.b_setGhostMode(0)
        if director:
            if director.zoneId != self.zoneId:
                self.air.writeServerEvent('suspicious', avId=directorId, issue='Tried to become director from another zone!')
                return
            director.b_setGhostMode(1)
        self.director = director
        self.sendUpdate('setDirector', [directorId])
        self.saveToHouse()

    def avatarEnter(self):
        pass

    def avatarExit(self):
        pass

    def moveItemToAttic(self, doId):
        item = self.getItemObject(doId)
        self.atticItems.append(item.catalogItem)
        self.d_setAtticItems(self.getAtticItems())
        item.destroy()
        self.items.remove(item)
        return ToontownGlobals.FM_MovedItem

    def moveItemFromAttic(self, index, x, y, z, h, p, r):
        item = self.getAtticFurniture(self.atticItems, index)
        self.atticItems.remove(item)
        self.d_setAtticItems(self.getAtticItems())
        item.posHpr = (x,
         y,
         z,
         h,
         p,
         r)
        if item.getFlags() & FLTrunk:
            if self.house.gender is 0:
                if item.furnitureType - 4000 < 10:
                    item.furnitureType += 10
            elif item.furnitureType - 4000 > 10:
                item.furnitureType -= 10
            do = DistributedTrunkAI(self.air, self, item)
        elif item.getFlags() & FLCloset:
            if self.house.gender is 0:
                if item.furnitureType - 500 < 10:
                    item.furnitureType += 10
            elif item.furnitureType - 500 > 10:
                item.furnitureType -= 10
            do = DistributedClosetAI(self.air, self, item)
        elif item.getFlags() & FLBank:
            do = DistributedBankAI(self.air, self, item)
        elif item.getFlags() & FLPhone:
            do = DistributedPhoneAI(self.air, self, item)
        else:
            do = DistributedFurnitureItemAI(self.air, self, item)

        do.generateWithRequired(self.zoneId)
        self.items.append(do)
        return ToontownGlobals.FM_MovedItem, do.doId

    def deleteItemFromAttic(self, blob, index):
        item = self.getAtticFurniture(self.atticItems, index)
        if item is None:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Tried to delete an invalid item at index %s' % index)
            return ToontownGlobals.FM_InvalidIndex
        self.atticItems.remove(item)
        self.d_setAtticItems(self.getAtticItems())
        return ToontownGlobals.FM_DeletedItem

    def deleteItemFromRoom(self, blob, doId):
        pass

    def moveWallpaperFromAttic(self, index, room):
        retcode = ToontownGlobals.FM_SwappedItem
        wallpaper = self.getAtticFurniture(self.atticWallpaper, index)
        if wallpaper is None:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Invalid wallpaper at index %s' % index)
            return ToontownGlobals.FM_InvalidIndex
        if room > 1:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Tried to apply a wallpaper in an invalid room %d!' % room)
            return ToontownGlobals.FM_InvalidItem
        interiorIndex = room * 4
        if isinstance(wallpaper, CatalogMouldingItem):
            interiorIndex += 1
        elif isinstance(wallpaper, CatalogFlooringItem):
            interiorIndex += 2
        elif isinstance(wallpaper, CatalogWainscotingItem):
            interiorIndex += 3
        atticIndex = self.atticWallpaper.index(wallpaper)
        self.atticWallpaper[atticIndex] = self.wallpaper[interiorIndex]
        self.d_setAtticWallpaper(self.getAtticWallpaper())
        self.wallpaper[interiorIndex] = wallpaper
        self.applyWallpaper()
        return retcode

    def deleteWallpaperFromAttic(self, blob, index):
        wallpaper = self.getAtticFurniture(self.atticWallpaper, index)
        self.atticWallpaper.remove(wallpaper)
        self.b_setAtticWallpaper(self.getAtticWallpaper())

    def moveWindowToAttic(self, slot):
        window = self.getWindow(slot)
        if window is None:
            return ToontownGlobals.FM_InvalidIndex
        self.windows.remove(window)
        self.applyWindows()
        self.atticWindows.append(window)
        self.d_setAtticWindows(self.getAtticWindows())
        return ToontownGlobals.FM_MovedItem

    def moveWindowFromAttic(self, index, slot):
        retcode = ToontownGlobals.FM_MovedItem
        window = self.getAtticFurniture(self.atticWindows, index)
        if slot > 5:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Tried to move window to invalid slot %d!' % slot)
            return ToontownGlobals.FM_HouseFull
        if self.getWindow(slot):
            self.moveWindowToAttic(slot)
            retcode = ToontownGlobals.FM_SwappedItem
        self.atticWindows.remove(window)
        self.d_setAtticWindows(self.getAtticWindows())
        window.placement = slot
        self.windows.append(window)
        self.applyWindows()
        return retcode

    def moveWindow(self, fromSlot, toSlot):
        retcode = ToontownGlobals.FM_MovedItem
        window = self.getWindow(fromSlot)
        if window is None:
            return ToontownGlobals.FM_InvalidIndex
        if toSlot > 5:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='DistributedfTried to move window to invalid slot %d!' % toSlot)
            return ToontownGlobals.FM_HouseFull
        if self.getWindow(toSlot):
            self.moveWindowToAttic(toSlot)
            retcode = ToontownGlobals.FM_SwappedItem
        window.placement = toSlot
        self.applyWindows()
        return retcode

    def deleteWindowFromAttic(self, blob, index):
        window = self.getAtticFurniture(self.atticWindows, index)
        if window is None:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Tried to delete an invalid window at index %s' % index)
            return ToontownGlobals.FM_InvalidIndex
        self.atticWindows.remove(window)
        self.d_setAtticWindows(self.getAtticWindows())
        return ToontownGlobals.FM_DeletedItem

    def recoverDeletedItem(self, blob, index):
        pass

    def handleMessage(self, func, response, *args):
        context = args[-1]
        args = args[:-1]
        senderId = self.air.getAvatarIdFromSender()
        if not self.director or senderId != self.director.doId:
            self.air.writeServerEvent('suspicious', avId=senderId, issue='Sent furniture management request without being the director.')
            retval = ToontownGlobals.FM_NotDirector
        else:
            try:
                retval = func(*args) or 0
            except FurnitureError as e:
                retval = e.code

        if response == 'moveItemFromAtticResponse':
            if type(retval) == tuple:
                retval, doId = retval
            else:
                doId = 0
            taskMgr.doMethodLater(1, self.sendUpdateToAvatarId, self.uniqueName('send-attic-response'), extraArgs=[senderId, response, [retval, doId, context]])
        else:
            self.sendUpdateToAvatarId(senderId, response, [retval, context])

    def moveItemToAtticMessage(self, doId, context):
        self.handleMessage(self.moveItemToAttic, 'moveItemToAtticResponse', doId, context)

    def moveItemFromAtticMessage(self, index, x, y, z, h, p, r, context):
        self.handleMessage(self.moveItemFromAttic, 'moveItemFromAtticResponse', index, x, y, z, h, p, r, context)

    def deleteItemFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteItemFromAttic, 'deleteItemFromAtticResponse', blob, index, context)

    def deleteItemFromRoomMessage(self, blob, doId, context):
        self.handleMessage(self.deleteItemFromRoom, 'deleteItemFromRoomResponse', blob, doId, context)

    def moveWallpaperFromAtticMessage(self, index, room, context):
        self.handleMessage(self.moveWallpaperFromAttic, 'moveWallpaperFromAtticResponse', index, room, context)

    def deleteWallpaperFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteWallpaperFromAttic, 'deleteWallpaperFromAtticResponse', blob, index, context)

    def moveWindowToAtticMessage(self, slot, context):
        self.handleMessage(self.moveWindowToAttic, 'moveWindowToAtticResponse', slot, context)

    def moveWindowFromAtticMessage(self, index, slot, context):
        self.handleMessage(self.moveWindowFromAttic, 'moveWindowFromAtticResponse', index, slot, context)

    def moveWindowMessage(self, fromSlot, toSlot, context):
        self.handleMessage(self.moveWindow, 'moveWindowResponse', fromSlot, toSlot, context)

    def deleteWindowFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteWindowFromAttic, 'deleteWindowFromAtticResponse', blob, index, context)

    def recoverDeletedItemMessage(self, blob, index, context):
        self.handleMessage(self.recoverDeletedItem, 'recoverDeletedItemResponse', blob, index, context)

    def getItemObject(self, doId):
        item = self.air.doId2do.get(doId)
        if item is None:
            raise FurnitureError(ToontownGlobals.FM_InvalidItem)
        if item not in self.items:
            raise FurnitureError(ToontownGlobals.FM_InvalidItem)
        return item

    def getAtticFurniture(self, attic, index):
        if index >= len(attic):
            raise FurnitureError(ToontownGlobals.FM_InvalidIndex)
        return attic[index]

    def getWindow(self, slot):
        for window in self.windows:
            if window.placement == slot:
                return window
 def setAtticWallpaper(self, atticWallpaper):
     self.atticWallpaper = CatalogItemList(atticWallpaper,
                                           store=Customization)
 def setAtticItems(self, atticItems):
     self.atticItems = CatalogItemList(atticItems, store=Customization)
 def setAtticWindows(self, atticWindows):
     self.atticWindows = CatalogItemList(atticWindows, store=Customization)
 def setAtticWallpaper(self, items):
     self.atticWallpaper = CatalogItemList(items,
                                           store=CatalogItem.Customization)
 def setAtticWindows(self, atticWindows):
     self.atticWindows = CatalogItemList(atticWindows, store=Customization)
 def setInteriorWindows(self, interiorWindows):
     self.interiorWindows = CatalogItemList(interiorWindows, store=Customization | WindowPlacement)
 def setInteriorWallpaper(self, interiorWallpaper):
     self.interiorWallpaper = CatalogItemList(interiorWallpaper, store=Customization)
 def setAtticWallpaper(self, atticWallpaper):
     self.atticWallpaper = CatalogItemList(atticWallpaper, store=Customization)
 def setInteriorItems(self, interiorItems):
     self.interiorItems = CatalogItemList(interiorItems, store=Customization | Location)
 def __init__(self, air):
     DistributedObjectAI.__init__(self, air)
     self.houseType = 0
     self.gardenPos = 0
     self.avatarId = 0
     self.name = ''
     self.color = 0
     self.housePos = 0
     self.gender = 1
     self.isInteriorInitialized = 1
     self.atticItems = CatalogItemList(store=Customization)
     self.interiorItems = CatalogItemList(store=Customization)
     self.interiorWallpaper = CatalogItemList(store=Customization)
     self.atticWallpaper = CatalogItemList(store=Customization)
     self.interiorWindows = CatalogItemList(store=Customization)
     self.atticWindows = CatalogItemList(store=Customization)
     self.deletedItems = CatalogItemList(store=Customization)
class DistributedFurnitureManagerAI(DistributedObjectAI):
    notify = directNotify.newCategory("DistributedFurnitureManagerAI")

    def __init__(self, air, house, interior):
        DistributedObjectAI.__init__(self, air)

        self.house = house
        self.interior = interior

        self.director = None

        self.ownerId = house.avatarId
        self.ownerName = house.name

        self.atticItems = None
        self.atticWallpaper = None
        self.wallpaper = None
        self.atticWindows = None
        self.windows = None
        self.deletedItems = None

        self.items = []

        # Initialize the above variables:
        self.loadFromHouse()

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)

        for item in self.items:
            item.generateWithRequired(self.zoneId)

    def delete(self):
        for item in self.items:
            item.destroy()

        DistributedObjectAI.delete(self)

    def loadFromHouse(self):
        self.b_setAtticItems(self.house.getAtticItems())
        self.b_setAtticWallpaper(self.house.getAtticWallpaper())
        self.b_setAtticWindows(self.house.getAtticWindows())
        self.b_setDeletedItems(self.house.getDeletedItems())

        self.wallpaper = CatalogItemList(self.house.getInteriorWallpaper(),
                                         store=CatalogItem.Customization)
        self.applyWallpaper()
        self.windows = CatalogItemList(self.house.getInteriorWindows(),
                                       store=CatalogItem.Customization |
                                             CatalogItem.WindowPlacement)
        self.applyWindows()

        self.setItems(self.house.getInteriorItems())

    def saveToHouse(self):
        self.house.b_setAtticItems(self.getAtticItems())
        self.house.b_setAtticWallpaper(self.getAtticWallpaper())
        self.house.b_setAtticWindows(self.getAtticWindows())
        self.house.b_setDeletedItems(self.getDeletedItems())

        self.house.b_setInteriorWallpaper(self.wallpaper.getBlob())
        self.house.b_setInteriorWindows(self.windows.getBlob())

        self.house.b_setInteriorItems(self.getItems())

    def applyWallpaper(self):
        self.interior.b_setWallpaper(self.wallpaper.getBlob())

    def applyWindows(self):
        self.interior.b_setWindows(self.windows.getBlob())

    def setItems(self, items):
        # Decode the blob:
        items = CatalogItemList(items, store=CatalogItem.Customization|CatalogItem.Location)

        # Throw out our old items:
        for item in self.items:
            item.destroy()
        self.items = []

        items.removeDuplicates(FLCloset)

        # Due to a bug, some people are missing their closets...
        hasCloset = False
        for item in items:
            if item.getFlags() & FLCloset:
                hasCloset = True
                break

        if not hasCloset:
            item = CatalogFurnitureItem(500)  # the basic closet...
            item.posHpr = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
            items.append(item)
            # Since we have modified the items list, should we save it back to the house?

        for item in items:
            if item.getFlags() & FLTrunk:
                if self.house.gender is 0:
                    if item.furnitureType - 4000 < 10:
                        item.furnitureType += 10
                elif item.furnitureType - 4000 > 10:
                    item.furnitureType -= 10
                do = DistributedTrunkAI(self.air, self, item)
            elif item.getFlags() & FLCloset:
                if self.house.gender is 0:
                    if item.furnitureType - 500 < 10:
                        item.furnitureType += 10
                elif item.furnitureType - 500 > 10:
                    item.furnitureType -= 10
                do = DistributedClosetAI(self.air, self, item)
            elif item.getFlags() & FLBank:
                continue # We dont want banks in the estates.
            elif item.getFlags() & FLPhone:
                do = DistributedPhoneAI(self.air, self, item)
            else:
                do = DistributedFurnitureItemAI(self.air, self, item)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)

    def getItems(self):
        items = CatalogItemList(store=CatalogItem.Customization|CatalogItem.Location)

        for item in self.items:
            items.append(item.catalogItem)

        return items.getBlob()

    def setOwnerId(self, ownerId):
        self.ownerId = ownerId

    def d_setOwnerId(self, ownerId):
        self.sendUpdate('setOwnerId', [ownerId])

    def b_setOwnerId(self, ownerId):
        self.setOwnerId(ownerId)
        self.d_setOwnerId(ownerId)

    def getOwnerId(self):
        return self.ownerId

    def setOwnerName(self, ownerName):
        self.ownerName = ownerName

    def d_setOwnerName(self, ownerName):
        self.sendUpdate('setOwnerName', [ownerName])

    def b_setOwnerName(self, ownerName):
        self.setOwnerName(ownerName)
        self.d_setOwnerName(ownerName)

    def getOwnerName(self):
        return self.ownerName

    def getInteriorId(self):
        return self.interior.doId

    def setAtticItems(self, items):
        self.atticItems = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticItems(self, items):
        self.sendUpdate('setAtticItems', [items])

    def b_setAtticItems(self, items):
        self.setAtticItems(items)
        if self.isGenerated():
            self.d_setAtticItems(items)

    def getAtticItems(self):
        return self.atticItems.getBlob()

    def setAtticWallpaper(self, items):
        self.atticWallpaper = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticWallpaper(self, items):
        self.sendUpdate('setAtticWallpaper', [items])

    def b_setAtticWallpaper(self, items):
        self.setAtticWallpaper(items)
        if self.isGenerated():
            self.d_setAtticWallpaper(items)

    def getAtticWallpaper(self):
        return self.atticWallpaper.getBlob()

    def setAtticWindows(self, items):
        self.atticWindows = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setAtticWindows(self, items):
        self.sendUpdate('setAtticWindows', [items])

    def b_setAtticWindows(self, items):
        self.setAtticWindows(items)
        if self.isGenerated():
            self.d_setAtticWindows(items)

    def getAtticWindows(self):
        return self.atticWindows.getBlob()

    def setDeletedItems(self, items):
        self.deletedItems = CatalogItemList(items, store=CatalogItem.Customization)

    def d_setDeletedItems(self, items):
        self.sendUpdate('setDeletedItems', [items])

    def b_setDeletedItems(self, items):
        self.setDeletedItems(items)
        if self.isGenerated():
            self.d_setDeletedItems(items)

    def getDeletedItems(self):
        return self.deletedItems.getBlob()

    def suggestDirector(self, directorId):
        senderId = self.air.getAvatarIdFromSender()

        if self.ownerId != senderId:
            self.air.writeServerEvent('suspicious', avId=senderId, issue='Tried to move furniture, but not the house owner!')
            return

        if senderId != directorId and directorId != 0:
            self.air.writeServerEvent('suspicious', avId=senderId, issue='Tried to make someone else (%d) move their furniture!' % directorId)
            return

        director = self.air.doId2do.get(directorId)
        if directorId and not director:
            self.air.writeServerEvent('suspicious', avId=directorId, issue='Tried to move furniture without being on the shard!')
            return

        if self.director:
            self.director.b_setGhostMode(0)
        if director:
            if director.zoneId != self.zoneId:
                self.air.writeServerEvent('suspicious', avId=directorId, issue='Tried to become director from another zone!')
                return
            director.b_setGhostMode(1)

        self.director = director
        self.sendUpdate('setDirector', [directorId])

        # Let's also save the furniture to the house (and thus to the DB) while
        # we're at it...
        self.saveToHouse()

    def avatarEnter(self):
        pass

    def avatarExit(self):
        pass

    # Furniture-manipulation:
    def moveItemToAttic(self, doId):
        item = self.getItemObject(doId)

        self.atticItems.append(item.catalogItem)
        self.d_setAtticItems(self.getAtticItems())

        item.destroy()
        self.items.remove(item)

        return ToontownGlobals.FM_MovedItem

    def moveItemFromAttic(self, index, x, y, z, h, p, r):
        item = self.getAtticFurniture(self.atticItems, index)

        self.atticItems.remove(item)
        self.d_setAtticItems(self.getAtticItems())

        item.posHpr = (x, y, z, h, p, r)

        if item.getFlags() & FLTrunk:
            if self.house.gender is 0:
                if item.furnitureType - 4000 < 10:
                    item.furnitureType += 10
            elif item.furnitureType - 4000 > 10:
                item.furnitureType -= 10
            do = DistributedTrunkAI(self.air, self, item)
        elif item.getFlags() & FLCloset:
            if self.house.gender is 0:
                if item.furnitureType - 500 < 10:
                    item.furnitureType += 10
            elif item.furnitureType - 500 > 10:
                item.furnitureType -= 10
            do = DistributedClosetAI(self.air, self, item)
        elif item.getFlags() & FLBank:
            pass # We don't want banks in the estates
        elif item.getFlags() & FLPhone:
            do = DistributedPhoneAI(self.air, self, item)
        else:
            do = DistributedFurnitureItemAI(self.air, self, item)

        do.generateWithRequired(self.zoneId)
        self.items.append(do)

        return (ToontownGlobals.FM_MovedItem, do.doId)

    def deleteItemFromAttic(self, blob, index):
        item = self.getAtticFurniture(self.atticItems, index)
        if item is None:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Tried to delete an invalid item at index %s' % index)
            return ToontownGlobals.FM_InvalidIndex

        self.atticItems.remove(item)
        self.d_setAtticItems(self.getAtticItems())

        return ToontownGlobals.FM_DeletedItem

    def deleteItemFromRoom(self, blob, doId):
        pass

    def moveWallpaperFromAttic(self, index, room):
        return ToontownGlobals.FM_InvalidIndex

        retcode = ToontownGlobals.FM_SwappedItem
        wallpaper = self.getAtticFurniture(self.atticWallpaper, index)
        if wallpaper is None:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Invalid wallpaper at index %s' % index)
            return ToontownGlobals.FM_InvalidIndex
        if room > 1:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Tried to apply a wallpaper in an invalid room %d!' % room)
            return ToontownGlobals.FM_InvalidItem
        interiorIndex = room + wallpaper.getSurfaceType()
        interiorIndex += wallpaper.getSurfaceType() - 1
        print room
        print interiorIndex
        atticIndex = self.atticWallpaper.index(wallpaper)
        self.atticWallpaper[atticIndex] = self.wallpaper[interiorIndex]
        self.d_setAtticWallpaper(self.getAtticWallpaper())
        self.wallpaper[interiorIndex] = wallpaper
        self.applyWallpaper()
        return retcode

    def deleteWallpaperFromAttic(self, blob, index):
        return # TODO

        wallpaper = self.getAtticFurniture(blob, index)
        self.atticWallpaper.remove(wallpaper)
        self.b_setAtticWallpaper(self.getAtticWallpaper())

    def moveWindowToAttic(self, slot):
        window = self.getWindow(slot)
        if window is None:
            return ToontownGlobals.FM_InvalidIndex
        self.windows.remove(window)
        self.applyWindows()
        self.atticWindows.append(window)
        self.d_setAtticWindows(self.getAtticWindows())
        return ToontownGlobals.FM_MovedItem

    def moveWindowFromAttic(self, index, slot):
        retcode = ToontownGlobals.FM_MovedItem
        window = self.getAtticFurniture(self.atticWindows, index)
        if slot > 5:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(),
                                      issue='Tried to move window to invalid slot %d!' % slot)
            return ToontownGlobals.FM_HouseFull
        if self.getWindow(slot):
            self.moveWindowToAttic(slot)
            retcode = ToontownGlobals.FM_SwappedItem
        self.atticWindows.remove(window)
        self.d_setAtticWindows(self.getAtticWindows())
        window.placement = slot
        self.windows.append(window)
        self.applyWindows()
        return retcode

    def moveWindow(self, fromSlot, toSlot):
        retcode = ToontownGlobals.FM_MovedItem
        window = self.getWindow(fromSlot)
        if window is None:
            return ToontownGlobals.FM_InvalidIndex
        if toSlot > 5:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(),
                                      issue='DistributedfTried to move window to invalid slot %d!' % toSlot)
            return ToontownGlobals.FM_HouseFull
        if self.getWindow(toSlot):
            self.moveWindowToAttic(toSlot)
            retcode = ToontownGlobals.FM_SwappedItem
        window.placement = toSlot
        self.applyWindows()
        return retcode

    def deleteWindowFromAttic(self, blob, index):
        window = self.getAtticFurniture(self.atticWindows, index)
        if window is None:
            self.air.writeServerEvent('suspicious', avId=self.air.getAvatarIdFromSender(), issue='Tried to delete an invalid window at index %s' % index)
            return ToontownGlobals.FM_InvalidIndex
        self.atticWindows.remove(window)
        self.d_setAtticWindows(self.getAtticWindows())
        return ToontownGlobals.FM_DeletedItem

    def recoverDeletedItem(self, blob, index):
        pass


    def handleMessage(self, func, response, *args):
        context = args[-1]
        args = args[:-1]
        senderId = self.air.getAvatarIdFromSender()
        if not self.director or senderId != self.director.doId:
            self.air.writeServerEvent('suspicious', avId=senderId,
                                      issue='Sent furniture management request without'
                                      ' being the director.')
            retval = ToontownGlobals.FM_NotDirector
        else:
            try:
                retval = func(*args) or 0
            except FurnitureError as e:
                retval = e.code
        if response == 'moveItemFromAtticResponse':
            if type(retval) == tuple:
                retval, doId = retval
            else:
                doId = 0
            taskMgr.doMethodLater(1, self.sendUpdateToAvatarId,
                                  self.uniqueName('send-attic-response'),
                                  extraArgs=[senderId, response, [retval, doId, context]])
        else:
            self.sendUpdateToAvatarId(senderId, response, [retval, context])

    def moveItemToAtticMessage(self, doId, context):
        self.handleMessage(self.moveItemToAttic, 'moveItemToAtticResponse', doId, context)

    def moveItemFromAtticMessage(self, index, x, y, z, h, p, r, context):
        self.handleMessage(self.moveItemFromAttic, 'moveItemFromAtticResponse', index, x, y, z, h, p, r, context)

    def deleteItemFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteItemFromAttic, 'deleteItemFromAtticResponse', blob, index, context)

    def deleteItemFromRoomMessage(self, blob, doId, context):
        self.handleMessage(self.deleteItemFromRoom, 'deleteItemFromRoomResponse', blob, doId, context)

    def moveWallpaperFromAtticMessage(self, index, room, context):
        self.handleMessage(self.moveWallpaperFromAttic, 'moveWallpaperFromAtticResponse', index, room, context)

    def deleteWallpaperFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteWallpaperFromAttic, 'deleteWallpaperFromAtticResponse', blob, index, context)

    def moveWindowToAtticMessage(self, slot, context):
        self.handleMessage(self.moveWindowToAttic, 'moveWindowToAtticResponse', slot, context)

    def moveWindowFromAtticMessage(self, index, slot, context):
        self.handleMessage(self.moveWindowFromAttic, 'moveWindowFromAtticResponse', index, slot, context)

    def moveWindowMessage(self, fromSlot, toSlot, context):
        self.handleMessage(self.moveWindow, 'moveWindowResponse', fromSlot, toSlot, context)

    def deleteWindowFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteWindowFromAttic, 'deleteWindowFromAtticResponse', blob, index, context)

    def recoverDeletedItemMessage(self, blob, index, context):
        self.handleMessage(self.recoverDeletedItem, 'recoverDeletedItemResponse', blob, index, context)

    def getItemObject(self, doId):
        item = self.air.doId2do.get(doId)
        if item is None:
            raise FurnitureError(ToontownGlobals.FM_InvalidItem)
        if item not in self.items:
            raise FurnitureError(ToontownGlobals.FM_InvalidItem)
        return item

    def getAtticFurniture(self, attic, index):
        if index >= len(attic):
            raise FurnitureError(ToontownGlobals.FM_InvalidIndex)
        return attic[index]

    def getWindow(self, slot):
        for window in self.windows:
            if window.placement == slot:
                return window
        return None
 def setInteriorItems(self, interiorItems):
     self.interiorItems = CatalogItemList(interiorItems,
                                          store=Customization | Location)
 def setDeletedItems(self, items):
     self.deletedItems = CatalogItemList(items, store=CatalogItem.Customization)
 def setInteriorWallpaper(self, interiorWallpaper):
     self.interiorWallpaper = CatalogItemList(interiorWallpaper,
                                              store=Customization)
 def setDeletedItems(self, items):
     self.deletedItems = CatalogItemList(items,
                                         store=CatalogItem.Customization)
 def setInteriorWindows(self, interiorWindows):
     self.interiorWindows = CatalogItemList(interiorWindows,
                                            store=Customization
                                            | WindowPlacement)
 def setAtticWallpaper(self, items):
     self.atticWallpaper = CatalogItemList(items, store=CatalogItem.Customization)
 def setAtticWindows(self, items):
     self.atticWindows = CatalogItemList(items,
                                         store=CatalogItem.Customization)
 def setAtticWindows(self, items):
     self.atticWindows = CatalogItemList(items, store=CatalogItem.Customization)
class DistributedFurnitureManagerAI(DistributedObjectAI):
    notify = DirectNotifyGlobal.directNotify.newCategory(
        "DistributedFurnitureManagerAI")

    def __init__(self, air, house, interior):
        DistributedObjectAI.__init__(self, air)

        self.house = house
        self.interior = interior

        self.director = None

        self.ownerId = house.avatarId
        self.ownerName = house.name

        self.atticItems = None
        self.atticWallpaper = None
        self.wallpaper = None
        self.atticWindows = None
        self.windows = None
        self.deletedItems = None

        self.items = []

        # Initialize the above variables:
        self.loadFromHouse()

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        for item in self.items:
            item.generateWithRequired(self.zoneId)

    def loadFromHouse(self):
        self.b_setAtticItems(self.house.getAtticItems())
        self.b_setAtticWallpaper(self.house.getAtticWallpaper())
        self.b_setAtticWindows(self.house.getAtticWindows())
        self.b_setDeletedItems(self.house.getDeletedItems())

        self.wallpaper = CatalogItemList(self.house.getInteriorWallpaper(),
                                         store=CatalogItem.Customization)
        self.applyWallpaper()
        self.windows = CatalogItemList(self.house.getInteriorWindows(),
                                       store=CatalogItem.Customization
                                       | CatalogItem.WindowPlacement)
        self.applyWindows()

        self.setItems(self.house.getInteriorItems())

    def saveToHouse(self):
        self.house.b_setAtticItems(self.getAtticItems())
        self.house.b_setAtticWallpaper(self.getAtticWallpaper())
        self.house.b_setAtticWindows(self.getAtticWindows())
        self.house.b_setDeletedItems(self.getDeletedItems())

        self.house.b_setInteriorWallpaper(self.wallpaper.getBlob())
        self.house.b_setInteriorWindows(self.windows.getBlob())

        self.house.b_setInteriorItems(self.getItems())

    def applyWallpaper(self):
        self.interior.b_setWallpaper(self.wallpaper.getBlob())

    def applyWindows(self):
        self.interior.b_setWindows(self.windows.getBlob())

    def setItems(self, items):
        # Decode the blob:
        items = CatalogItemList(items,
                                store=CatalogItem.Customization
                                | CatalogItem.Location)

        # Throw out our old items:
        for item in self.items:
            item.destroy()
        self.items = []

        for item in items:
            if item.furnitureType in furnitureId2Do:
                do = furnitureId2Do[item.furnitureType](self.air, self, item,
                                                        self.ownerId)
                if self.isGenerated():
                    do.generateWithRequired(self.zoneId)
                self.items.append(do)
            else:
                do = DistributedFurnitureItemAI(self.air, self, item)
                if self.isGenerated():
                    do.generateWithRequired(self.zoneId)
                self.items.append(do)

    def getItems(self):
        items = CatalogItemList(store=CatalogItem.Customization
                                | CatalogItem.Location)

        for item in self.items:
            items.append(item.catalogItem)

        return items.getBlob()

    def setOwnerId(self, ownerId):
        self.ownerId = ownerId

    def d_setOwnerId(self, ownerId):
        self.sendUpdate('setOwnerId', [ownerId])

    def b_setOwnerId(self, ownerId):
        self.setOwnerId(ownerId)
        self.d_setOwnerId(ownerId)

    def getOwnerId(self):
        return self.ownerId

    def setOwnerName(self, ownerName):
        self.ownerName = ownerName

    def d_setOwnerName(self, ownerName):
        self.sendUpdate('setOwnerName', [ownerName])

    def b_setOwnerName(self, ownerName):
        self.setOwnerName(ownerName)
        self.d_setOwnerName(ownerName)

    def getOwnerName(self):
        return self.ownerName

    def getInteriorId(self):
        return self.interior.doId

    def setAtticItems(self, items):
        self.atticItems = CatalogItemList(items,
                                          store=CatalogItem.Customization)

    def d_setAtticItems(self, items):
        self.sendUpdate('setAtticItems', [items])

    def b_setAtticItems(self, items):
        self.setAtticItems(items)
        if self.isGenerated():
            self.d_setAtticItems(items)

    def getAtticItems(self):
        return self.atticItems.getBlob()

    def setAtticWallpaper(self, items):
        self.atticWallpaper = CatalogItemList(items,
                                              store=CatalogItem.Customization)

    def d_setAtticWallpaper(self, items):
        self.sendUpdate('setAtticWallpaper', [items])

    def b_setAtticWallpaper(self, items):
        self.setAtticWallpaper(items)
        if self.isGenerated():
            self.d_setAtticWallpaper(items)

    def getAtticWallpaper(self):
        return self.atticWallpaper.getBlob()

    def setAtticWindows(self, items):
        self.atticWindows = CatalogItemList(items,
                                            store=CatalogItem.Customization)

    def d_setAtticWindows(self, items):
        self.sendUpdate('setAtticWindows', [items])

    def b_setAtticWindows(self, items):
        self.setAtticWindows(items)
        if self.isGenerated():
            self.d_setAtticWindows(items)

    def getAtticWindows(self):
        return self.atticWindows.getBlob()

    def setDeletedItems(self, items):
        self.deletedItems = CatalogItemList(items,
                                            store=CatalogItem.Customization)

    def d_setDeletedItems(self, items):
        self.sendUpdate('setDeletedItems', [items])

    def b_setDeletedItems(self, items):
        self.setDeletedItems(items)
        if self.isGenerated():
            self.d_setDeletedItems(items)

    def getDeletedItems(self):
        return self.deletedItems.getBlob()

    def suggestDirector(self, directorId):
        senderId = self.air.getAvatarIdFromSender()

        if self.ownerId != senderId:
            self.air.writeServerEvent(
                'suspicious', senderId,
                'Tried to move furniture, but not the house owner!')
            return

        if senderId != directorId and directorId != 0:
            self.air.writeServerEvent(
                'suspicious', senderId,
                'Tried to make someone else (%d) move their furniture!' %
                directorId)
            return

        director = self.air.doId2do.get(directorId)
        if directorId and not director:
            self.air.writeServerEvent(
                'suspicious', directorId,
                'Tried to move furniture without being on the shard!')
            return

        if self.director:
            self.director.b_setGhostMode(0)
        if director:
            director.b_setGhostMode(1)

        self.director = director
        self.sendUpdate('setDirector', [directorId])

        # Let's also save the furniture to the house (and thus to the DB) while
        # we're at it...
        self.saveToHouse()

    def avatarEnter(self):
        pass

    def avatarExit(self):
        pass

    # Furniture-manipulation:
    def moveItemToAttic(self, doId):
        item = self.getItemObject(doId)

        self.atticItems.append(item.catalogItem)
        self.d_setAtticItems(self.getAtticItems())

        item.destroy()
        self.items.remove(item)

        return ToontownGlobals.FM_MovedItem

    def moveItemFromAttic(self, index, x, y, z, h, p, r):
        item = self.getAtticFurniture(self.atticItems, index)

        self.atticItems.remove(item)
        self.d_setAtticItems(self.getAtticItems())

        item.posHpr = (x, y, z, h, p, r)

        if item.furnitureType in furnitureId2Do:
            do = furnitureId2Do[item.furnitureType](self.air, self, item,
                                                    self.ownerId)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)
        else:
            do = DistributedFurnitureItemAI(self.air, self, item)
            if self.isGenerated():
                do.generateWithRequired(self.zoneId)
            self.items.append(do)

        return (ToontownGlobals.FM_MovedItem, do.doId)

    def deleteItemFromAttic(self, blob, index):
        pass

    def deleteItemFromRoom(self, blob, doId):
        pass

    def moveWallpaperFromAttic(self, index, room):
        pass

    def deleteWallpaperFromAttic(self, blob, index):
        pass

    def moveWindowToAttic(self, slot):
        window = self.getWindow(slot)
        if window is None:
            return ToontownGlobals.FM_InvalidIndex

        self.windows.remove(window)
        self.applyWindows()
        self.atticWindows.append(window)
        self.d_setAtticWindows(self.getAtticWindows())

        return ToontownGlobals.FM_MovedItem

    def moveWindowFromAttic(self, index, slot):
        retcode = ToontownGlobals.FM_MovedItem

        window = self.getAtticFurniture(self.atticWindows, index)

        if slot > 5:
            # This is not a valid slot! HACKER!!!
            self.air.writeServerEvent(
                'suspicious', self.air.getAvatarIdFromSender(),
                'Tried to move window to invalid slot %d!' % slot)
            return ToontownGlobals.FM_HouseFull

        if self.getWindow(slot):
            # Already a window there, swap 'er out.
            self.moveWindowToAttic(slot)
            retcode = ToontownGlobals.FM_SwappedItem

        self.atticWindows.remove(window)
        self.d_setAtticWindows(self.getAtticWindows())
        window.placement = slot
        self.windows.append(window)
        self.applyWindows()

        return retcode

    def moveWindow(self, fromSlot, toSlot):
        retcode = ToontownGlobals.FM_MovedItem

        window = self.getWindow(fromSlot)
        if window is None:
            return ToontownGlobals.FM_InvalidIndex

        if toSlot > 5:
            # This is not a valid slot! HACKER!!!
            self.air.writeServerEvent(
                'suspicious', self.air.getAvatarIdFromSender(),
                'Tried to move window to invalid slot %d!' % toSlot)
            return ToontownGlobals.FM_HouseFull

        if self.getWindow(toSlot):
            # Already a window there, swap 'er out.
            self.moveWindowToAttic(toSlot)
            retcode = ToontownGlobals.FM_SwappedItem

        window.placement = toSlot
        self.applyWindows()

        return retcode

    def deleteWindowFromAttic(self, blob, index):
        pass

    def recoverDeletedItem(self, blob, index):
        pass

    # Network handlers for the above:
    def handleMessage(self, func, response, *args):
        context = args[-1]
        args = args[:-1]

        senderId = self.air.getAvatarIdFromSender()
        if not self.director or senderId != self.director.doId:
            self.air.writeServerEvent(
                'suspicious', senderId,
                'Sent furniture management request without'
                ' being the director.')
            retval = ToontownGlobals.FM_NotDirector
        else:
            try:
                retval = func(*args) or 0
            except FurnitureError as e:
                retval = e.code

        if response == 'moveItemFromAtticResponse':
            # This message actually includes a doId; we split the retval apart
            # if it's a tuple, otherwise it falls back to 0.
            if type(retval) == tuple:
                retval, doId = retval
            else:
                doId = 0

            # Brief delay; this is to give the State Server time to finish
            # processing the new furniture item appearing before we hit the
            # client with the doId:
            taskMgr.doMethodLater(
                5,
                self.sendUpdateToAvatarId,
                self.uniqueName('send-attic-response'),
                extraArgs=[senderId, response, [retval, doId, context]])
        else:
            self.sendUpdateToAvatarId(senderId, response, [retval, context])

    def moveItemToAtticMessage(self, doId, context):
        self.handleMessage(self.moveItemToAttic, 'moveItemToAtticResponse',
                           doId, context)

    def moveItemFromAtticMessage(self, index, x, y, z, h, p, r, context):
        self.handleMessage(self.moveItemFromAttic, 'moveItemFromAtticResponse',
                           index, x, y, z, h, p, r, context)

    def deleteItemFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteItemFromAttic,
                           'deleteItemFromAtticResponse', blob, index, context)

    def deleteItemFromRoomMessage(self, blob, doId, context):
        self.handleMessage(self.deleteItemFromRoom,
                           'deleteItemFromRoomResponse', blob, doId, context)

    def moveWallpaperFromAtticMessage(self, index, room, context):
        self.handleMessage(self.moveWallpaperFromAttic,
                           'moveWallpaperFromAtticResponse', index, room,
                           context)

    def deleteWallpaperFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteWallpaperFromAttic,
                           'deleteWallpaperFromAtticResponse', blob, index,
                           context)

    def moveWindowToAtticMessage(self, slot, context):
        self.handleMessage(self.moveWindowToAttic, 'moveWindowToAtticResponse',
                           slot, context)

    def moveWindowFromAtticMessage(self, index, slot, context):
        self.handleMessage(self.moveWindowFromAttic,
                           'moveWindowFromAtticResponse', index, slot, context)

    def moveWindowMessage(self, fromSlot, toSlot, context):
        self.handleMessage(self.moveWindow, 'moveWindowResponse', fromSlot,
                           toSlot, context)

    def deleteWindowFromAtticMessage(self, blob, index, context):
        self.handleMessage(self.deleteWindowFromAttic,
                           'deleteWindowFromAtticResponse', blob, index,
                           context)

    def recoverDeletedItemMessage(self, blob, index, context):
        self.handleMessage(self.recoverDeletedItem,
                           'recoverDeletedItemResponse', blob, index, context)

    # Functions to safely process data off the wire:
    def getItemObject(self, doId):
        item = self.air.doId2do.get(doId)

        if item is None:
            raise FurnitureError(ToontownGlobals.FM_InvalidItem)

        if item not in self.items:
            raise FurnitureError(ToontownGlobals.FM_InvalidItem)

        return item

    def getAtticFurniture(self, attic, index):
        if index >= len(attic):
            raise FurnitureError(ToontownGlobals.FM_InvalidIndex)

        return attic[index]

    def getWindow(self, slot):
        for window in self.windows:
            if window.placement == slot:
                return window

        return None
class DistributedHouseAI(DistributedObjectAI):
    notify = directNotify.newCategory("DistributedHouseAI")

    def __init__(self, air):
        DistributedObjectAI.__init__(self, air)

        self.houseType = 0
        self.gardenPos = 0
        self.avatarId = 0
        self.name = ''
        self.color = 0
        self.housePos = 0
        self.gender = 1
        self.isInteriorInitialized = 1

        self.atticItems = CatalogItemList(store=Customization)
        self.interiorItems = CatalogItemList(store=Customization)
        self.interiorWallpaper = CatalogItemList(store=Customization)
        self.atticWallpaper = CatalogItemList(store=Customization)
        self.interiorWindows = CatalogItemList(store=Customization)
        self.atticWindows = CatalogItemList(store=Customization)
        self.deletedItems = CatalogItemList(store=Customization)

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        self.interiorZone = self.air.allocateZone()

        self.door = DistributedHouseDoorAI(self.air, self.getDoId(), DoorTypes.EXT_STANDARD)
        self.door.setSwing(3)
        self.door.generateWithRequired(self.zoneId)

        self.interiorDoor = DistributedHouseDoorAI(self.air, self.getDoId(), DoorTypes.INT_STANDARD)
        self.interiorDoor.setSwing(3)
        self.interiorDoor.setOtherDoor(self.door)
        self.interiorDoor.generateWithRequired(self.interiorZone)

        self.door.setOtherDoor(self.interiorDoor)

        self.interior = DistributedHouseInteriorAI(self.air, self)
        self.interior.setHouseIndex(self.housePos)
        self.interior.setHouseId(self.getDoId())
        self.interior.generateWithRequired(self.interiorZone)

        if self.avatarId:
            self.mailbox = DistributedMailboxAI(self.air, self)
            self.mailbox.generateWithRequired(self.zoneId)

        if not self.isInteriorInitialized:
            self.notify.info('Initializing interior...')
            self.interior.initialize()
            self.b_setInteriorInitialized(1)

        self.sendUpdate('setHouseReady', [])


    def delete(self):
        self.door.requestDelete()
        self.interiorDoor.requestDelete()
        self.interior.requestDelete()
        if self.avatarId:
            self.mailbox.requestDelete()
        self.air.deallocateZone(self.interiorZone)
        DistributedObjectAI.delete(self)

    def setHousePos(self, pos):
        self.housePos = pos

    def d_setHousePos(self, pos):
        self.sendUpdate('setHousePos', [pos])

    def b_setHousePos(self, pos):
        self.setHousePos(pos)
        self.d_setHousePos(pos)

    def getHousePos(self):
        return self.housePos

    def setHouseType(self, type):
        self.houseType = type

    def d_setHouseType(self, type):
        self.sendUpdate('setHouseType', [type])

    def b_setHouseType(self, type):
        self.setHouseType(type)
        self.d_setHouseType(type)

    def getHouseType(self):
        return self.houseType

    def setGardenPos(self, pos):
        self.gardenPos = pos

    def d_setGardenPos(self, pos):
        self.sendUpdate('setGardenPos', [pos])

    def b_setGardenPos(self, pos):
        self.setGardenPow(pos)
        self.d_setGardenPos(pos)

    def getGardenPos(self):
        return self.gardenPos

    def setAvatarId(self, avId):
        self.avatarId = avId

    def d_setAvatarId(self, avId):
        self.sendUpdate('setAvatarId', [avId])

    def b_setAvatarId(self, avId):
        self.setAvatarId(avId)
        self.d_setAvatarId(avId)

    def getAvatarId(self):
        return self.avatarId

    def setName(self, name):
        self.name = name

    def d_setName(self, name):
        self.sendUpdate('setName', [name])

    def b_setName(self, name):
        self.setName(name)
        self.d_setName(name)

    def getName(self):
        return self.name

    def setColor(self, color):
        self.color = color

    def d_setColor(self, color):
        self.sendUpdate('setColor', [color])

    def b_setColor(self, color):
        self.setColor(color)
        self.d_setColor(color)

    def getColor(self):
        return self.color

    def setGender(self, genderIndex):
        self.gender = genderIndex

    def getGender(self):
        return self.gender

    def setAtticItems(self, atticItems):
        self.atticItems = CatalogItemList(atticItems, store=Customization)

    def d_setAtticItems(self, atticItems):
        self.sendUpdate('setAtticItems', [atticItems])

    def b_setAtticItems(self, atticItems):
        self.setAtticItems(atticItems)
        self.d_setAtticItems(atticItems)

    def getAtticItems(self):
        return self.atticItems.getBlob()

    def setInteriorItems(self, interiorItems):
        self.interiorItems = CatalogItemList(interiorItems, store=Customization | Location)

    def d_setInteriorItems(self, interiorItems):
        self.sendUpdate('setInteriorItems', [interiorItems])

    def b_setInteriorItems(self, interiorItems):
        self.setInteriorItems(interiorItems)
        self.d_setInteriorItems(interiorItems)

    def getInteriorItems(self):
        return self.interiorItems.getBlob()

    def setAtticWallpaper(self, atticWallpaper):
        self.atticWallpaper = CatalogItemList(atticWallpaper, store=Customization)

    def d_setAtticWallpaper(self, atticWallpaper):
        self.sendUpdate('setAtticWallpaper', [atticWallpaper])

    def b_setAtticWallpaper(self, atticWallpaper):
        self.setAtticWallpaper(atticWallpaper)
        self.d_setAtticWallpaper(atticWallpaper)

    def getAtticWallpaper(self):
        return self.atticWallpaper.getBlob()

    def setInteriorWallpaper(self, interiorWallpaper):
        self.interiorWallpaper = CatalogItemList(interiorWallpaper, store=Customization)

    def d_setInteriorWallpaper(self, interiorWallpaper):
        self.sendUpdate('setInteriorWallpaper', [interiorWallpaper])

    def b_setInteriorWallpaper(self, interiorWallpaper):
        self.setInteriorWallpaper(interiorWallpaper)
        self.d_setInteriorWallpaper(interiorWallpaper)

    def getInteriorWallpaper(self):
        return self.interiorWallpaper.getBlob()

    def setAtticWindows(self, atticWindows):
        self.atticWindows = CatalogItemList(atticWindows, store=Customization)

    def d_setAtticWindows(self, atticWindows):
        self.sendUpdate('setAtticWindows', [atticWindows])

    def b_setAtticWindows(self, atticWindows):
        self.setAtticWindows(atticWindows)
        self.d_setAtticWindows(atticWindows)

    def getAtticWindows(self):
        return self.atticWindows.getBlob()

    def setInteriorWindows(self, interiorWindows):
        self.interiorWindows = CatalogItemList(interiorWindows, store=Customization | WindowPlacement)

    def d_setInteriorWindows(self, interiorWindows):
        self.sendUpdate('setInteriorWindows', [interiorWindows])

    def b_setInteriorWindows(self, interiorWindows):
        self.setInteriorWindows(interiorWindows)
        self.d_setInteriorWindows(interiorWindows)

    def getInteriorWindows(self):
        return self.interiorWindows.getBlob()

    def setDeletedItems(self, deletedItems):
        self.deletedItems = CatalogItemList(deletedItems, store=Customization)

    def d_setDeletedItems(self, deletedItems):
        self.sendUpdate('setDeletedItems', [deletedItems])

    def b_setDeletedItems(self, deletedItems):
        self.setDeletedItems(deletedItems)
        self.d_setDeletedItems(deletedItems)

    def getDeletedItems(self):
        return self.deletedItems.getBlob()

    def setInteriorInitialized(self, initialized):
        self.isInteriorInitialized = initialized

    def d_setInteriorInitialized(self, initialized):
        self.sendUpdate('setInteriorInitialized', [initialized])

    def b_setInteriorInitialized(self, initialized):
        self.setInteriorInitialized(initialized)
        self.d_setInteriorInitialized(initialized)

    def getInteriorInitialized(self):
        return self.isInteriorInitialized

    def setCannonEnabled(self, todo0):
        pass

    def getCannonEnabled(self):
        return 0

    def setHouseReady(self):
        pass

    def addAtticItem(self, item):
        self.interior.furnitureManager.saveToHouse()
        if item.getFlags() & FLTrunk:
            self.atticItems.append(item)
        elif item.replacesExisting() and item.hasExisting():
            if item.getFlags() & FLCloset:
                closets = ClosetToClothes.keys()
                for itItem in self.interiorItems:
                    if itItem.furnitureType in closets:
                        posHpr = itItem.posHpr
                        self.interiorItems.remove(itItem)
                        item.posHpr = posHpr
                        self.interiorItems.append(item)
                        break
                for itItem in self.atticItems:
                    if itItem.furnitureType in closets:
                        self.atticItems.remove(itItem)
                        self.atticItems.append(item)
                        break
        else:
            self.atticItems.append(item)
        self.d_setAtticItems(self.atticItems.getBlob())
        self.d_setInteriorItems(self.interiorItems.getBlob())
        self.interior.furnitureManager.loadFromHouse()

    def addWindow(self, item):
        self.interior.furnitureManager.saveToHouse()
        self.atticWindows.append(item)
        self.d_setAtticWindows(self.atticWindows.getBlob())
        self.interior.furnitureManager.loadFromHouse()

    def addWallpaper(self, item):
        self.interior.furnitureManager.saveToHouse()
        self.atticWallpaper.append(item)
        self.d_setAtticWallpaper(self.atticWallpaper.getBlob())
        self.interior.furnitureManager.loadFromHouse()