toontown-just-works/toontown/estate/DistributedPhoneAI.py

258 lines
10 KiB
Python
Raw Normal View History

2024-07-07 18:08:39 -05:00
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