from direct.directnotify import DirectNotifyGlobal from direct.distributed.ClockDelta import * from toontown.estate.DistributedFurnitureItemAI import DistributedFurnitureItemAI from PhoneGlobals import * from toontown.toonbase import ToontownGlobals from toontown.catalog import CatalogItem, CatalogInvalidItem, GiftAvatar from toontown.catalog.CatalogItemList import CatalogItemList from toontown.uberdog import TopToonsGlobals import json class LoadGiftAvatar: def __init__(self, phone, avId, targetId, optional, callback): self.air = phone.air self.phone = phone self.avId = avId self.targetId = targetId self.optional = optional self.callback = callback def start(self): self.air.dbInterface.queryObject(self.air.dbId, self.targetId, self.__gotAvatar) def copyDict(self, dict, *keys): return {key: dict[key] for key in keys} def __gotAvatar(self, dclass, fields): if dclass != self.air.dclassesByName['DistributedToonAI']: return for key in ('setDNAString', 'setMailboxContents', 'setGiftSchedule', 'setDeliverySchedule'): fields[key] = fields[key][0].encode('base64') newDict = self.copyDict(fields, 'setDNAString', 'setMailboxContents', 'setGiftSchedule', 'setDeliverySchedule', 'setHat', 'setGlasses', 'setBackpack', 'setShoes', 'setHatList', 'setGlassesList', 'setBackpackList', 'setShoes', 'setShoesList', 'setCustomMessages', 'setEmoteAccess', 'setClothesTopsList', 'setClothesBottomsList', 'setPetTrickPhrases', 'setNametagStyles') self.callback(self.avId, self.targetId, newDict, self.optional) del self.phone.fsms[self.avId] class DistributedPhoneAI(DistributedFurnitureItemAI): notify = DirectNotifyGlobal.directNotify.newCategory("DistributedPhoneAI") def __init__(self, air, furnitureMgr, catalogItem): DistributedFurnitureItemAI.__init__(self, air, furnitureMgr, catalogItem) self.fsms = {} self.initialScale = (0.8, 0.8, 0.8) self.inUse = False self.currAvId = 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 setInitialScale(self, scale): self.initialScale = scale def getInitialScale(self): return self.initialScale def avatarEnter(self): avId = self.air.getAvatarIdFromSender() if self.inUse: self.ejectAvatar(avId) return av = self.air.doId2do.get(avId) if av: self.setInUse(avId) self.sendUpdateToAvatarId(avId, 'setLimits', [self.calcHouseItems(av)]) self.d_setMovie(PHONE_MOVIE_PICKUP, avId) av.b_setCatalogNotify(0, av.mailboxNotify) self.air.questManager.toonCalledClarabelle(av) def avatarExit(self): if not self.inUse: self.notify.warning('Requested avatarExit but phone isn\'t in use!') return avId = self.air.getAvatarIdFromSender() if avId != self.currAvId: self.notify.warning('Requested avatarExit from unknown avatar %s' %avId) return self.d_setMovie(PHONE_MOVIE_HANGUP, avId) taskMgr.doMethodLater(1, self.resetMovie, self.taskName('resetMovie')) self.setFree() def setFree(self): self.inUse = False self.currAvId = 0 def setInUse(self, avId): self.inUse = True self.currAvId = avId def d_setMovie(self, movie, avId): self.sendUpdate('setMovie', args=[movie, avId, globalClockDelta.getRealNetworkTime(bits=32)]) def ejectAvatar(self, avId): self.sendUpdateToAvatarId(avId, 'freeAvatar', []) def __getCaller(self): avId = self.air.getAvatarIdFromSender() if avId != self.currAvId: self.air.writeServerEvent('suspicious', avId, 'tried purchasing item, but not using phone') self.notify.warning('%d tried purchasing item, but not using phone' % avId) return av = self.air.doId2do.get(avId) if not av: self.air.writeServerEvent('suspicious', avId, 'tried purchasing item, but not on shard') self.notify.warning('%d tried purchasing item, but not on shard' % avId) return return av def checkPurchaseLimit(self, recipient, item): if len(recipient.mailboxContents) + len(recipient.onOrder) + len(recipient.onGiftOrder) + 1 >= ToontownGlobals.MaxMailboxContents: return ToontownGlobals.P_MailboxFull elif item.reachedPurchaseLimit(recipient): return ToontownGlobals.P_ReachedPurchaseLimit return ToontownGlobals.P_ItemOnOrder def chargeAvatar(self, av, money, emblems): av.takeMoney(money) av.subtractEmblems(emblems) def attemptPurchase(self, context, av, blob, optional, gifting=False): avId = av.doId item = CatalogItem.getItem(blob, CatalogItem.Customization) if isinstance(item, CatalogInvalidItem.CatalogInvalidItem): self.air.writeServerEvent('suspicious', avId, 'tried purchasing invalid item') self.notify.warning('%d tried purchasing invalid item' % avId) return ToontownGlobals.P_NotInCatalog elif (not item.hasEmblemPrices()) and item not in av.backCatalog and item not in av.weeklyCatalog and item not in av.monthlyCatalog: self.air.writeServerEvent('suspicious', avId, 'tried purchasing non-existing item') self.notify.warning('%d tried purchasing non-existing item' % avId) return ToontownGlobals.P_NotInCatalog if gifting and not item.isGift(): return ToontownGlobals.P_NotAGift price = item.getPrice(CatalogItem.CatalogTypeBackorder if item in av.backCatalog else 0) if price > av.getTotalMoney() or (item.hasEmblemPrices() and not av.isEnoughEmblemsToBuy(item.getEmblemPrices())): return ToontownGlobals.P_NotEnoughMoney if gifting: return self.requestGiftAvatarOperation(avId, gifting, [context, item, price], self.attemptGiftPurchase) else: returnCode = self.checkPurchaseLimit(av, item) if returnCode != ToontownGlobals.P_ItemOnOrder: return returnCode if item.getDeliveryTime(): self.chargeAvatar(av, price, item.getEmblemPrices()) av.addToDeliverySchedule(item, item.getDeliveryTime()) av.addStat(ToontownGlobals.STAT_ITEMS) else: returnCode = item.recordPurchase(av, optional) if returnCode == ToontownGlobals.P_ItemAvailable: self.chargeAvatar(av, price, item.getEmblemPrices()) av.addStat(ToontownGlobals.STAT_ITEMS) return returnCode return None def attemptGiftPurchase(self, avId, targetId, avatar, optional): av = self.air.doId2do.get(avId) if not av: return recipient = GiftAvatar.createFromFields(avatar) context = optional[0] item = optional[1] returnCode = self.checkPurchaseLimit(recipient, item) if returnCode != ToontownGlobals.P_ItemOnOrder: self.sendGiftPurchaseResponse(context, avId, returnCode) return self.chargeAvatar(av, optional[2], item.getEmblemPrices()) recipient.addToGiftSchedule(avId, targetId, item, item.getDeliveryTime()) av.addStat(ToontownGlobals.STAT_ITEMS) self.sendGiftPurchaseResponse(context, avId, ToontownGlobals.P_ItemOnOrder) def sendGiftPurchaseResponse(self, context, avId, returnCode): if returnCode in (ToontownGlobals.P_ItemOnOrder, ToontownGlobals.P_ItemAvailable): messenger.send('topToonsManager-event', [avId, TopToonsGlobals.CAT_CATALOG | TopToonsGlobals.CAT_GIFTS, 1]) self.sendUpdateToAvatarId(avId, 'requestGiftPurchaseResponse', [context, returnCode]) def requestPurchaseMessage(self, context, blob, optional): av = self.__getCaller() if not av: return returnCode = self.attemptPurchase(context, av, blob, optional) if returnCode in (ToontownGlobals.P_ItemOnOrder, ToontownGlobals.P_ItemAvailable): messenger.send('topToonsManager-event', [av.doId, TopToonsGlobals.CAT_CATALOG, 1]) self.sendUpdateToAvatarId(av.doId, 'requestPurchaseResponse', [context, returnCode]) def requestGiftPurchaseMessage(self, context, targetId, blob, optional): av = self.__getCaller() if not av: return returnCode = self.attemptPurchase(context, av, blob, optional, gifting=targetId) if returnCode: self.sendGiftPurchaseResponse(context, av.doId, returnCode) def requestGiftAvatar(self, doId): self.requestGiftAvatarOperation(self.air.getAvatarIdFromSender(), doId, None, self.sendGiftAvatarResponse) def requestGiftAvatarOperation(self, avId, doId, optional, callback): if avId in self.fsms: return ToontownGlobals.P_TooFast loadOperation = LoadGiftAvatar(self, avId, doId, optional, callback) loadOperation.start() self.fsms[avId] = loadOperation return None def sendGiftAvatarResponse(self, avId, targetId, avatar, optional): self.sendUpdateToAvatarId(avId, 'setGiftAvatar', [json.dumps(avatar)]) def resetMovie(self, task): self.d_setMovie(PHONE_MOVIE_CLEAR, 0) return task.done