from direct.distributed.DistributedObjectAI import DistributedObjectAI from toontown.catalog.CatalogItemList import CatalogItemList from toontown.catalog import CatalogItem from toontown.catalog.CatalogFurnitureItem import CatalogFurnitureItem, FLTrunk, FLCloset, FLBank, FLPhone from toontown.catalog.CatalogWallpaperItem import CatalogWallpaperItem from toontown.catalog.CatalogMouldingItem import CatalogMouldingItem from toontown.catalog.CatalogFlooringItem import CatalogFlooringItem from toontown.catalog.CatalogWainscotingItem import CatalogWainscotingItem from toontown.toonbase import ToontownGlobals from DistributedFurnitureItemAI import DistributedFurnitureItemAI from DistributedPhoneAI import DistributedPhoneAI from DistributedClosetAI import DistributedClosetAI from DistributedTrunkAI import DistributedTrunkAI from DistributedBankAI import DistributedBankAI from otp.ai.MagicWordGlobal import * class FurnitureError(Exception): def __init__(self, code): Exception.__init__(self) self.code = code 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 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 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: 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(blob, index) if wallpaper in self.atticWallpaper: 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 @magicWord(category=CATEGORY_PROGRAMMER, types=[]) def findCloset(): """ find the closet """ target = spellbook.getTarget() if not target: target = spellbook.getInvoker() if not target: return "Strange.. who are we talking about?" if not hasattr(target, "estate") or not hasattr(target.estate, "houses"): return "no houses in the state" for house in target.estate.houses: if house.doId == target.houseId: fm = house.interior.furnitureManager for item in fm.items: if item.catalogItem.getFlags() & FLCloset: return 'items: %s'%(str(item.catalogItem)) for item in fm.atticItems: if item.getFlags() & FLCloset: return 'atticItems: %s'%(str(item)) return "I cannot find your closet" @magicWord(category=CATEGORY_PROGRAMMER, types=[]) def recoverCloset(): """ recover the closet """ target = spellbook.getTarget() if not target: target = spellbook.getInvoker() if not target: return "Strange.. who are we talking about?" if not hasattr(target, "estate") or not hasattr(target.estate, "houses"): return "no houses in the state" for house in target.estate.houses: if house.doId == target.houseId: fm = house.interior.furnitureManager for item in reversed(fm.items): if item.catalogItem.getFlags() & FLCloset: fm.moveItemToAttic(item.doId); return "Moved the closet" fm.saveToHouse() return "I cannot find your closet" @magicWord(category=CATEGORY_PROGRAMMER, types=[]) def fillAttic(): """ move everything to the attic """ target = spellbook.getTarget() if not target: target = spellbook.getInvoker() if not target: return "Strange.. who are we talking about?" if not hasattr(target, "estate") or not hasattr(target.estate, "houses"): return "no houses in the state" for house in target.estate.houses: if house.doId == target.houseId: fm = house.interior.furnitureManager for item in reversed(fm.items): fm.moveItemToAttic(item.doId); fm.saveToHouse() return "everything has been moved to the attic" @magicWord(category=CATEGORY_PROGRAMMER, types=[]) def emptyHouse(): """ delete everything in the house """ target = spellbook.getTarget() if not target: target = spellbook.getInvoker() if not target: return "Strange.. who are we talking about?" if not hasattr(target, "estate") or not hasattr(target.estate, "houses"): return "no houses in the state" for house in target.estate.houses: if house.doId == target.houseId: fm = house.interior.furnitureManager for item in reversed(fm.items): item.destroy() fm.items.remove(item) fm.saveToHouse() return "The house is empty"