2015-03-09 12:33:29 -05:00
|
|
|
from direct.directnotify import DirectNotifyGlobal
|
2015-06-23 18:11:48 -05:00
|
|
|
from panda3d.core import *
|
2015-03-03 16:10:12 -06:00
|
|
|
from toontown.toonbase import TTLocalizer
|
|
|
|
from toontown.toonbase import ToontownGlobals
|
|
|
|
from direct.interval.IntervalGlobal import *
|
|
|
|
from direct.distributed.PyDatagram import PyDatagram
|
|
|
|
from direct.distributed.PyDatagramIterator import PyDatagramIterator
|
|
|
|
import types
|
|
|
|
import sys
|
|
|
|
CatalogReverseType = None
|
2015-05-14 12:54:08 -05:00
|
|
|
CatalogItemVersion = 0
|
2015-03-03 16:10:12 -06:00
|
|
|
CatalogBackorderMarkup = 1.2
|
|
|
|
CatalogSaleMarkdown = 0.75
|
|
|
|
Customization = 1
|
|
|
|
DeliveryDate = 2
|
|
|
|
Location = 4
|
|
|
|
WindowPlacement = 8
|
|
|
|
GiftTag = 16
|
|
|
|
CatalogTypeUnspecified = 0
|
|
|
|
CatalogTypeWeekly = 1
|
|
|
|
CatalogTypeBackorder = 2
|
|
|
|
CatalogTypeMonthly = 3
|
2015-07-23 15:00:50 -05:00
|
|
|
CatalogTypeSpecial = 4
|
2015-03-03 16:10:12 -06:00
|
|
|
|
|
|
|
class CatalogItem:
|
2015-03-09 12:33:29 -05:00
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('CatalogItem')
|
2015-03-03 16:10:12 -06:00
|
|
|
|
|
|
|
def __init__(self, *args, **kw):
|
|
|
|
self.saleItem = 0
|
|
|
|
self.deliveryDate = None
|
|
|
|
self.posHpr = None
|
|
|
|
self.giftTag = None
|
|
|
|
self.giftCode = 0
|
|
|
|
self.hasPicture = False
|
2015-07-23 15:00:50 -05:00
|
|
|
self.isSpecial = False
|
2015-03-03 16:10:12 -06:00
|
|
|
self.volume = 0
|
|
|
|
self.specialEventId = 0
|
|
|
|
if len(args) >= 1 and isinstance(args[0], DatagramIterator):
|
|
|
|
self.decodeDatagram(*args, **kw)
|
|
|
|
else:
|
|
|
|
self.makeNewItem(*args, **kw)
|
|
|
|
return
|
|
|
|
|
|
|
|
def isAward(self):
|
2015-07-13 09:17:56 -05:00
|
|
|
#result = self.specialEventId != 0
|
|
|
|
return False
|
2015-03-03 16:10:12 -06:00
|
|
|
|
|
|
|
def makeNewItem(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def needsCustomize(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def saveHistory(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def getBackSticky(self):
|
|
|
|
itemType = 0
|
|
|
|
numSticky = 0
|
|
|
|
return (itemType, numSticky)
|
|
|
|
|
|
|
|
def putInBackCatalog(self, backCatalog, lastBackCatalog):
|
|
|
|
if self.saveHistory() and not self.isSaleItem():
|
|
|
|
if self not in backCatalog:
|
|
|
|
if self in lastBackCatalog:
|
|
|
|
lastBackCatalog.remove(self)
|
|
|
|
backCatalog.append(self)
|
|
|
|
|
|
|
|
def replacesExisting(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def hasExisting(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def getYourOldDesc(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def storedInCloset(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def storedInAttic(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def notOfferedTo(self, avatar):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def getPurchaseLimit(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def reachedPurchaseLimit(self, avatar):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def hasBeenGifted(self, avatar):
|
|
|
|
if avatar.onGiftOrder.count(self) != 0:
|
|
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def getTypeName(self):
|
|
|
|
return 'Unknown Type Item'
|
|
|
|
|
|
|
|
def getName(self):
|
|
|
|
return 'Unnamed Item'
|
|
|
|
|
|
|
|
def getDisplayName(self):
|
|
|
|
return self.getName()
|
|
|
|
|
|
|
|
def recordPurchase(self, avatar, optional):
|
|
|
|
self.notify.warning('%s has no purchase method.' % self)
|
|
|
|
return ToontownGlobals.P_NoPurchaseMethod
|
|
|
|
|
|
|
|
def isSaleItem(self):
|
|
|
|
return self.saleItem
|
|
|
|
|
|
|
|
def isGift(self):
|
2015-05-16 23:52:07 -05:00
|
|
|
if self.getEmblemPrices():
|
|
|
|
return 0
|
|
|
|
return 1
|
2015-03-03 16:10:12 -06:00
|
|
|
|
|
|
|
def isRental(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def forBoysOnly(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def forGirlsOnly(self):
|
|
|
|
return 0
|
|
|
|
|
2015-07-23 15:00:50 -05:00
|
|
|
def getIsSpecial(self):
|
|
|
|
return self.isSpecial
|
2015-03-03 16:10:12 -06:00
|
|
|
|
|
|
|
def getPrice(self, catalogType):
|
|
|
|
if catalogType == CatalogTypeBackorder:
|
|
|
|
return self.getBackPrice()
|
|
|
|
elif self.isSaleItem():
|
|
|
|
return self.getSalePrice()
|
|
|
|
else:
|
|
|
|
return self.getCurrentPrice()
|
|
|
|
|
|
|
|
def getCurrentPrice(self):
|
|
|
|
return int(self.getBasePrice())
|
|
|
|
|
|
|
|
def getBackPrice(self):
|
|
|
|
return int(self.getBasePrice() * CatalogBackorderMarkup)
|
|
|
|
|
|
|
|
def getSalePrice(self):
|
|
|
|
return int(self.getBasePrice() * CatalogSaleMarkdown)
|
|
|
|
|
|
|
|
def getDeliveryTime(self):
|
2015-03-23 06:51:32 -05:00
|
|
|
return 1
|
2015-03-03 16:10:12 -06:00
|
|
|
|
|
|
|
def getPicture(self, avatar):
|
|
|
|
self.hasPicture = True
|
|
|
|
return (None, None)
|
|
|
|
|
|
|
|
def cleanupPicture(self):
|
|
|
|
self.hasPicture = False
|
|
|
|
|
|
|
|
def requestPurchase(self, phone, callback, optional = -1):
|
|
|
|
phone.requestPurchase(self, callback, optional)
|
|
|
|
|
|
|
|
def requestGiftPurchase(self, phone, targetDoID, callback, optional = -1):
|
|
|
|
phone.requestGiftPurchase(self, targetDoID, callback, optional)
|
|
|
|
|
|
|
|
def requestPurchaseCleanup(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def getRequestPurchaseErrorText(self, retcode):
|
|
|
|
if retcode == ToontownGlobals.P_ItemAvailable:
|
|
|
|
return TTLocalizer.CatalogPurchaseItemAvailable
|
|
|
|
elif retcode == ToontownGlobals.P_ItemOnOrder:
|
|
|
|
return TTLocalizer.CatalogPurchaseItemOnOrder
|
|
|
|
elif retcode == ToontownGlobals.P_MailboxFull:
|
|
|
|
return TTLocalizer.CatalogPurchaseMailboxFull
|
|
|
|
elif retcode == ToontownGlobals.P_OnOrderListFull:
|
|
|
|
return TTLocalizer.CatalogPurchaseOnOrderListFull
|
|
|
|
else:
|
|
|
|
return TTLocalizer.CatalogPurchaseGeneralError % retcode
|
|
|
|
|
|
|
|
def getRequestGiftPurchaseErrorText(self, retcode):
|
|
|
|
if retcode == ToontownGlobals.P_ItemAvailable:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftItemAvailable
|
|
|
|
elif retcode == ToontownGlobals.P_ItemOnOrder:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftItemOnOrder
|
|
|
|
elif retcode == ToontownGlobals.P_MailboxFull:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftMailboxFull
|
|
|
|
elif retcode == ToontownGlobals.P_OnOrderListFull:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftOnOrderListFull
|
|
|
|
elif retcode == ToontownGlobals.P_NotAGift:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftNotAGift
|
|
|
|
elif retcode == ToontownGlobals.P_WillNotFit:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftWillNotFit
|
|
|
|
elif retcode == ToontownGlobals.P_ReachedPurchaseLimit:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftLimitReached
|
|
|
|
elif retcode == ToontownGlobals.P_NotEnoughMoney:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftNotEnoughMoney
|
2015-07-17 07:54:12 -05:00
|
|
|
elif retcode == ToontownGlobals.P_TooFast:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftTooFast
|
2015-03-03 16:10:12 -06:00
|
|
|
else:
|
|
|
|
return TTLocalizer.CatalogPurchaseGiftGeneralError % {'friend': '%s',
|
|
|
|
'error': retcode}
|
|
|
|
|
|
|
|
def acceptItem(self, mailbox, index, callback):
|
|
|
|
mailbox.acceptItem(self, index, callback)
|
|
|
|
|
|
|
|
def discardItem(self, mailbox, index, callback):
|
2015-03-09 12:33:29 -05:00
|
|
|
print 'Item discardItem'
|
2015-03-03 16:10:12 -06:00
|
|
|
mailbox.discardItem(self, index, callback)
|
|
|
|
|
|
|
|
def acceptItemCleanup(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def getAcceptItemErrorText(self, retcode):
|
|
|
|
if retcode == ToontownGlobals.P_NoRoomForItem:
|
|
|
|
return TTLocalizer.CatalogAcceptRoomError
|
|
|
|
elif retcode == ToontownGlobals.P_ReachedPurchaseLimit:
|
|
|
|
return TTLocalizer.CatalogAcceptLimitError
|
|
|
|
elif retcode == ToontownGlobals.P_WillNotFit:
|
|
|
|
return TTLocalizer.CatalogAcceptFitError
|
|
|
|
elif retcode == ToontownGlobals.P_InvalidIndex:
|
|
|
|
return TTLocalizer.CatalogAcceptInvalidError
|
|
|
|
else:
|
|
|
|
return TTLocalizer.CatalogAcceptGeneralError % retcode
|
|
|
|
|
|
|
|
def output(self, store = -1):
|
|
|
|
return 'CatalogItem'
|
|
|
|
|
|
|
|
def getFilename(self):
|
|
|
|
return ''
|
|
|
|
|
|
|
|
def getColor(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def formatOptionalData(self, store = -1):
|
|
|
|
result = ''
|
|
|
|
if store & Location and self.posHpr != None:
|
|
|
|
result += ', posHpr = (%s, %s, %s, %s, %s, %s)' % self.posHpr
|
|
|
|
return result
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.output()
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return self.output()
|
|
|
|
|
|
|
|
def compareTo(self, other):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def getHashContents(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def __cmp__(self, other):
|
|
|
|
c = cmp(self.__class__, other.__class__)
|
|
|
|
if c != 0:
|
|
|
|
return c
|
|
|
|
return self.compareTo(other)
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash((self.__class__, self.getHashContents()))
|
|
|
|
|
|
|
|
def getBasePrice(self):
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def getEmblemPrices(self):
|
|
|
|
return ()
|
|
|
|
|
2015-05-28 12:55:37 -05:00
|
|
|
def hasEmblemPrices(self):
|
|
|
|
return len(self.getEmblemPrices()) >= ToontownGlobals.NumEmblemTypes
|
|
|
|
|
2015-03-03 16:10:12 -06:00
|
|
|
def loadModel(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def decodeDatagram(self, di, versionNumber, store):
|
|
|
|
if store & DeliveryDate:
|
|
|
|
self.deliveryDate = di.getUint32()
|
|
|
|
if store & Location:
|
|
|
|
x = di.getArg(STInt16, 10)
|
|
|
|
y = di.getArg(STInt16, 10)
|
|
|
|
z = di.getArg(STInt16, 100)
|
2015-07-17 08:51:45 -05:00
|
|
|
h = di.getArg(STInt16, 256.0 / 360.0)
|
|
|
|
p = di.getArg(STInt16, 256.0 / 360.0)
|
|
|
|
r = di.getArg(STInt16, 256.0 / 360.0)
|
2015-03-03 16:10:12 -06:00
|
|
|
self.posHpr = (x,
|
|
|
|
y,
|
|
|
|
z,
|
|
|
|
h,
|
|
|
|
p,
|
|
|
|
r)
|
|
|
|
if store & GiftTag:
|
2015-07-12 14:42:55 -05:00
|
|
|
self.giftTag = di.getUint32()
|
2015-05-14 12:54:08 -05:00
|
|
|
self.specialEventId = di.getUint8()
|
2015-03-03 16:10:12 -06:00
|
|
|
|
|
|
|
def encodeDatagram(self, dg, store):
|
|
|
|
if store & DeliveryDate:
|
|
|
|
dg.addUint32(self.deliveryDate)
|
|
|
|
if store & Location:
|
|
|
|
dg.putArg(self.posHpr[0], STInt16, 10)
|
|
|
|
dg.putArg(self.posHpr[1], STInt16, 10)
|
|
|
|
dg.putArg(self.posHpr[2], STInt16, 100)
|
2015-07-17 08:51:45 -05:00
|
|
|
dg.putArg(self.posHpr[3], STInt16, 256.0 / 360.0)
|
|
|
|
dg.putArg(self.posHpr[4], STInt16, 256.0 / 360.0)
|
|
|
|
dg.putArg(self.posHpr[5], STInt16, 256.0 / 360.0)
|
2015-03-03 16:10:12 -06:00
|
|
|
if store & GiftTag:
|
2015-07-17 08:51:45 -05:00
|
|
|
dg.addString(self.giftTag)
|
2015-03-03 16:10:12 -06:00
|
|
|
dg.addUint8(self.specialEventId)
|
|
|
|
|
|
|
|
def getTypeCode(self):
|
|
|
|
import CatalogItemTypes
|
|
|
|
return CatalogItemTypes.CatalogItemTypes[self.__class__]
|
|
|
|
|
|
|
|
def applyColor(self, model, colorDesc):
|
|
|
|
if model == None or colorDesc == None:
|
|
|
|
return
|
|
|
|
for partName, color in colorDesc:
|
|
|
|
matches = model.findAllMatches(partName)
|
|
|
|
if color == None:
|
|
|
|
matches.hide()
|
|
|
|
elif isinstance(color, types.StringType):
|
|
|
|
tex = loader.loadTexture(color)
|
|
|
|
tex.setMinfilter(Texture.FTLinearMipmapLinear)
|
|
|
|
tex.setMagfilter(Texture.FTLinear)
|
2015-07-05 20:02:35 -05:00
|
|
|
for i in xrange(matches.getNumPaths()):
|
2015-03-03 16:10:12 -06:00
|
|
|
matches.getPath(i).setTexture(tex, 1)
|
|
|
|
|
|
|
|
else:
|
|
|
|
needsAlpha = color[3] != 1
|
|
|
|
color = VBase4(color[0], color[1], color[2], color[3])
|
2015-07-05 20:02:35 -05:00
|
|
|
for i in xrange(matches.getNumPaths()):
|
2015-03-03 16:10:12 -06:00
|
|
|
matches.getPath(i).setColorScale(color, 1)
|
|
|
|
if needsAlpha:
|
|
|
|
matches.getPath(i).setTransparency(1)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
def makeFrame(self):
|
|
|
|
from direct.gui.DirectGui import DirectFrame
|
|
|
|
frame = DirectFrame(parent=hidden, frameSize=(-1.0, 1.0, -1.0, 1.0), relief=None)
|
|
|
|
return frame
|
|
|
|
|
|
|
|
def makeFrameModel(self, model, spin = 1):
|
|
|
|
frame = self.makeFrame()
|
|
|
|
ival = None
|
|
|
|
if model:
|
|
|
|
model.setDepthTest(1)
|
|
|
|
model.setDepthWrite(1)
|
|
|
|
if spin:
|
|
|
|
pitch = frame.attachNewNode('pitch')
|
|
|
|
rotate = pitch.attachNewNode('rotate')
|
|
|
|
scale = rotate.attachNewNode('scale')
|
|
|
|
model.reparentTo(scale)
|
|
|
|
bMin, bMax = model.getTightBounds()
|
|
|
|
center = (bMin + bMax) / 2.0
|
|
|
|
model.setPos(-center[0], -center[1], -center[2])
|
|
|
|
pitch.setP(20)
|
|
|
|
bMin, bMax = pitch.getTightBounds()
|
|
|
|
center = (bMin + bMax) / 2.0
|
|
|
|
corner = Vec3(bMax - center)
|
|
|
|
scale.setScale(1.0 / max(corner[0], corner[1], corner[2]))
|
|
|
|
pitch.setY(2)
|
|
|
|
ival = LerpHprInterval(rotate, 10, VBase3(-270, 0, 0), startHpr=VBase3(90, 0, 0))
|
|
|
|
else:
|
|
|
|
scale = frame.attachNewNode('scale')
|
|
|
|
model.reparentTo(scale)
|
|
|
|
bMin, bMax = model.getTightBounds()
|
|
|
|
center = (bMin + bMax) / 2.0
|
|
|
|
model.setPos(-center[0], 2, -center[2])
|
|
|
|
corner = Vec3(bMax - center)
|
|
|
|
scale.setScale(1.0 / max(corner[0], corner[1], corner[2]))
|
|
|
|
return (frame, ival)
|
|
|
|
|
|
|
|
def getBlob(self, store = 0):
|
|
|
|
dg = PyDatagram()
|
|
|
|
dg.addUint8(CatalogItemVersion)
|
|
|
|
encodeCatalogItem(dg, self, store)
|
|
|
|
return dg.getMessage()
|
|
|
|
|
|
|
|
def getRequestPurchaseErrorTextTimeout(self):
|
|
|
|
return 6
|
|
|
|
|
|
|
|
def encodeCatalogItem(dg, item, store):
|
|
|
|
import CatalogItemTypes
|
|
|
|
flags = item.getTypeCode()
|
|
|
|
if item.isSaleItem():
|
|
|
|
flags |= CatalogItemTypes.CatalogItemSaleFlag
|
|
|
|
if item.giftTag != None:
|
|
|
|
flags |= CatalogItemTypes.CatalogItemGiftTag
|
|
|
|
dg.addUint8(flags)
|
|
|
|
if item.giftTag != None:
|
|
|
|
dg.addUint32(item.giftTag)
|
|
|
|
if not item.giftCode:
|
|
|
|
item.giftCode = 0
|
|
|
|
dg.addUint8(item.giftCode)
|
|
|
|
item.encodeDatagram(dg, store)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
def decodeCatalogItem(di, versionNumber, store):
|
|
|
|
global CatalogReverseType
|
|
|
|
import CatalogItemTypes
|
|
|
|
if CatalogReverseType == None:
|
|
|
|
CatalogReverseType = {}
|
|
|
|
for itemClass, index in CatalogItemTypes.CatalogItemTypes.items():
|
|
|
|
CatalogReverseType[index] = itemClass
|
|
|
|
|
|
|
|
startIndex = di.getCurrentIndex()
|
|
|
|
try:
|
|
|
|
flags = di.getUint8()
|
|
|
|
typeIndex = flags & CatalogItemTypes.CatalogItemTypeMask
|
|
|
|
gift = None
|
|
|
|
code = None
|
|
|
|
if flags & CatalogItemTypes.CatalogItemGiftTag:
|
|
|
|
gift = di.getUint32()
|
|
|
|
code = di.getUint8()
|
|
|
|
itemClass = CatalogReverseType[typeIndex]
|
|
|
|
item = itemClass(di, versionNumber, store=store)
|
|
|
|
except Exception, e:
|
|
|
|
CatalogItem.notify.warning('Invalid catalog item in stream: %s, %s' % (sys.exc_info()[0], e))
|
|
|
|
d = Datagram(di.getDatagram().getMessage()[startIndex:])
|
|
|
|
d.dumpHex(Notify.out())
|
|
|
|
import CatalogInvalidItem
|
|
|
|
return CatalogInvalidItem.CatalogInvalidItem()
|
|
|
|
|
|
|
|
if flags & CatalogItemTypes.CatalogItemSaleFlag:
|
|
|
|
item.saleItem = 1
|
|
|
|
item.giftTag = gift
|
|
|
|
item.giftCode = code
|
|
|
|
return item
|
|
|
|
|
|
|
|
|
|
|
|
def getItem(blob, store = 0):
|
|
|
|
dg = PyDatagram(blob)
|
|
|
|
di = PyDatagramIterator(dg)
|
|
|
|
try:
|
|
|
|
versionNumber = di.getUint8()
|
|
|
|
return decodeCatalogItem(di, versionNumber, store)
|
|
|
|
except Exception, e:
|
|
|
|
CatalogItem.notify.warning('Invalid catalog item: %s, %s' % (sys.exc_info()[0], e))
|
|
|
|
dg.dumpHex(Notify.out())
|
|
|
|
import CatalogInvalidItem
|
|
|
|
return CatalogInvalidItem.CatalogInvalidItem()
|