191 lines
8.9 KiB
Python
191 lines
8.9 KiB
Python
from otp.ai.AIBaseGlobal import *
|
|
from panda3d.core import *
|
|
from DistributedNPCToonBaseAI import *
|
|
import ToonDNA
|
|
from direct.task.Task import Task
|
|
from toontown.estate import ClosetGlobals
|
|
|
|
class DistributedNPCTailorAI(DistributedNPCToonBaseAI):
|
|
freeClothes = simbase.config.GetBool('free-clothes', 0)
|
|
housingEnabled = simbase.config.GetBool('want-housing', 1)
|
|
useJellybeans = simbase.config.GetBool('want-tailor-jellybeans', False)
|
|
|
|
def __init__(self, air, npcId):
|
|
DistributedNPCToonBaseAI.__init__(self, air, npcId)
|
|
self.timedOut = 0
|
|
self.givesQuests = 0
|
|
self.customerDNA = None
|
|
self.customerId = None
|
|
self.jbCost = 150
|
|
|
|
if self.freeClothes:
|
|
self.useJellybeans = False
|
|
|
|
def getTailor(self):
|
|
return 1
|
|
|
|
def delete(self):
|
|
taskMgr.remove(self.uniqueName('clearMovie'))
|
|
self.ignoreAll()
|
|
self.customerDNA = None
|
|
self.customerId = None
|
|
DistributedNPCToonBaseAI.delete(self)
|
|
|
|
def avatarEnter(self):
|
|
avId = self.air.getAvatarIdFromSender()
|
|
if avId not in self.air.doId2do:
|
|
self.notify.warning('Avatar: %s not found' % avId)
|
|
return
|
|
if self.isBusy():
|
|
self.freeAvatar(avId)
|
|
return
|
|
av = self.air.doId2do[avId]
|
|
self.customerDNA = ToonDNA.ToonDNA()
|
|
self.customerDNA.makeFromNetString(av.getDNAString())
|
|
self.customerId = avId
|
|
av.b_setDNAString(self.customerDNA.makeNetString())
|
|
self.acceptOnce(self.air.getAvatarExitEvent(avId), self.__handleUnexpectedExit, extraArgs=[avId])
|
|
|
|
if self.useJellybeans:
|
|
flag = NPCToons.PURCHASE_MOVIE_START_BROWSE_JBS
|
|
else:
|
|
flag = NPCToons.PURCHASE_MOVIE_START_BROWSE
|
|
|
|
if self.freeClothes:
|
|
flag = NPCToons.PURCHASE_MOVIE_START
|
|
elif self.useJellybeans and self.hasEnoughJbs(av):
|
|
flag = NPCToons.PURCHASE_MOVIE_START
|
|
elif self.air.questManager.hasTailorClothingTicket(av, self):
|
|
flag = NPCToons.PURCHASE_MOVIE_START
|
|
|
|
if self.housingEnabled and self.isClosetAlmostFull(av):
|
|
flag = NPCToons.PURCHASE_MOVIE_START_NOROOM
|
|
|
|
self.sendShoppingMovie(avId, flag)
|
|
DistributedNPCToonBaseAI.avatarEnter(self)
|
|
|
|
def isClosetAlmostFull(self, av):
|
|
numClothes = len(av.clothesTopsList) / 4 + len(av.clothesBottomsList) / 2
|
|
return numClothes >= av.maxClothes - 1
|
|
|
|
def hasEnoughJbs(self, av):
|
|
return av.getTotalMoney() >= self.jbCost
|
|
|
|
def sendShoppingMovie(self, avId, flag):
|
|
self.busy = avId
|
|
self.sendUpdate('setMovie', [flag,
|
|
self.npcId,
|
|
avId,
|
|
ClockDelta.globalClockDelta.getRealNetworkTime()])
|
|
taskMgr.doMethodLater(NPCToons.TAILOR_COUNTDOWN_TIME, self.sendTimeoutMovie, self.uniqueName('clearMovie'))
|
|
|
|
def rejectAvatar(self, avId):
|
|
self.notify.warning('rejectAvatar: should not be called by a Tailor!')
|
|
|
|
def sendTimeoutMovie(self, task):
|
|
toon = self.air.doId2do.get(self.customerId)
|
|
if toon != None and self.customerDNA:
|
|
toon.b_setDNAString(self.customerDNA.makeNetString())
|
|
self.timedOut = 1
|
|
self.sendUpdate('setMovie', [NPCToons.PURCHASE_MOVIE_TIMEOUT,
|
|
self.npcId,
|
|
self.busy,
|
|
ClockDelta.globalClockDelta.getRealNetworkTime()])
|
|
self.sendClearMovie(None)
|
|
return Task.done
|
|
|
|
def sendClearMovie(self, task):
|
|
self.ignore(self.air.getAvatarExitEvent(self.busy))
|
|
self.customerDNA = None
|
|
self.customerId = None
|
|
self.busy = 0
|
|
self.timedOut = 0
|
|
self.sendUpdate('setMovie', [NPCToons.PURCHASE_MOVIE_CLEAR,
|
|
self.npcId,
|
|
0,
|
|
ClockDelta.globalClockDelta.getRealNetworkTime()])
|
|
self.sendUpdate('setCustomerDNA', [0, ''])
|
|
return Task.done
|
|
|
|
def completePurchase(self, avId):
|
|
av = self.air.doId2do[avId]
|
|
self.busy = avId
|
|
self.sendUpdate('setMovie', [NPCToons.PURCHASE_MOVIE_COMPLETE,
|
|
self.npcId,
|
|
avId,
|
|
ClockDelta.globalClockDelta.getRealNetworkTime()])
|
|
self.sendClearMovie(None)
|
|
if self.air.questManager.hasTailorClothingTicket(av, self):
|
|
self.air.questManager.removeClothingTicket(av, self)
|
|
|
|
def setDNA(self, blob, finished, which):
|
|
avId = self.air.getAvatarIdFromSender()
|
|
if avId != self.customerId:
|
|
if self.customerId:
|
|
self.air.writeServerEvent('suspicious', avId, 'DistributedNPCTailorAI.setDNA customer is %s' % self.customerId)
|
|
self.notify.warning('customerId: %s, but got setDNA for: %s' % (self.customerId, avId))
|
|
return
|
|
testDNA = ToonDNA.ToonDNA()
|
|
if not testDNA.isValidNetString(blob):
|
|
self.air.writeServerEvent('suspicious', avId, 'DistributedNPCTailorAI.setDNA: invalid dna: %s' % blob)
|
|
return
|
|
if avId in self.air.doId2do:
|
|
av = self.air.doId2do.get(avId)
|
|
if finished == 2 and which > 0:
|
|
if self.freeClothes or av.takeMoney(self.jbCost, bUseBank = True):
|
|
av.b_setDNAString(blob)
|
|
if which & ClosetGlobals.SHIRT:
|
|
if av.addToClothesTopsList(self.customerDNA.topTex, self.customerDNA.topTexColor, self.customerDNA.sleeveTex, self.customerDNA.sleeveTexColor) == 1:
|
|
av.b_setClothesTopsList(av.getClothesTopsList())
|
|
else:
|
|
self.notify.warning('NPCTailor: setDNA() - unable to save old tops - we exceeded the tops list length')
|
|
if which & ClosetGlobals.SHORTS:
|
|
if av.addToClothesBottomsList(self.customerDNA.botTex, self.customerDNA.botTexColor) == 1:
|
|
av.b_setClothesBottomsList(av.getClothesBottomsList())
|
|
else:
|
|
self.notify.warning('NPCTailor: setDNA() - unable to save old bottoms - we exceeded the bottoms list length')
|
|
self.air.writeServerEvent('boughtTailorClothes', avId, '%s|%s|%s' % (self.doId, which, self.customerDNA.asTuple()))
|
|
elif self.useJellybeans:
|
|
self.air.writeServerEvent('suspicious', avId, 'DistributedNPCTailorAI.setDNA tried to purchase with insufficient jellybeans')
|
|
self.notify.warning('NPCTailor: setDNA() - client tried to purchase with insufficient jellybeans!')
|
|
elif self.air.questManager.hasTailorClothingTicket(av, self):
|
|
self.air.questManager.removeClothingTicket(av, self)
|
|
av.b_setDNAString(blob)
|
|
if which & ClosetGlobals.SHIRT:
|
|
if av.addToClothesTopsList(self.customerDNA.topTex, self.customerDNA.topTexColor, self.customerDNA.sleeveTex, self.customerDNA.sleeveTexColor) == 1:
|
|
av.b_setClothesTopsList(av.getClothesTopsList())
|
|
else:
|
|
self.notify.warning('NPCTailor: setDNA() - unable to save old tops - we exceeded the tops list length')
|
|
if which & ClosetGlobals.SHORTS:
|
|
if av.addToClothesBottomsList(self.customerDNA.botTex, self.customerDNA.botTexColor) == 1:
|
|
av.b_setClothesBottomsList(av.getClothesBottomsList())
|
|
else:
|
|
self.notify.warning('NPCTailor: setDNA() - unable to save old bottoms - we exceeded the bottoms list length')
|
|
self.air.writeServerEvent('boughtTailorClothes', avId, '%s|%s|%s' % (self.doId, which, self.customerDNA.asTuple()))
|
|
elif finished == 1:
|
|
if self.customerDNA:
|
|
av.b_setDNAString(self.customerDNA.makeNetString())
|
|
else:
|
|
self.sendUpdate('setCustomerDNA', [avId, blob])
|
|
else:
|
|
self.notify.warning('no av for avId: %d' % avId)
|
|
if self.timedOut == 1 or finished == 0:
|
|
return
|
|
if self.busy == avId:
|
|
taskMgr.remove(self.uniqueName('clearMovie'))
|
|
self.completePurchase(avId)
|
|
elif self.busy:
|
|
self.air.writeServerEvent('suspicious', avId, 'DistributedNPCTailorAI.setDNA busy with %s' % self.busy)
|
|
self.notify.warning('setDNA from unknown avId: %s busy: %s' % (avId, self.busy))
|
|
|
|
def __handleUnexpectedExit(self, avId):
|
|
self.notify.warning('avatar:' + str(avId) + ' has exited unexpectedly')
|
|
if self.customerId == avId:
|
|
dna = self.customerDNA.makeNetString()
|
|
self.air.dbInterface.updateObject(self.air.dbId, avId, self.air.dclassesByName['DistributedToonAI'], {'setDNAString': [dna]})
|
|
else:
|
|
self.notify.warning('invalid customer avId: %s, customerId: %s ' % (avId, self.customerId))
|
|
if self.busy == avId:
|
|
self.sendClearMovie(None)
|
|
else:
|
|
self.notify.warning('not busy with avId: %s, busy: %s ' % (avId, self.busy))
|