1663 lines
72 KiB
Python
1663 lines
72 KiB
Python
from direct.directtools.DirectSelection import *
|
|
from direct.directtools.DirectUtil import ROUND_TO
|
|
from direct.directtools.DirectGeometry import LineNodePath
|
|
from direct.gui.DirectGui import *
|
|
from panda3d.core import *
|
|
from direct.showbase.DirectObject import DirectObject
|
|
from toontown.toonbase import ToontownGlobals
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.task import Task
|
|
from toontown.catalog import CatalogFurnitureItem
|
|
from toontown.catalog import CatalogItemTypes
|
|
from direct.showbase import PythonUtil
|
|
from toontown.toontowngui import TTDialog
|
|
from toontown.toonbase import TTLocalizer
|
|
from otp.otpbase import OTPLocalizer
|
|
camPos50 = (Point3(0.0, -10.0, 50.0),
|
|
Point3(0.0, -9.66, 49.06),
|
|
Point3(0.0, 1.5, 12.38),
|
|
Point3(0.0, 1.5, -3.1),
|
|
1)
|
|
camPos40 = (Point3(0.0, -15.0, 40.0),
|
|
Point3(0.0, -14.5, 39.13),
|
|
Point3(0.0, 1.5, 12.38),
|
|
Point3(0.0, 1.5, -3.1),
|
|
1)
|
|
camPos30 = (Point3(0.0, -20.0, 30.0),
|
|
Point3(0.0, -19.29, 29.29),
|
|
Point3(0.0, 1.5, 12.38),
|
|
Point3(0.0, 1.5, -3.1),
|
|
1)
|
|
camPos20 = (Point3(0.0, -20.0, 20.0),
|
|
Point3(0.0, -19.13, 19.5),
|
|
Point3(0.0, 1.5, 12.38),
|
|
Point3(0.0, 1.5, -3.1),
|
|
1)
|
|
camPosList = [camPos20,
|
|
camPos30,
|
|
camPos40,
|
|
camPos50]
|
|
DEFAULT_CAM_INDEX = 2
|
|
NormalPickerPanelColor = (1, 0.9, 0.745, 1)
|
|
DisabledPickerPanelColor = (0.7, 0.65, 0.58, 1)
|
|
DeletePickerPanelColor = (1, 0.4, 0.4, 1)
|
|
DisabledDeletePickerPanelColor = (0.7, 0.3, 0.3, 1)
|
|
|
|
class FurnitureItemPanel(DirectButton):
|
|
|
|
def __init__(self, item, itemId, command = None, deleteMode = 0, withinFunc = None, helpCategory = None):
|
|
self.item = item
|
|
self.itemId = itemId
|
|
self.command = command
|
|
self.origHelpCategory = helpCategory
|
|
self.deleteMode = deleteMode
|
|
if self.deleteMode:
|
|
framePanelColor = DeletePickerPanelColor
|
|
else:
|
|
framePanelColor = NormalPickerPanelColor
|
|
DirectButton.__init__(self, relief=DGG.RAISED, frameSize=(-0.25,
|
|
0.25,
|
|
-0.2,
|
|
0.2), frameColor=framePanelColor, borderWidth=(0.02, 0.02), command=self.clicked)
|
|
if self.deleteMode:
|
|
helpCategory = 'FurnitureItemPanelDelete'
|
|
self.bindHelpText(helpCategory)
|
|
if withinFunc:
|
|
self.bind(DGG.WITHIN, lambda event: withinFunc(self.itemId))
|
|
self.initialiseoptions(FurnitureItemPanel)
|
|
self.load()
|
|
|
|
def show(self):
|
|
DirectFrame.show(self)
|
|
if self.ival:
|
|
self.ival.resume()
|
|
|
|
def hide(self):
|
|
DirectFrame.hide(self)
|
|
if self.ival:
|
|
self.ival.pause()
|
|
|
|
def load(self):
|
|
panelWidth = 7
|
|
panelCenter = 0
|
|
self.picture, self.ival = self.item.getPicture(base.localAvatar)
|
|
if self.picture:
|
|
self.picture.reparentTo(self)
|
|
self.picture.setScale(0.14)
|
|
self.picture.setPos(0, 0, -0.02)
|
|
text = self.item.getName()
|
|
text_pos = (0, -0.1, 0)
|
|
else:
|
|
text = self.item.getTypeName() + ': ' + self.item.getName()
|
|
text_pos = (0, -0.3, 0)
|
|
if self.ival:
|
|
self.ival.loop()
|
|
self.ival.pause()
|
|
self.nameLabel = DirectLabel(parent=self, relief=None, pos=(0, 0, 0.17), scale=0.45, text=text, text_scale=0.15, text_fg=(0, 0, 0, 1), text_pos=text_pos, text_font=ToontownGlobals.getInterfaceFont(), text_wordwrap=panelWidth)
|
|
return
|
|
|
|
def clicked(self):
|
|
self.command(self.item, self.itemId)
|
|
|
|
def unload(self):
|
|
if self.item.hasPicture:
|
|
self.item.cleanupPicture()
|
|
del self.item
|
|
self.nameLabel.destroy()
|
|
del self.nameLabel
|
|
if self.ival:
|
|
self.ival.finish()
|
|
del self.ival
|
|
del self.picture
|
|
self.command = None
|
|
return
|
|
|
|
def destroy(self):
|
|
self.unload()
|
|
DirectButton.destroy(self)
|
|
|
|
def bindHelpText(self, category):
|
|
self.unbind(DGG.ENTER)
|
|
self.unbind(DGG.EXIT)
|
|
if category is None:
|
|
category = self.origHelpCategory
|
|
self.bind(DGG.ENTER, base.cr.objectManager.showHelpText, extraArgs=[category, self.item.getName()])
|
|
self.bind(DGG.EXIT, base.cr.objectManager.hideHelpText)
|
|
return
|
|
|
|
def setDeleteMode(self, deleteMode):
|
|
self.deleteMode = deleteMode
|
|
self.__updateAppearance()
|
|
|
|
def enable(self, enabled):
|
|
if enabled:
|
|
self['state'] = DGG.NORMAL
|
|
else:
|
|
self['state'] = DGG.DISABLED
|
|
self.__updateAppearance()
|
|
|
|
def __updateAppearance(self):
|
|
color = NormalPickerPanelColor
|
|
relief = DGG.RAISED
|
|
if self.deleteMode:
|
|
if self['state'] == DGG.DISABLED:
|
|
color = DisabledDeletePickerPanelColor
|
|
relief = DGG.SUNKEN
|
|
else:
|
|
color = DeletePickerPanelColor
|
|
relief = DGG.RAISED
|
|
elif self['state'] == DGG.DISABLED:
|
|
color = DisabledPickerPanelColor
|
|
relief = DGG.SUNKEN
|
|
else:
|
|
color = NormalPickerPanelColor
|
|
relief = DGG.RAISED
|
|
self['frameColor'] = color
|
|
|
|
|
|
class MovableObject(NodePath, DirectObject):
|
|
|
|
def __init__(self, dfitem, parent = render):
|
|
NodePath.__init__(self)
|
|
self.assign(dfitem)
|
|
self.dfitem = dfitem
|
|
dfitem.transmitRelativeTo = dfitem.getParent()
|
|
self.reparentTo(parent)
|
|
self.setTag('movableObject', '1')
|
|
self.builtInCNodes = self.findAllMatches('**/+CollisionNode')
|
|
self.numBuiltInNodes = self.builtInCNodes.getNumPaths()
|
|
self.stashBuiltInCollisionNodes()
|
|
shadows = self.findAllMatches('**/*shadow*')
|
|
shadows.addPathsFrom(self.findAllMatches('**/*Shadow*'))
|
|
shadows.stash()
|
|
flags = self.dfitem.item.getFlags()
|
|
if flags & CatalogFurnitureItem.FLPainting:
|
|
self.setOnFloor(0)
|
|
self.setOnWall(1)
|
|
else:
|
|
self.setOnFloor(1)
|
|
self.setOnWall(0)
|
|
if flags & CatalogFurnitureItem.FLOnTable:
|
|
self.setOnTable(1)
|
|
else:
|
|
self.setOnTable(0)
|
|
if flags & CatalogFurnitureItem.FLRug:
|
|
self.setIsRug(1)
|
|
else:
|
|
self.setIsRug(0)
|
|
if flags & CatalogFurnitureItem.FLIsTable:
|
|
self.setIsTable(1)
|
|
else:
|
|
self.setIsTable(0)
|
|
m = self.getTransform()
|
|
self.iPosHpr()
|
|
bMin, bMax = self.bounds = self.getTightBounds()
|
|
bMin -= Vec3(0.1, 0.1, 0)
|
|
bMax += Vec3(0.1, 0.1, 0)
|
|
self.c0 = Point3(bMin[0], bMin[1], 0.2)
|
|
self.c1 = Point3(bMax[0], bMin[1], 0.2)
|
|
self.c2 = Point3(bMax[0], bMax[1], 0.2)
|
|
self.c3 = Point3(bMin[0], bMax[1], 0.2)
|
|
self.center = (bMin + bMax) / 2.0
|
|
if flags & CatalogFurnitureItem.FLPainting:
|
|
self.dragPoint = Vec3(self.center[0], bMax[1], self.center[2])
|
|
else:
|
|
self.dragPoint = Vec3(self.center[0], self.center[1], bMin[2])
|
|
delta = self.dragPoint - self.c0
|
|
self.radius = min(delta[0], delta[1])
|
|
if self.getOnWall():
|
|
self.setWallOffset(0.1)
|
|
else:
|
|
self.setWallOffset(self.radius + 0.1)
|
|
self.makeCollisionBox()
|
|
self.setTransform(m)
|
|
self.unstashBuiltInCollisionNodes()
|
|
shadows.unstash()
|
|
|
|
def resetMovableObject(self):
|
|
self.unstashBuiltInCollisionNodes()
|
|
self.collisionNodePath.removeNode()
|
|
self.clearTag('movableObject')
|
|
|
|
def setOnFloor(self, fOnFloor):
|
|
self.fOnFloor = fOnFloor
|
|
|
|
def getOnFloor(self):
|
|
return self.fOnFloor
|
|
|
|
def setOnWall(self, fOnWall):
|
|
self.fOnWall = fOnWall
|
|
|
|
def getOnWall(self):
|
|
return self.fOnWall
|
|
|
|
def setOnTable(self, fOnTable):
|
|
self.fOnTable = fOnTable
|
|
|
|
def getOnTable(self):
|
|
return self.fOnTable
|
|
|
|
def setIsRug(self, fIsRug):
|
|
self.fIsRug = fIsRug
|
|
|
|
def getIsRug(self):
|
|
return self.fIsRug
|
|
|
|
def setIsTable(self, fIsTable):
|
|
self.fIsTable = fIsTable
|
|
|
|
def getIsTable(self):
|
|
return self.fIsTable
|
|
|
|
def setWallOffset(self, offset):
|
|
self.wallOffset = offset
|
|
|
|
def getWallOffset(self):
|
|
return self.wallOffset
|
|
|
|
def destroy(self):
|
|
self.removeNode()
|
|
|
|
def stashBuiltInCollisionNodes(self):
|
|
self.builtInCNodes.stash()
|
|
|
|
def unstashBuiltInCollisionNodes(self):
|
|
self.builtInCNodes.unstash()
|
|
|
|
def getFloorBitmask(self):
|
|
if self.getOnTable():
|
|
return ToontownGlobals.FloorBitmask | ToontownGlobals.FurnitureTopBitmask
|
|
else:
|
|
return ToontownGlobals.FloorBitmask
|
|
|
|
def getWallBitmask(self):
|
|
if self.getIsRug() or self.getOnWall():
|
|
return ToontownGlobals.WallBitmask
|
|
else:
|
|
return ToontownGlobals.WallBitmask | ToontownGlobals.FurnitureSideBitmask
|
|
|
|
def makeCollisionBox(self):
|
|
self.collisionNodePath = self.attachNewNode('furnitureCollisionNode')
|
|
if self.getIsRug() or self.getOnWall():
|
|
return
|
|
mx = self.bounds[0][0] - 0.01
|
|
Mx = self.bounds[1][0] + 0.01
|
|
my = self.bounds[0][1] - 0.01
|
|
My = self.bounds[1][1] + 0.01
|
|
mz = self.bounds[0][2]
|
|
Mz = self.bounds[1][2]
|
|
cn = CollisionNode('sideCollisionNode')
|
|
cn.setIntoCollideMask(ToontownGlobals.FurnitureSideBitmask)
|
|
self.collisionNodePath.attachNewNode(cn)
|
|
cp = CollisionPolygon(Point3(mx, My, mz), Point3(mx, my, mz), Point3(mx, my, Mz), Point3(mx, My, Mz))
|
|
cn.addSolid(cp)
|
|
cp = CollisionPolygon(Point3(Mx, my, mz), Point3(Mx, My, mz), Point3(Mx, My, Mz), Point3(Mx, my, Mz))
|
|
cn.addSolid(cp)
|
|
cp = CollisionPolygon(Point3(mx, my, mz), Point3(Mx, my, mz), Point3(Mx, my, Mz), Point3(mx, my, Mz))
|
|
cn.addSolid(cp)
|
|
cp = CollisionPolygon(Point3(Mx, My, mz), Point3(mx, My, mz), Point3(mx, My, Mz), Point3(Mx, My, Mz))
|
|
cn.addSolid(cp)
|
|
if self.getIsTable():
|
|
cn = CollisionNode('topCollisionNode')
|
|
cn.setIntoCollideMask(ToontownGlobals.FurnitureTopBitmask)
|
|
self.collisionNodePath.attachNewNode(cn)
|
|
cp = CollisionPolygon(Point3(mx, my, Mz), Point3(Mx, my, Mz), Point3(Mx, My, Mz), Point3(mx, My, Mz))
|
|
cn.addSolid(cp)
|
|
|
|
|
|
class ObjectManager(NodePath, DirectObject):
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('ObjectManager')
|
|
|
|
def __init__(self):
|
|
NodePath.__init__(self)
|
|
self.assign(render.attachNewNode('objectManager'))
|
|
self.objectDict = {}
|
|
self.selectedObject = None
|
|
self.movingObject = 0
|
|
self.deselectEvent = None
|
|
self.startPose = render.attachNewNode('startPose')
|
|
self.dragPointNP = self.attachNewNode('dragPoint')
|
|
self.gridSnapNP = self.dragPointNP.attachNewNode('gridSnap')
|
|
self.collisionOffsetNP = self.gridSnapNP.attachNewNode('collisionResponse')
|
|
self.iRay = SelectionRay()
|
|
self.iSegment = SelectionSegment(numSegments=6)
|
|
self.iSegment4 = SelectionSegment(numSegments=4)
|
|
self.iSphere = SelectionSphere()
|
|
self.houseExtents = None
|
|
self.doorBlocker = None
|
|
cp = CollisionPolygon(Point3(-100, -100, 0), Point3(100, -100, 0), Point3(100, 100, 0), Point3(-100, 100, 0))
|
|
cn = CollisionNode('dragCollisionNode')
|
|
cn.addSolid(cp)
|
|
cn.setIntoCollideMask(ToontownGlobals.FurnitureDragBitmask)
|
|
self.collisionNP = NodePath(cn)
|
|
self.lnp = LineNodePath()
|
|
self.fRecenter = 0
|
|
self.gridSpacing = None
|
|
self.firstTime = 0
|
|
guiModels = loader.loadModel('phase_5.5/models/gui/house_design_gui')
|
|
self.createSelectedObjectPanel(guiModels)
|
|
self.createMainControls(guiModels)
|
|
self.furnitureManager = None
|
|
self.atticPicker = None
|
|
self.inRoomPicker = None
|
|
self.inTrashPicker = None
|
|
self.dialog = None
|
|
self.deleteMode = 0
|
|
self.nonDeletableItem = None
|
|
self.verifyFrame = None
|
|
self.deleteItemText = None
|
|
self.okButton = None
|
|
self.cancelButton = None
|
|
self.itemIval = None
|
|
self.itemPanel = None
|
|
self.guiInterval = None
|
|
self.accept('enterFurnitureMode', self.enterFurnitureMode)
|
|
self.accept('exitFurnitureMode', self.exitFurnitureMode)
|
|
return
|
|
|
|
def enterFurnitureMode(self, furnitureManager, fDirector):
|
|
if not fDirector:
|
|
if self.furnitureManager:
|
|
self.exitFurnitureMode(self.furnitureManager)
|
|
return
|
|
if furnitureManager == self.furnitureManager:
|
|
return
|
|
if self.furnitureManager != None:
|
|
self.exitFurnitureMode(self.furnitureManager)
|
|
self.notify.info('enterFurnitureMode, fDirector = %s' % fDirector)
|
|
self.furnitureManager = furnitureManager
|
|
self.furnitureManager.d_avatarEnter()
|
|
house = furnitureManager.getInteriorObject()
|
|
house.hideExteriorWindows()
|
|
self.setTargetNodePath(house.interior)
|
|
self.createAtticPicker()
|
|
self.initializeDistributedFurnitureItems(furnitureManager.dfitems)
|
|
self.setCamPosIndex(DEFAULT_CAM_INDEX)
|
|
base.localAvatar.setGhostMode(1)
|
|
taskMgr.remove('editModeTransition')
|
|
self.orientCamH(base.localAvatar.getH(self.targetNodePath))
|
|
self.accept('mouse1', self.moveObjectStart)
|
|
self.accept('mouse1-up', self.moveObjectStop)
|
|
self.furnitureGui.show()
|
|
self.deleteMode = 0
|
|
self.__updateDeleteButtons()
|
|
self.showAtticPicker()
|
|
base.localAvatar.laffMeter.stop()
|
|
base.setCellsAvailable(base.leftCells + [base.bottomCells[0]], 0)
|
|
if self.guiInterval:
|
|
self.guiInterval.finish()
|
|
self.guiInterval = self.furnitureGui.posHprScaleInterval(1.0, Point3(0.155, -0.6, -1.045), Vec3(0), Vec3(0.06), startPos=Point3(0.115, 0.0, -0.66), startHpr=Vec3(0), startScale=Vec3(0.04), blendType='easeInOut', name='lerpFurnitureButton')
|
|
self.guiInterval.start()
|
|
taskMgr.add(self.recenterButtonFrameTask, 'recenterButtonFrameTask', 10)
|
|
messenger.send('wakeup')
|
|
return
|
|
|
|
def exitFurnitureMode(self, furnitureManager):
|
|
if furnitureManager != self.furnitureManager:
|
|
return
|
|
self.notify.info('exitFurnitureMode')
|
|
house = furnitureManager.getInteriorObject()
|
|
if house:
|
|
house.showExteriorWindows()
|
|
self.furnitureManager.d_avatarExit()
|
|
self.furnitureManager = None
|
|
base.localAvatar.setCameraPositionByIndex(0)
|
|
self.exitDeleteMode()
|
|
self.houseExtents.detachNode()
|
|
self.doorBlocker.detachNode()
|
|
self.deselectObject()
|
|
self.ignore('mouse1')
|
|
self.ignore('mouse1-up')
|
|
if self.atticPicker:
|
|
self.atticPicker.destroy()
|
|
self.atticPicker = None
|
|
if self.inRoomPicker:
|
|
self.inRoomPicker.destroy()
|
|
self.inRoomPicker = None
|
|
if self.inTrashPicker:
|
|
self.inTrashPicker.destroy()
|
|
self.inTrashPicker = None
|
|
self.__cleanupVerifyDelete()
|
|
self.furnitureGui.hide()
|
|
base.setCellsAvailable(base.leftCells + [base.bottomCells[0]], 1)
|
|
base.localAvatar.laffMeter.start()
|
|
taskMgr.remove('recenterButtonFrameTask')
|
|
self.cleanupDialog()
|
|
taskMgr.remove('showHelpTextDoLater')
|
|
messenger.send('wakeup')
|
|
return
|
|
|
|
def initializeDistributedFurnitureItems(self, dfitems):
|
|
self.objectDict = {}
|
|
for item in dfitems:
|
|
mo = MovableObject(item, parent=self.targetNodePath)
|
|
self.objectDict[mo.get_key()] = mo
|
|
|
|
def setCamPosIndex(self, index):
|
|
self.camPosIndex = index
|
|
base.localAvatar.setCameraSettings(camPosList[index])
|
|
|
|
def zoomCamIn(self):
|
|
self.setCamPosIndex(max(0, self.camPosIndex - 1))
|
|
messenger.send('wakeup')
|
|
|
|
def zoomCamOut(self):
|
|
self.setCamPosIndex(min(len(camPosList) - 1, self.camPosIndex + 1))
|
|
messenger.send('wakeup')
|
|
|
|
def rotateCamCW(self):
|
|
self.orientCamH(base.localAvatar.getH(self.targetNodePath) - 90)
|
|
messenger.send('wakeup')
|
|
|
|
def rotateCamCCW(self):
|
|
self.orientCamH(base.localAvatar.getH(self.targetNodePath) + 90)
|
|
messenger.send('wakeup')
|
|
|
|
def orientCamH(self, toonH):
|
|
targetH = ROUND_TO(toonH, 90)
|
|
base.localAvatar.hprInterval(duration=1, hpr=Vec3(targetH, 0, 0), other=self.targetNodePath, blendType='easeInOut', name='editModeTransition').start()
|
|
|
|
def setTargetNodePath(self, nodePath):
|
|
self.targetNodePath = nodePath
|
|
if self.houseExtents:
|
|
self.houseExtents.removeNode()
|
|
if self.doorBlocker:
|
|
self.doorBlocker.removeNode()
|
|
self.makeHouseExtentsBox()
|
|
self.makeDoorBlocker()
|
|
self.collisionNP.reparentTo(self.targetNodePath)
|
|
|
|
def loadObject(self, filename):
|
|
mo = MovableObject(filename, parent=self.targetNodePath)
|
|
self.objectDict[mo.get_key()] = mo
|
|
self.selectObject(mo)
|
|
return mo
|
|
|
|
def pickObject(self):
|
|
self.iRay.setParentNP(base.cam)
|
|
entry = self.iRay.pickGeom(targetNodePath=self.targetNodePath, skipFlags=SKIP_ALL)
|
|
if entry:
|
|
nodePath = entry.getIntoNodePath()
|
|
if self.isMovableObject(nodePath):
|
|
self.selectObject(self.findObject(nodePath))
|
|
return
|
|
self.deselectObject()
|
|
|
|
def pickInRoom(self, objectId):
|
|
self.selectObject(self.objectDict.get(objectId))
|
|
|
|
def selectObject(self, selectedObject):
|
|
messenger.send('wakeup')
|
|
if self.selectedObject:
|
|
self.deselectObject()
|
|
if selectedObject:
|
|
self.selectedObject = selectedObject
|
|
self.deselectEvent = self.selectedObject.dfitem.uniqueName('disable')
|
|
self.acceptOnce(self.deselectEvent, self.deselectObject)
|
|
self.lnp.reset()
|
|
self.lnp.reparentTo(selectedObject)
|
|
self.lnp.moveTo(selectedObject.c0)
|
|
self.lnp.drawTo(selectedObject.c1)
|
|
self.lnp.drawTo(selectedObject.c2)
|
|
self.lnp.drawTo(selectedObject.c3)
|
|
self.lnp.drawTo(selectedObject.c0)
|
|
self.lnp.create()
|
|
self.buttonFrame.show()
|
|
self.enableButtonFrameTask()
|
|
self.sendToAtticButton.show()
|
|
self.atticRoof.hide()
|
|
|
|
def deselectObject(self):
|
|
self.moveObjectStop()
|
|
if self.deselectEvent:
|
|
self.ignore(self.deselectEvent)
|
|
self.deselectEvent = None
|
|
self.selectedObject = None
|
|
self.lnp.detachNode()
|
|
self.buttonFrame.hide()
|
|
self.disableButtonFrameTask()
|
|
self.sendToAtticButton.hide()
|
|
self.atticRoof.show()
|
|
return
|
|
|
|
def isMovableObject(self, nodePath):
|
|
return nodePath.hasNetTag('movableObject')
|
|
|
|
def findObject(self, nodePath):
|
|
np = nodePath.findNetTag('movableObject')
|
|
if np.isEmpty():
|
|
return None
|
|
else:
|
|
return self.objectDict.get(np.get_key(), None)
|
|
return None
|
|
|
|
def moveObjectStop(self, *args):
|
|
if self.movingObject:
|
|
self.movingObject = 0
|
|
taskMgr.remove('moveObjectTask')
|
|
if self.selectedObject:
|
|
self.selectedObject.wrtReparentTo(self.targetNodePath)
|
|
self.selectedObject.collisionNodePath.unstash()
|
|
self.selectedObject.dfitem.stopAdjustPosHpr()
|
|
for object in self.objectDict.values():
|
|
object.unstashBuiltInCollisionNodes()
|
|
|
|
self.centerMarker['image'] = [self.grabUp, self.grabDown, self.grabRollover]
|
|
self.centerMarker.configure(text=['', TTLocalizer.HDMoveLabel], text_pos=(0, 1), text_scale=0.7, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), image_scale=0.3)
|
|
|
|
def moveObjectStart(self):
|
|
self.moveObjectStop()
|
|
self.pickObject()
|
|
self.moveObjectContinue()
|
|
|
|
def moveObjectContinue(self, *args):
|
|
messenger.send('wakeup')
|
|
if self.selectedObject:
|
|
for object in self.objectDict.values():
|
|
object.stashBuiltInCollisionNodes()
|
|
|
|
self.selectedObject.collisionNodePath.stash()
|
|
self.selectedObject.dfitem.startAdjustPosHpr()
|
|
self.firstTime = 1
|
|
self.iPosHpr()
|
|
self.startPoseValid = 0
|
|
self.centerMarker['image'] = self.grabDown
|
|
self.centerMarker.configure(text=TTLocalizer.HDMoveLabel, text_pos=(0, 1), text_scale=0.7, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), image_scale=0.3)
|
|
taskMgr.add(self.moveObjectTask, 'moveObjectTask')
|
|
self.movingObject = 1
|
|
|
|
def setLnpColor(self, r, g, b):
|
|
for i in xrange(5):
|
|
self.lnp.lineSegs.setVertexColor(i, r, g, b)
|
|
|
|
def markNewPosition(self, isValid):
|
|
if not isValid:
|
|
if self.startPoseValid:
|
|
self.collisionOffsetNP.setPosHpr(self.startPose, self.selectedObject.dragPoint, Vec3(0))
|
|
else:
|
|
self.startPoseValid = 1
|
|
|
|
def moveObjectTask(self, state):
|
|
so = self.selectedObject
|
|
target = self.targetNodePath
|
|
self.startPose.iPosHpr(so)
|
|
self.iRay.setParentNP(base.cam)
|
|
entry = self.iRay.pickBitMask(bitMask=ToontownGlobals.FurnitureDragBitmask, targetNodePath=target, skipFlags=SKIP_BACKFACE | SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
if not entry:
|
|
return Task.cont
|
|
self.setPos(base.cam, entry.getSurfacePoint(base.cam))
|
|
if self.firstTime:
|
|
self.moveObjectInit()
|
|
self.firstTime = 0
|
|
else:
|
|
self.gridSnapNP.iPos()
|
|
self.collisionOffsetNP.iPosHpr()
|
|
if self.gridSpacing:
|
|
pos = self.dragPointNP.getPos(target)
|
|
self.gridSnapNP.setPos(target, ROUND_TO(pos[0], self.gridSpacing), ROUND_TO(pos[1], self.gridSpacing), pos[2])
|
|
self.iRay.setParentNP(base.cam)
|
|
entry = self.iRay.pickBitMask3D(bitMask=so.getWallBitmask(), targetNodePath=target, dir=Vec3(self.getNearProjectionPoint(self.gridSnapNP)), skipFlags=SKIP_BACKFACE | SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
fWall = 0
|
|
if not so.getOnTable():
|
|
while entry:
|
|
intoMask = entry.getIntoNodePath().node().getIntoCollideMask()
|
|
fClosest = (intoMask & ToontownGlobals.WallBitmask).isZero()
|
|
if self.alignObject(entry, target, fClosest=fClosest):
|
|
fWall = 1
|
|
break
|
|
entry = self.iRay.findNextCollisionEntry(skipFlags=SKIP_BACKFACE | SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
|
|
if so.getOnWall():
|
|
self.markNewPosition(fWall)
|
|
return Task.cont
|
|
self.iRay.setParentNP(target)
|
|
entry = self.iRay.pickBitMask3D(bitMask=so.getFloorBitmask(), targetNodePath=target, origin=Point3(self.gridSnapNP.getPos(target) + Vec3(0, 0, 10)), dir=Vec3(0, 0, -1), skipFlags=SKIP_BACKFACE | SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
if not entry:
|
|
self.markNewPosition(0)
|
|
return Task.cont
|
|
nodePath = entry.getIntoNodePath()
|
|
if self.isMovableObject(nodePath):
|
|
self.gridSnapNP.setPos(target, Point3(entry.getSurfacePoint(target)))
|
|
else:
|
|
self.gridSnapNP.setPos(target, Point3(entry.getSurfacePoint(target) + Vec3(0, 0, ToontownGlobals.FloorOffset)))
|
|
if not fWall:
|
|
self.iSphere.setParentNP(self.gridSnapNP)
|
|
self.iSphere.setCenterRadius(0, Point3(0), so.radius * 1.25)
|
|
entry = self.iSphere.pickBitMask(bitMask=so.getWallBitmask(), targetNodePath=target, skipFlags=SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
if entry:
|
|
self.alignObject(entry, target, fClosest=1)
|
|
isValid = self.collisionTest()
|
|
self.markNewPosition(isValid)
|
|
return Task.cont
|
|
|
|
def collisionTest(self):
|
|
so = self.selectedObject
|
|
target = self.targetNodePath
|
|
entry = self.segmentCollision()
|
|
if not entry:
|
|
return 1
|
|
offsetDict = {}
|
|
while entry:
|
|
offset = self.computeSegmentOffset(entry)
|
|
if offset:
|
|
eid = entry.getInto()
|
|
maxOffsetVec = offsetDict.get(eid, Vec3(0))
|
|
if offset.length() > maxOffsetVec.length():
|
|
maxOffsetVec.assign(offset)
|
|
offsetDict[eid] = maxOffsetVec
|
|
entry = self.iSegment.findNextCollisionEntry(skipFlags=SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
|
|
if offsetDict:
|
|
keys = offsetDict.keys()
|
|
ortho1 = offsetDict[keys[0]]
|
|
ortho2 = Vec3(0)
|
|
v1 = Vec3(ortho1)
|
|
v1.normalize()
|
|
for key in keys[1:]:
|
|
offset = offsetDict[key]
|
|
v2 = Vec3(offset)
|
|
v2.normalize()
|
|
dp = v1.dot(v2)
|
|
if abs(dp) > 0.95:
|
|
if offset.length() > ortho1.length():
|
|
ortho1.assign(offset)
|
|
elif abs(dp) < 0.05:
|
|
if offset.length() > ortho2.length():
|
|
ortho2.assign(offset)
|
|
else:
|
|
o1Len = ortho1.length()
|
|
parallelVec = Vec3(ortho1 * offset.dot(ortho1) / (o1Len * o1Len))
|
|
perpVec = Vec3(offset - parallelVec)
|
|
if parallelVec.length() > o1Len:
|
|
ortho1.assign(parallelVec)
|
|
if perpVec.length() > ortho2.length():
|
|
ortho2.assign(perpVec)
|
|
|
|
totalOffset = ortho1 + ortho2
|
|
self.collisionOffsetNP.setPos(self.collisionOffsetNP, totalOffset)
|
|
if not self.segmentCollision():
|
|
return 1
|
|
m = self.startPose.getMat(so)
|
|
deltaMove = Vec3(m.getRow3(3))
|
|
if deltaMove.length() == 0:
|
|
return 1
|
|
self.iSegment4.setParentNP(so)
|
|
entry = self.iSegment4.pickBitMask(bitMask=so.getWallBitmask(), targetNodePath=target, endPointList=[(so.c0, Point3(m.xformPoint(so.c0))),
|
|
(so.c1, Point3(m.xformPoint(so.c1))),
|
|
(so.c2, Point3(m.xformPoint(so.c2))),
|
|
(so.c3, Point3(m.xformPoint(so.c3)))], skipFlags=SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
maxLen = 0
|
|
maxOffset = None
|
|
while entry:
|
|
offset = Vec3(entry.getSurfacePoint(entry.getFromNodePath()) - entry.getFrom().getPointA())
|
|
offsetLen = Vec3(offset).length()
|
|
if offsetLen > maxLen:
|
|
maxLen = offsetLen
|
|
maxOffset = offset
|
|
entry = self.iSegment4.findNextCollisionEntry(skipFlags=SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
|
|
if maxOffset:
|
|
self.collisionOffsetNP.setPos(self.collisionOffsetNP, maxOffset)
|
|
if not self.segmentCollision():
|
|
return 1
|
|
return 0
|
|
|
|
def segmentCollision(self):
|
|
so = self.selectedObject
|
|
self.iSegment.setParentNP(so)
|
|
entry = self.iSegment.pickBitMask(bitMask=so.getWallBitmask(), targetNodePath=self.targetNodePath, endPointList=[(so.c0, so.c1),
|
|
(so.c1, so.c2),
|
|
(so.c2, so.c3),
|
|
(so.c3, so.c0),
|
|
(so.c0, so.c2),
|
|
(so.c1, so.c3)], skipFlags=SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
return entry
|
|
|
|
def computeSegmentOffset(self, entry):
|
|
fromNodePath = entry.getFromNodePath()
|
|
if entry.hasSurfaceNormal():
|
|
normal = entry.getSurfaceNormal(fromNodePath)
|
|
else:
|
|
return None
|
|
hitPoint = entry.getSurfacePoint(fromNodePath)
|
|
m = self.selectedObject.getMat(self.startPose)
|
|
hp = Point3(m.xformPoint(hitPoint))
|
|
hpn = Vec3(m.xformVec(normal))
|
|
hitPointVec = Vec3(hp - self.selectedObject.dragPoint)
|
|
if hitPointVec.dot(hpn) > 0:
|
|
return None
|
|
nLen = normal.length()
|
|
offsetVecA = hitPoint - entry.getFrom().getPointA()
|
|
offsetA = normal * offsetVecA.dot(normal) / (nLen * nLen)
|
|
if offsetA.dot(normal) > 0:
|
|
return offsetA * 1.01
|
|
else:
|
|
offsetVecB = hitPoint - entry.getFrom().getPointB()
|
|
offsetB = normal * offsetVecB.dot(normal) / (nLen * nLen)
|
|
return offsetB * 1.01
|
|
return None
|
|
|
|
def alignObject(self, entry, target, fClosest = 0, wallOffset = None):
|
|
if not entry.hasSurfaceNormal():
|
|
return 0
|
|
normal = entry.getSurfaceNormal(target)
|
|
if abs(normal.dot(Vec3(0, 0, 1))) < 0.1:
|
|
tempNP = target.attachNewNode('temp')
|
|
normal.setZ(0)
|
|
normal.normalize()
|
|
lookAtNormal = Point3(normal)
|
|
lookAtNormal *= -1
|
|
tempNP.lookAt(lookAtNormal)
|
|
realAngle = ROUND_TO(self.gridSnapNP.getH(tempNP), 90.0)
|
|
if fClosest:
|
|
angle = realAngle
|
|
else:
|
|
angle = 0
|
|
self.gridSnapNP.setHpr(tempNP, angle, 0, 0)
|
|
hitPoint = entry.getSurfacePoint(target)
|
|
tempNP.setPos(hitPoint)
|
|
if wallOffset == None:
|
|
wallOffset = self.selectedObject.getWallOffset()
|
|
self.gridSnapNP.setPos(tempNP, 0, -wallOffset, 0)
|
|
tempNP.removeNode()
|
|
if realAngle == 180.0:
|
|
self.gridSnapNP.setH(self.gridSnapNP.getH() + 180.0)
|
|
return 1
|
|
return 0
|
|
|
|
def rotateLeft(self):
|
|
if not self.selectedObject:
|
|
return
|
|
so = self.selectedObject
|
|
so.dfitem.startAdjustPosHpr()
|
|
self.iPosHpr(so)
|
|
self.moveObjectInit()
|
|
if so.getOnWall():
|
|
startR = self.gridSnapNP.getR()
|
|
newR = ROUND_TO(startR + 22.5, 22.5)
|
|
self.gridSnapNP.setR(newR)
|
|
else:
|
|
startH = self.gridSnapNP.getH(self.targetNodePath)
|
|
newH = ROUND_TO(startH - 22.5, 22.5)
|
|
self.iSphere.setParentNP(self.gridSnapNP)
|
|
self.iSphere.setCenterRadius(0, Point3(0), so.radius * 1.25)
|
|
entry = self.iSphere.pickBitMask(bitMask=so.getWallBitmask(), targetNodePath=self.targetNodePath, skipFlags=SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
if not entry:
|
|
self.gridSnapNP.setHpr(self.targetNodePath, newH, 0, 0)
|
|
self.collisionTest()
|
|
so.wrtReparentTo(self.targetNodePath)
|
|
self.disableButtonFrameTask()
|
|
so.dfitem.stopAdjustPosHpr()
|
|
|
|
def rotateRight(self):
|
|
if not self.selectedObject:
|
|
return
|
|
so = self.selectedObject
|
|
so.dfitem.startAdjustPosHpr()
|
|
self.iPosHpr(so)
|
|
self.moveObjectInit()
|
|
if so.getOnWall():
|
|
startR = self.gridSnapNP.getR()
|
|
newR = ROUND_TO(startR - 22.5, 22.5)
|
|
self.gridSnapNP.setR(newR)
|
|
else:
|
|
startH = self.gridSnapNP.getH(self.targetNodePath)
|
|
newH = ROUND_TO(startH + 22.5, 22.5) % 360.0
|
|
self.iSphere.setParentNP(self.gridSnapNP)
|
|
self.iSphere.setCenterRadius(0, Point3(0), so.radius * 1.25)
|
|
entry = self.iSphere.pickBitMask(bitMask=so.getWallBitmask(), targetNodePath=self.targetNodePath, skipFlags=SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
if not entry:
|
|
self.gridSnapNP.setHpr(self.targetNodePath, newH, 0, 0)
|
|
self.collisionTest()
|
|
so.wrtReparentTo(self.targetNodePath)
|
|
self.disableButtonFrameTask()
|
|
so.dfitem.stopAdjustPosHpr()
|
|
|
|
def moveObjectInit(self):
|
|
self.dragPointNP.setPosHpr(self.selectedObject, self.selectedObject.dragPoint, Vec3(0))
|
|
self.gridSnapNP.iPosHpr()
|
|
self.collisionOffsetNP.iPosHpr()
|
|
self.selectedObject.wrtReparentTo(self.collisionOffsetNP)
|
|
|
|
def resetFurniture(self):
|
|
for o in self.objectDict.values():
|
|
o.resetMovableObject()
|
|
|
|
self.objectDict = {}
|
|
self.deselectObject()
|
|
self.buttonFrame.hide()
|
|
|
|
def destroy(self):
|
|
self.ignore('enterFurnitureMode')
|
|
self.ignore('exitFurnitureMode')
|
|
if self.guiInterval:
|
|
self.guiInterval.finish()
|
|
if self.furnitureManager:
|
|
self.exitFurnitureMode(self.furnitureManager)
|
|
self.cleanupDialog()
|
|
self.resetFurniture()
|
|
self.buttonFrame.destroy()
|
|
self.furnitureGui.destroy()
|
|
if self.houseExtents:
|
|
self.houseExtents.removeNode()
|
|
if self.doorBlocker:
|
|
self.doorBlocker.removeNode()
|
|
self.removeNode()
|
|
if self.verifyFrame:
|
|
self.verifyFrame.destroy()
|
|
self.verifyFrame = None
|
|
self.deleteItemText = None
|
|
self.okButton = None
|
|
self.cancelButton = None
|
|
return
|
|
|
|
def createSelectedObjectPanel(self, guiModels):
|
|
self.buttonFrame = DirectFrame(scale=0.5)
|
|
self.grabUp = guiModels.find('**/handup')
|
|
self.grabDown = guiModels.find('**/handdown')
|
|
self.grabRollover = guiModels.find('**/handrollover')
|
|
self.centerMarker = DirectButton(parent=self.buttonFrame, text=['', TTLocalizer.HDMoveLabel], text_pos=(0, 1), text_scale=0.7, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), image=[self.grabUp, self.grabDown, self.grabRollover], image_scale=0.3, relief=None, scale=0.12)
|
|
self.centerMarker.bind(DGG.B1PRESS, self.moveObjectContinue)
|
|
self.centerMarker.bind(DGG.B1RELEASE, self.moveObjectStop)
|
|
guiCCWArrowUp = guiModels.find('**/LarrowUp')
|
|
guiCCWArrowDown = guiModels.find('**/LarrowDown')
|
|
guiCCWArrowRollover = guiModels.find('**/LarrowRollover')
|
|
self.rotateLeftButton = DirectButton(parent=self.buttonFrame, relief=None, image=(guiCCWArrowUp,
|
|
guiCCWArrowDown,
|
|
guiCCWArrowRollover,
|
|
guiCCWArrowUp), image_pos=(0, 0, 0.1), image_scale=0.15, image3_color=Vec4(0.5, 0.5, 0.5, 0.75), text=('',
|
|
TTLocalizer.HDRotateCCWLabel,
|
|
TTLocalizer.HDRotateCCWLabel,
|
|
''), text_pos=(0.135, -0.1), text_scale=0.1, text_align=TextNode.ARight, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), pos=(-.125, 0, -.2), scale=0.7, command=self.rotateLeft)
|
|
self.rotateLeftButton.bind(DGG.EXIT, self.enableButtonFrameTask)
|
|
guiCWArrowUp = guiModels.find('**/RarrowUp')
|
|
guiCWArrowDown = guiModels.find('**/RarrowDown')
|
|
guiCWArrowRollover = guiModels.find('**/RarrowRollover')
|
|
self.rotateRightButton = DirectButton(parent=self.buttonFrame, relief=None, image=(guiCWArrowUp,
|
|
guiCWArrowDown,
|
|
guiCWArrowRollover,
|
|
guiCWArrowUp), image_pos=(0, 0, 0.1), image_scale=0.15, image3_color=Vec4(0.5, 0.5, 0.5, 0.75), text=('',
|
|
TTLocalizer.HDRotateCWLabel,
|
|
TTLocalizer.HDRotateCWLabel,
|
|
''), text_pos=(-0.135, -0.1), text_scale=0.1, text_align=TextNode.ALeft, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), pos=(0.125, 0, -0.2), scale=0.7, command=self.rotateRight)
|
|
self.rotateRightButton.bind(DGG.EXIT, self.enableButtonFrameTask)
|
|
self.buttonFrame.hide()
|
|
return
|
|
|
|
def recenterButtonFrameTask(self, state):
|
|
if self.selectedObject and self.fRecenter:
|
|
self.buttonFrame.setPos(self.getSelectedObjectScreenXY())
|
|
return Task.cont
|
|
|
|
def disableButtonFrameTask(self, event = None):
|
|
self.fRecenter = 0
|
|
|
|
def enableButtonFrameTask(self, event = None):
|
|
self.fRecenter = 1
|
|
|
|
def getNearProjectionPoint(self, nodePath):
|
|
origin = nodePath.getPos(camera)
|
|
if origin[1] != 0.0:
|
|
return origin * (base.camLens.getNear() / origin[1])
|
|
else:
|
|
return Point3(0, base.camLens.getNear(), 0)
|
|
|
|
def getSelectedObjectScreenXY(self):
|
|
tNodePath = self.selectedObject.attachNewNode('temp')
|
|
tNodePath.setPos(self.selectedObject.center)
|
|
nearVec = self.getNearProjectionPoint(tNodePath)
|
|
nearVec *= base.camLens.getFocalLength() / base.camLens.getNear()
|
|
render2dX = CLAMP(nearVec[0] / (base.camLens.getFilmSize()[0] / 2.0), -.9, 0.9)
|
|
aspect2dX = render2dX * base.getAspectRatio()
|
|
aspect2dZ = CLAMP(nearVec[2] / (base.camLens.getFilmSize()[1] / 2.0), -.8, 0.9)
|
|
tNodePath.removeNode()
|
|
return Vec3(aspect2dX, 0, aspect2dZ)
|
|
|
|
def createMainControls(self, guiModels):
|
|
attic = guiModels.find('**/attic')
|
|
self.furnitureGui = DirectFrame(relief=None, parent=base.a2dTopLeft, pos=(0.155, -0.6, -1.045), scale=0.04, image=attic)
|
|
bMoveStopUp = guiModels.find('**/bu_atticX/bu_attic_up')
|
|
bMoveStopDown = guiModels.find('**/bu_atticX/bu_attic_down')
|
|
bMoveStopRollover = guiModels.find('**/bu_atticX/bu_attic_rollover')
|
|
self.bStopMoveFurniture = DirectButton(parent=self.furnitureGui, relief=None, image=[bMoveStopUp,
|
|
bMoveStopDown,
|
|
bMoveStopRollover,
|
|
bMoveStopUp], text=['', TTLocalizer.HDStopMoveFurnitureButton, TTLocalizer.HDStopMoveFurnitureButton], text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getInterfaceFont(), pos=(-0.3, 0, 9.4), command=base.localAvatar.stopMoveFurniture)
|
|
self.bindHelpText(self.bStopMoveFurniture, 'DoneMoving')
|
|
self.atticRoof = DirectLabel(parent=self.furnitureGui, relief=None, image=guiModels.find('**/rooftile'))
|
|
self.itemBackgroundFrame = DirectFrame(parent=self.furnitureGui, relief=None, image=guiModels.find('**/item_backgroun'), image_pos=(0, 0, -22), image_scale=(1, 1, 5))
|
|
self.scrollUpFrame = DirectFrame(parent=self.furnitureGui, relief=None, image=guiModels.find('**/scrollup'), pos=(0, 0, -0.58))
|
|
self.camButtonFrame = DirectFrame(parent=self.furnitureGui, relief=None, image=guiModels.find('**/low'), pos=(0, 0, -11.69))
|
|
tagUp = guiModels.find('**/tag_up')
|
|
tagDown = guiModels.find('**/tag_down')
|
|
tagRollover = guiModels.find('**/tag_rollover')
|
|
self.inAtticButton = DirectButton(parent=self.itemBackgroundFrame, relief=None, text=TTLocalizer.HDInAtticLabel, text_pos=(-0.1, -0.25), image=[tagUp, tagDown, tagRollover], pos=(2.85, 0, 4), scale=0.8, command=self.showAtticPicker)
|
|
self.bindHelpText(self.inAtticButton, 'Attic')
|
|
self.inRoomButton = DirectButton(parent=self.itemBackgroundFrame, relief=None, text=TTLocalizer.HDInRoomLabel, text_pos=(-0.1, -0.25), image=[tagUp, tagDown, tagRollover], pos=(2.85, 0, 1.1), scale=0.8, command=self.showInRoomPicker)
|
|
self.bindHelpText(self.inRoomButton, 'Room')
|
|
self.inTrashButton = DirectButton(parent=self.itemBackgroundFrame, relief=None, text=TTLocalizer.HDInTrashLabel, text_pos=(-0.1, -0.25), image=[tagUp, tagDown, tagRollover], pos=(2.85, 0, -1.8), scale=0.8, command=self.showInTrashPicker)
|
|
self.bindHelpText(self.inTrashButton, 'Trash')
|
|
for i in xrange(4):
|
|
self.inAtticButton.component('text%d' % i).setR(-90)
|
|
self.inRoomButton.component('text%d' % i).setR(-90)
|
|
self.inTrashButton.component('text%d' % i).setR(-90)
|
|
|
|
backInAtticUp = guiModels.find('**/bu_backinattic_up1')
|
|
backInAtticDown = guiModels.find('**/bu_backinattic_down1')
|
|
backInAtticRollover = guiModels.find('**/bu_backinattic_rollover2')
|
|
self.sendToAtticButton = DirectButton(parent=self.furnitureGui, relief=None, pos=(0.4, 0, 12.8), text=['', TTLocalizer.HDToAtticLabel], text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), text_pos=(1.2, -0.3), image=[backInAtticUp, backInAtticDown, backInAtticRollover], command=self.sendItemToAttic)
|
|
self.sendToAtticButton.hide()
|
|
self.bindHelpText(self.sendToAtticButton, 'SendToAttic')
|
|
zoomInUp = guiModels.find('**/bu_RzoomOut_up')
|
|
zoomInDown = guiModels.find('**/bu_RzoomOut_down')
|
|
zoomInRollover = guiModels.find('**/bu_RzoomOut_rollover')
|
|
self.zoomInButton = DirectButton(parent=self.camButtonFrame, image=[zoomInUp, zoomInDown, zoomInRollover], relief=None, pos=(0.9, 0, -0.75), command=self.zoomCamIn)
|
|
self.bindHelpText(self.zoomInButton, 'ZoomIn')
|
|
zoomOutUp = guiModels.find('**/bu_LzoomIn_up')
|
|
zoomOutDown = guiModels.find('**/bu_LzoomIn_down')
|
|
zoomOutRollover = guiModels.find('**/buLzoomIn_rollover')
|
|
self.zoomOutButton = DirectButton(parent=self.camButtonFrame, image=[zoomOutUp, zoomOutDown, zoomOutRollover], relief=None, pos=(-1.4, 0, -0.75), command=self.zoomCamOut)
|
|
self.bindHelpText(self.zoomOutButton, 'ZoomOut')
|
|
camCCWUp = guiModels.find('**/bu_Rarrow_up1')
|
|
camCCWDown = guiModels.find('**/bu_Rarrow_down1')
|
|
camCCWRollover = guiModels.find('**/bu_Rarrow_orllover')
|
|
self.rotateCamLeftButton = DirectButton(parent=self.camButtonFrame, image=[camCCWUp, camCCWDown, camCCWRollover], relief=None, pos=(0.9, 0, -3.0), command=self.rotateCamCCW)
|
|
self.bindHelpText(self.rotateCamLeftButton, 'RotateLeft')
|
|
camCWUp = guiModels.find('**/bu_Larrow_up1')
|
|
camCWDown = guiModels.find('**/bu_Larrow_down1')
|
|
camCWRollover = guiModels.find('**/bu_Larrow_rollover2')
|
|
self.rotateCamRightButton = DirectButton(parent=self.camButtonFrame, image=[camCWUp, camCWDown, camCWRollover], relief=None, pos=(-1.4, 0, -3.0), command=self.rotateCamCW)
|
|
self.bindHelpText(self.rotateCamRightButton, 'RotateRight')
|
|
trashcanGui = loader.loadModel('phase_3/models/gui/trashcan_gui')
|
|
trashcanUp = trashcanGui.find('**/TrashCan_CLSD')
|
|
trashcanDown = trashcanGui.find('**/TrashCan_OPEN')
|
|
trashcanRollover = trashcanGui.find('**/TrashCan_RLVR')
|
|
self.deleteEnterButton = DirectButton(parent=self.furnitureGui, image=(trashcanUp,
|
|
trashcanDown,
|
|
trashcanRollover,
|
|
trashcanUp), text=['',
|
|
TTLocalizer.InventoryDelete,
|
|
TTLocalizer.InventoryDelete,
|
|
''], text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), text_scale=0.1, text_align=TextNode.ACenter, text_pos=(0, -0.12), text_font=ToontownGlobals.getInterfaceFont(), textMayChange=0, relief=None, pos=(3.7, 0.0, -13.8), scale=7.13, command=self.enterDeleteMode)
|
|
self.bindHelpText(self.deleteEnterButton, 'DeleteEnter')
|
|
self.deleteExitButton = DirectButton(parent=self.furnitureGui, image=(trashcanUp,
|
|
trashcanDown,
|
|
trashcanRollover,
|
|
trashcanUp), text=('',
|
|
TTLocalizer.InventoryDone,
|
|
TTLocalizer.InventoryDone,
|
|
''), text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), text_scale=0.1, text_align=TextNode.ACenter, text_pos=(0, -0.12), text_font=ToontownGlobals.getInterfaceFont(), textMayChange=0, relief=None, pos=(3.7, 0.0, -13.8), scale=7.13, command=self.exitDeleteMode)
|
|
self.bindHelpText(self.deleteExitButton, 'DeleteExit')
|
|
self.deleteExitButton.hide()
|
|
self.trashcanBase = DirectLabel(parent=self.furnitureGui, image=guiModels.find('**/trashcan_base'), relief=None, pos=(0, 0, -11.64))
|
|
self.furnitureGui.hide()
|
|
self.helpText = DirectLabel(parent=self.furnitureGui, relief=DGG.SUNKEN, frameSize=(-0.5,
|
|
10,
|
|
-3,
|
|
0.9), frameColor=(0.2, 0.2, 0.2, 0.5), borderWidth=(0.01, 0.01), text='', text_wordwrap=12, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), text_scale=0.8, pos=(3, 0.0, -7), scale=1, text_align=TextNode.ALeft)
|
|
self.helpText.hide()
|
|
return
|
|
|
|
def createAtticPicker(self):
|
|
self.atticItemPanels = []
|
|
for itemIndex in xrange(len(self.furnitureManager.atticItems)):
|
|
panel = FurnitureItemPanel(self.furnitureManager.atticItems[itemIndex], itemIndex, command=self.bringItemFromAttic, deleteMode=self.deleteMode, helpCategory='FurnitureItemPanelAttic')
|
|
self.atticItemPanels.append(panel)
|
|
|
|
self.atticWallpaperPanels = []
|
|
for itemIndex in xrange(len(self.furnitureManager.atticWallpaper)):
|
|
panel = FurnitureItemPanel(self.furnitureManager.atticWallpaper[itemIndex], itemIndex, command=self.bringWallpaperFromAttic, deleteMode=self.deleteMode, helpCategory='FurnitureItemPanelAttic')
|
|
self.atticWallpaperPanels.append(panel)
|
|
|
|
self.atticWindowPanels = []
|
|
for itemIndex in xrange(len(self.furnitureManager.atticWindows)):
|
|
panel = FurnitureItemPanel(self.furnitureManager.atticWindows[itemIndex], itemIndex, command=self.bringWindowFromAttic, deleteMode=self.deleteMode, helpCategory='FurnitureItemPanelAttic')
|
|
self.atticWindowPanels.append(panel)
|
|
|
|
self.regenerateAtticPicker()
|
|
|
|
def regenerateAtticPicker(self):
|
|
selectedIndex = 0
|
|
if self.atticPicker:
|
|
selectedIndex = self.atticPicker.getSelectedIndex()
|
|
for panel in self.atticItemPanels:
|
|
panel.detachNode()
|
|
|
|
for panel in self.atticWallpaperPanels:
|
|
panel.detachNode()
|
|
|
|
for panel in self.atticWindowPanels:
|
|
panel.detachNode()
|
|
|
|
self.atticPicker.destroy()
|
|
self.atticPicker = None
|
|
itemList = self.atticItemPanels + self.atticWallpaperPanels + self.atticWindowPanels
|
|
if self.deleteMode:
|
|
text = TTLocalizer.HDDeletePickerLabel
|
|
else:
|
|
text = TTLocalizer.HDAtticPickerLabel
|
|
self.atticPicker = self.createScrolledList(itemList, text, 'atticPicker', selectedIndex)
|
|
if self.inRoomPicker or self.inTrashPicker:
|
|
self.atticPicker.hide()
|
|
else:
|
|
self.atticPicker.show()
|
|
return
|
|
|
|
def createInRoomPicker(self):
|
|
self.inRoomPanels = []
|
|
for objectId, object in self.objectDict.items():
|
|
panel = FurnitureItemPanel(object.dfitem.item, objectId, command=self.requestReturnToAttic, deleteMode=self.deleteMode, withinFunc=self.pickInRoom, helpCategory='FurnitureItemPanelRoom')
|
|
self.inRoomPanels.append(panel)
|
|
|
|
self.regenerateInRoomPicker()
|
|
|
|
def regenerateInRoomPicker(self):
|
|
selectedIndex = 0
|
|
if self.inRoomPicker:
|
|
selectedIndex = self.inRoomPicker.getSelectedIndex()
|
|
for panel in self.inRoomPanels:
|
|
panel.detachNode()
|
|
|
|
self.inRoomPicker.destroy()
|
|
self.inRoomPicker = None
|
|
if self.deleteMode:
|
|
text = TTLocalizer.HDDeletePickerLabel
|
|
else:
|
|
text = TTLocalizer.HDInRoomPickerLabel
|
|
self.inRoomPicker = self.createScrolledList(self.inRoomPanels, text, 'inRoomPicker', selectedIndex)
|
|
return
|
|
|
|
def createInTrashPicker(self):
|
|
self.inTrashPanels = []
|
|
for itemIndex in xrange(len(self.furnitureManager.deletedItems)):
|
|
panel = FurnitureItemPanel(self.furnitureManager.deletedItems[itemIndex], itemIndex, command=self.requestReturnToAtticFromTrash, helpCategory='FurnitureItemPanelTrash')
|
|
self.inTrashPanels.append(panel)
|
|
|
|
self.regenerateInTrashPicker()
|
|
|
|
def regenerateInTrashPicker(self):
|
|
selectedIndex = 0
|
|
if self.inTrashPicker:
|
|
selectedIndex = self.inTrashPicker.getSelectedIndex()
|
|
for panel in self.inTrashPanels:
|
|
panel.detachNode()
|
|
|
|
self.inTrashPicker.destroy()
|
|
self.inTrashPicker = None
|
|
text = TTLocalizer.HDInTrashPickerLabel
|
|
self.inTrashPicker = self.createScrolledList(self.inTrashPanels, text, 'inTrashPicker', selectedIndex)
|
|
return
|
|
|
|
def createScrolledList(self, itemList, text, name, selectedIndex):
|
|
gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui')
|
|
picker = DirectScrolledList(parent=self.furnitureGui, pos=(-0.38, 0.0, 3), scale=7.125, relief=None, items=itemList, numItemsVisible=5, text=text, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), text_scale=0.1, text_pos=(0, 0.4), decButton_image=(gui.find('**/FndsLst_ScrollUp'),
|
|
gui.find('**/FndsLst_ScrollDN'),
|
|
gui.find('**/FndsLst_ScrollUp_Rllvr'),
|
|
gui.find('**/FndsLst_ScrollUp')), decButton_relief=None, decButton_scale=(1.5, 1.5, 1.5), decButton_pos=(0, 0, 0.3), decButton_image3_color=Vec4(1, 1, 1, 0.1), incButton_image=(gui.find('**/FndsLst_ScrollUp'),
|
|
gui.find('**/FndsLst_ScrollDN'),
|
|
gui.find('**/FndsLst_ScrollUp_Rllvr'),
|
|
gui.find('**/FndsLst_ScrollUp')), incButton_relief=None, incButton_scale=(1.5, 1.5, -1.5), incButton_pos=(0, 0, -1.878), incButton_image3_color=Vec4(1, 1, 1, 0.1))
|
|
picker.setName(name)
|
|
picker.scrollTo(selectedIndex)
|
|
return picker
|
|
|
|
def reset():
|
|
self.destroy()
|
|
furnitureMenu.destroy()
|
|
|
|
def showAtticPicker(self):
|
|
if self.inRoomPicker:
|
|
self.inRoomPicker.destroy()
|
|
self.inRoomPicker = None
|
|
if self.inTrashPicker:
|
|
self.inTrashPicker.destroy()
|
|
self.inTrashPicker = None
|
|
self.atticPicker.show()
|
|
self.inAtticButton['image_color'] = Vec4(1, 1, 1, 1)
|
|
self.inRoomButton['image_color'] = Vec4(0.8, 0.8, 0.8, 1)
|
|
self.inTrashButton['image_color'] = Vec4(0.8, 0.8, 0.8, 1)
|
|
self.deleteExitButton['state'] = 'normal'
|
|
self.deleteEnterButton['state'] = 'normal'
|
|
return
|
|
|
|
def showInRoomPicker(self):
|
|
messenger.send('wakeup')
|
|
if not self.inRoomPicker:
|
|
self.createInRoomPicker()
|
|
self.atticPicker.hide()
|
|
if self.inTrashPicker:
|
|
self.inTrashPicker.destroy()
|
|
self.inTrashPicker = None
|
|
self.inAtticButton['image_color'] = Vec4(0.8, 0.8, 0.8, 1)
|
|
self.inRoomButton['image_color'] = Vec4(1, 1, 1, 1)
|
|
self.inTrashButton['image_color'] = Vec4(0.8, 0.8, 0.8, 1)
|
|
self.deleteExitButton['state'] = 'normal'
|
|
self.deleteEnterButton['state'] = 'normal'
|
|
return
|
|
|
|
def showInTrashPicker(self):
|
|
messenger.send('wakeup')
|
|
if not self.inTrashPicker:
|
|
self.createInTrashPicker()
|
|
self.atticPicker.hide()
|
|
if self.inRoomPicker:
|
|
self.inRoomPicker.destroy()
|
|
self.inRoomPicker = None
|
|
self.inAtticButton['image_color'] = Vec4(0.8, 0.8, 0.8, 1)
|
|
self.inRoomButton['image_color'] = Vec4(0.8, 0.8, 0.8, 1)
|
|
self.inTrashButton['image_color'] = Vec4(1, 1, 1, 1)
|
|
self.deleteExitButton['state'] = 'disabled'
|
|
self.deleteEnterButton['state'] = 'disabled'
|
|
return
|
|
|
|
def sendItemToAttic(self):
|
|
if base.config.GetBool('want-qa-regression', 0):
|
|
self.notify.info('QA-REGRESSION: ESTATE: Send Item to Attic')
|
|
messenger.send('wakeup')
|
|
if self.selectedObject:
|
|
callback = PythonUtil.Functor(self.__sendItemToAtticCallback, self.selectedObject.get_key())
|
|
self.furnitureManager.moveItemToAttic(self.selectedObject.dfitem, callback)
|
|
self.deselectObject()
|
|
|
|
def __sendItemToAtticCallback(self, objectId, retcode, item):
|
|
self.__enableItemButtons(1)
|
|
if retcode < 0:
|
|
self.notify.info('Unable to send item %s to attic, reason %s.' % (item.getName(), retcode))
|
|
return
|
|
del self.objectDict[objectId]
|
|
if self.selectedObject != None and self.selectedObject.get_key() == objectId:
|
|
self.selectedObject.detachNode()
|
|
self.deselectObject()
|
|
itemIndex = len(self.atticItemPanels)
|
|
panel = FurnitureItemPanel(item, itemIndex, command=self.bringItemFromAttic, deleteMode=self.deleteMode, helpCategory='FurnitureItemPanelAttic')
|
|
self.atticItemPanels.append(panel)
|
|
self.regenerateAtticPicker()
|
|
if self.inRoomPicker:
|
|
for i in xrange(len(self.inRoomPanels)):
|
|
if self.inRoomPanels[i].itemId == objectId:
|
|
del self.inRoomPanels[i]
|
|
self.regenerateInRoomPicker()
|
|
return
|
|
|
|
return
|
|
|
|
def cleanupDialog(self, buttonValue = None):
|
|
if self.dialog:
|
|
self.dialog.cleanup()
|
|
self.dialog = None
|
|
self.__enableItemButtons(1)
|
|
return
|
|
|
|
def enterDeleteMode(self):
|
|
self.deleteMode = 1
|
|
self.__updateDeleteMode()
|
|
|
|
def exitDeleteMode(self):
|
|
self.deleteMode = 0
|
|
self.__updateDeleteMode()
|
|
|
|
def __updateDeleteMode(self):
|
|
if not self.atticPicker:
|
|
return
|
|
self.notify.debug('__updateDeleteMode deleteMode=%s' % self.deleteMode)
|
|
if self.deleteMode:
|
|
framePanelColor = DeletePickerPanelColor
|
|
atticText = TTLocalizer.HDDeletePickerLabel
|
|
inRoomText = TTLocalizer.HDDeletePickerLabel
|
|
helpCategory = 'FurnitureItemPanelDelete'
|
|
else:
|
|
framePanelColor = NormalPickerPanelColor
|
|
atticText = TTLocalizer.HDAtticPickerLabel
|
|
inRoomText = TTLocalizer.HDInRoomPickerLabel
|
|
helpCategory = None
|
|
if self.inRoomPicker:
|
|
self.inRoomPicker['text'] = inRoomText
|
|
for panel in self.inRoomPicker['items']:
|
|
panel.setDeleteMode(self.deleteMode)
|
|
panel.bindHelpText(helpCategory)
|
|
|
|
if self.atticPicker:
|
|
self.atticPicker['text'] = atticText
|
|
for panel in self.atticPicker['items']:
|
|
panel.setDeleteMode(self.deleteMode)
|
|
panel.bindHelpText(helpCategory)
|
|
|
|
self.__updateDeleteButtons()
|
|
return
|
|
|
|
def __updateDeleteButtons(self):
|
|
if self.deleteMode:
|
|
self.deleteExitButton.show()
|
|
self.deleteEnterButton.hide()
|
|
else:
|
|
self.deleteEnterButton.show()
|
|
self.deleteExitButton.hide()
|
|
|
|
def deleteItemFromRoom(self, dfitem, objectId, itemIndex):
|
|
messenger.send('wakeup')
|
|
callback = PythonUtil.Functor(self.__deleteItemFromRoomCallback, objectId, itemIndex)
|
|
self.furnitureManager.deleteItemFromRoom(dfitem, callback)
|
|
|
|
def __deleteItemFromRoomCallback(self, objectId, itemIndex, retcode, item):
|
|
self.__enableItemButtons(1)
|
|
if retcode < 0:
|
|
self.notify.info('Unable to delete item %s from room, reason %s.' % (item.getName(), retcode))
|
|
return
|
|
del self.objectDict[objectId]
|
|
if self.selectedObject != None and self.selectedObject.get_key() == objectId:
|
|
self.selectedObject.detachNode()
|
|
self.deselectObject()
|
|
if self.inRoomPicker and itemIndex is not None:
|
|
del self.inRoomPanels[itemIndex]
|
|
self.regenerateInRoomPicker()
|
|
return
|
|
|
|
def bringItemFromAttic(self, item, itemIndex):
|
|
if base.config.GetBool('want-qa-regression', 0):
|
|
self.notify.info('QA-REGRESSION: ESTATE: Place Item in Room')
|
|
messenger.send('wakeup')
|
|
self.__enableItemButtons(0)
|
|
if self.deleteMode:
|
|
self.requestDelete(item, itemIndex, self.deleteItemFromAttic)
|
|
return
|
|
pos = self.targetNodePath.getRelativePoint(base.localAvatar, Point3(0, 2, 0))
|
|
hpr = Point3(0, 0, 0)
|
|
if abs(pos[0]) > 3000 or abs(pos[1]) > 3000 or abs(pos[2]) > 300:
|
|
self.notify.warning('bringItemFromAttic extreme pos targetNodePath=%s avatar=%s %s' % (repr(self.targetNodePath.getPos(render)), repr(base.localAvatar.getPos(render)), repr(pos)))
|
|
if item.getFlags() & CatalogFurnitureItem.FLPainting:
|
|
for object in self.objectDict.values():
|
|
object.stashBuiltInCollisionNodes()
|
|
|
|
self.gridSnapNP.iPosHpr()
|
|
target = self.targetNodePath
|
|
self.iRay.setParentNP(base.localAvatar)
|
|
entry = self.iRay.pickBitMask3D(bitMask=ToontownGlobals.WallBitmask, targetNodePath=target, origin=Point3(0, 0, 6), dir=Vec3(0, 1, 0), skipFlags=SKIP_BACKFACE | SKIP_CAMERA | SKIP_UNPICKABLE)
|
|
for object in self.objectDict.values():
|
|
object.unstashBuiltInCollisionNodes()
|
|
|
|
if entry:
|
|
self.alignObject(entry, target, fClosest=0, wallOffset=0.1)
|
|
pos = self.gridSnapNP.getPos(target)
|
|
hpr = self.gridSnapNP.getHpr(target)
|
|
else:
|
|
self.notify.warning('wall not found for painting')
|
|
self.furnitureManager.moveItemFromAttic(itemIndex, (pos[0],
|
|
pos[1],
|
|
pos[2],
|
|
hpr[0],
|
|
hpr[1],
|
|
hpr[2]), self.__bringItemFromAtticCallback)
|
|
|
|
def __bringItemFromAtticCallback(self, retcode, dfitem, itemIndex):
|
|
self.__enableItemButtons(1)
|
|
if retcode < 0:
|
|
self.notify.info('Unable to bring furniture item %s into room, reason %s.' % (itemIndex, retcode))
|
|
return
|
|
mo = self.loadObject(dfitem)
|
|
objectId = mo.get_key()
|
|
self.atticItemPanels[itemIndex].destroy()
|
|
del self.atticItemPanels[itemIndex]
|
|
for i in xrange(itemIndex, len(self.atticItemPanels)):
|
|
self.atticItemPanels[i].itemId -= 1
|
|
|
|
self.regenerateAtticPicker()
|
|
if self.inRoomPicker:
|
|
panel = FurnitureItemPanel(dfitem.item, objectId, command=self.requestReturnToAttic, helpCategory='FurnitureItemPanelRoom')
|
|
self.inRoomPanels.append(panel)
|
|
self.regenerateInRoomPicker()
|
|
|
|
def deleteItemFromAttic(self, item, itemIndex):
|
|
messenger.send('wakeup')
|
|
self.furnitureManager.deleteItemFromAttic(item, itemIndex, self.__deleteItemFromAtticCallback)
|
|
|
|
def __deleteItemFromAtticCallback(self, retcode, item, itemIndex):
|
|
self.__enableItemButtons(1)
|
|
if retcode < 0:
|
|
self.notify.info('Unable to delete furniture item %s, reason %s.' % (itemIndex, retcode))
|
|
return
|
|
self.atticItemPanels[itemIndex].destroy()
|
|
del self.atticItemPanels[itemIndex]
|
|
for i in xrange(itemIndex, len(self.atticItemPanels)):
|
|
self.atticItemPanels[i].itemId -= 1
|
|
|
|
self.regenerateAtticPicker()
|
|
|
|
def bringWallpaperFromAttic(self, item, itemIndex):
|
|
messenger.send('wakeup')
|
|
self.__enableItemButtons(0)
|
|
if self.deleteMode:
|
|
self.requestDelete(item, itemIndex, self.deleteWallpaperFromAttic)
|
|
return
|
|
room = self.getRoom()
|
|
self.furnitureManager.moveWallpaperFromAttic(itemIndex, room, self.__bringWallpaperFromAtticCallback)
|
|
|
|
def getRoom(self):
|
|
x, y, z = base.localAvatar.getPos()
|
|
|
|
if (x <= -13.5 and y <= -7.6 and y >= 0.0) or (z >= 4.5 and z <= 10):
|
|
return 0
|
|
elif base.localAvatar.getZ() > 5.0:
|
|
return 1
|
|
elif base.localAvatar.getY() < 2.3:
|
|
return 2
|
|
return 3
|
|
|
|
def __bringWallpaperFromAtticCallback(self, retcode, itemIndex, room):
|
|
self.__enableItemButtons(1)
|
|
if retcode < 0:
|
|
self.notify.info('Unable to bring wallpaper %s into room %s, reason %s.' % (itemIndex, room, retcode))
|
|
return
|
|
self.atticWallpaperPanels[itemIndex].destroy()
|
|
item = self.furnitureManager.atticWallpaper[itemIndex]
|
|
panel = FurnitureItemPanel(item, itemIndex, command=self.bringWallpaperFromAttic, deleteMode=self.deleteMode, helpCategory='FurnitureItemPanelAttic')
|
|
self.atticWallpaperPanels[itemIndex] = panel
|
|
self.regenerateAtticPicker()
|
|
|
|
def deleteWallpaperFromAttic(self, item, itemIndex):
|
|
messenger.send('wakeup')
|
|
self.furnitureManager.deleteWallpaperFromAttic(item, itemIndex, self.__deleteWallpaperFromAtticCallback)
|
|
|
|
def __deleteWallpaperFromAtticCallback(self, retcode, item, itemIndex):
|
|
self.__enableItemButtons(1)
|
|
if retcode < 0:
|
|
self.notify.info('Unable to delete wallpaper %s, reason %s.' % (itemIndex, retcode))
|
|
return
|
|
self.atticWallpaperPanels[itemIndex].destroy()
|
|
del self.atticWallpaperPanels[itemIndex]
|
|
for i in xrange(itemIndex, len(self.atticWallpaperPanels)):
|
|
self.atticWallpaperPanels[i].itemId -= 1
|
|
|
|
self.regenerateAtticPicker()
|
|
|
|
def bringWindowFromAttic(self, item, itemIndex):
|
|
messenger.send('wakeup')
|
|
self.__enableItemButtons(0)
|
|
if self.deleteMode:
|
|
self.requestDelete(item, itemIndex, self.deleteWindowFromAttic)
|
|
return
|
|
room = self.getRoom()
|
|
if room == 0:
|
|
room = 1
|
|
slot = room * 2
|
|
self.furnitureManager.moveWindowFromAttic(itemIndex, slot, self.__bringWindowFromAtticCallback)
|
|
|
|
def __bringWindowFromAtticCallback(self, retcode, itemIndex, slot):
|
|
self.__enableItemButtons(1)
|
|
if retcode < 0:
|
|
self.notify.info('Unable to bring window %s into slot %s, reason %s.' % (itemIndex, slot, retcode))
|
|
return
|
|
if retcode == ToontownGlobals.FM_SwappedItem:
|
|
self.atticWindowPanels[itemIndex].destroy()
|
|
item = self.furnitureManager.atticWindows[itemIndex]
|
|
panel = FurnitureItemPanel(item, itemIndex, command=self.bringWindowFromAttic, deleteMode=self.deleteMode, helpCategory='FurnitureItemPanelAttic')
|
|
self.atticWindowPanels[itemIndex] = panel
|
|
else:
|
|
self.atticWindowPanels[itemIndex].destroy()
|
|
del self.atticWindowPanels[itemIndex]
|
|
for i in xrange(itemIndex, len(self.atticWindowPanels)):
|
|
self.atticWindowPanels[i].itemId -= 1
|
|
|
|
self.regenerateAtticPicker()
|
|
|
|
def deleteWindowFromAttic(self, item, itemIndex):
|
|
messenger.send('wakeup')
|
|
self.furnitureManager.deleteWindowFromAttic(item, itemIndex, self.__deleteWindowFromAtticCallback)
|
|
|
|
def __deleteWindowFromAtticCallback(self, retcode, item, itemIndex):
|
|
self.__enableItemButtons(1)
|
|
if retcode < 0:
|
|
self.notify.info('Unable to delete window %s, reason %s.' % (itemIndex, retcode))
|
|
return
|
|
self.atticWindowPanels[itemIndex].destroy()
|
|
del self.atticWindowPanels[itemIndex]
|
|
for i in xrange(itemIndex, len(self.atticWindowPanels)):
|
|
self.atticWindowPanels[i].itemId -= 1
|
|
|
|
self.regenerateAtticPicker()
|
|
|
|
def setGridSpacingString(self, spacingStr):
|
|
spacing = eval(spacingStr)
|
|
self.setGridSpacing(spacing)
|
|
|
|
def setGridSpacing(self, gridSpacing):
|
|
self.gridSpacing = gridSpacing
|
|
|
|
def makeHouseExtentsBox(self):
|
|
houseGeom = self.targetNodePath.findAllMatches('**/group*')
|
|
targetBounds = houseGeom.getTightBounds()
|
|
self.houseExtents = self.targetNodePath.attachNewNode('furnitureCollisionNode')
|
|
mx = targetBounds[0][0]
|
|
Mx = targetBounds[1][0]
|
|
my = targetBounds[0][1]
|
|
My = targetBounds[1][1]
|
|
mz = targetBounds[0][2]
|
|
Mz = targetBounds[1][2]
|
|
cn = CollisionNode('extentsCollisionNode')
|
|
cn.setIntoCollideMask(ToontownGlobals.GhostBitmask)
|
|
self.houseExtents.attachNewNode(cn)
|
|
cp = CollisionPolygon(Point3(mx, my, mz), Point3(mx, My, mz), Point3(mx, My, Mz), Point3(mx, my, Mz))
|
|
cn.addSolid(cp)
|
|
cp = CollisionPolygon(Point3(Mx, My, mz), Point3(Mx, my, mz), Point3(Mx, my, Mz), Point3(Mx, My, Mz))
|
|
cn.addSolid(cp)
|
|
cp = CollisionPolygon(Point3(Mx, my, mz), Point3(mx, my, mz), Point3(mx, my, Mz), Point3(Mx, my, Mz))
|
|
cn.addSolid(cp)
|
|
cp = CollisionPolygon(Point3(mx, My, mz), Point3(Mx, My, mz), Point3(Mx, My, Mz), Point3(mx, My, Mz))
|
|
cn.addSolid(cp)
|
|
|
|
def makeDoorBlocker(self):
|
|
self.doorBlocker = self.targetNodePath.attachNewNode('doorBlocker')
|
|
cn = CollisionNode('doorBlockerCollisionNode')
|
|
cn.setIntoCollideMask(ToontownGlobals.FurnitureSideBitmask)
|
|
self.doorBlocker.attachNewNode(cn)
|
|
cs = CollisionSphere(Point3(-12, -33, 0), 7.5)
|
|
cn.addSolid(cs)
|
|
|
|
def createVerifyDialog(self, item, verifyText, okFunc, cancelFunc):
|
|
if self.verifyFrame == None:
|
|
buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui')
|
|
okButtonImage = (buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr'))
|
|
cancelButtonImage = (buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr'))
|
|
self.verifyFrame = DirectFrame(pos=(-0.4, 0.1, 0.3), scale=0.75, relief=None, image=DGG.getDefaultDialogGeom(), image_color=ToontownGlobals.GlobalDialogColor, image_scale=(1.2, 1, 1.3), text='', text_wordwrap=19, text_scale=0.06, text_pos=(0, 0.5), textMayChange=1, sortOrder=NO_FADE_SORT_INDEX)
|
|
self.okButton = DirectButton(parent=self.verifyFrame, image=okButtonImage, relief=None, text=OTPLocalizer.DialogOK, text_scale=0.05, text_pos=(0.0, -0.1), textMayChange=0, pos=(-0.22, 0.0, -0.5))
|
|
self.cancelButton = DirectButton(parent=self.verifyFrame, image=cancelButtonImage, relief=None, text=OTPLocalizer.DialogCancel, text_scale=0.05, text_pos=(0.0, -0.1), textMayChange=0, pos=(0.22, 0.0, -0.5))
|
|
self.deleteItemText = DirectLabel(parent=self.verifyFrame, relief=None, text='', text_wordwrap=16, pos=(0.0, 0.0, -0.4), scale=0.09)
|
|
self.verifyFrame['text'] = verifyText
|
|
self.deleteItemText['text'] = item.getName()
|
|
self.okButton['command'] = okFunc
|
|
self.cancelButton['command'] = cancelFunc
|
|
self.verifyFrame.show()
|
|
self.itemPanel, self.itemIval = item.getPicture(base.localAvatar)
|
|
if self.itemPanel:
|
|
self.itemPanel.reparentTo(self.verifyFrame, -1)
|
|
self.itemPanel.setPos(0, 0, 0.05)
|
|
self.itemPanel.setScale(0.35)
|
|
self.deleteItemText.setPos(0.0, 0.0, -0.4)
|
|
else:
|
|
self.deleteItemText.setPos(0, 0, 0.07)
|
|
if self.itemIval:
|
|
self.itemIval.loop()
|
|
return
|
|
|
|
def __handleVerifyDeleteOK(self):
|
|
if base.config.GetBool('want-qa-regression', 0):
|
|
self.notify.info('QA-REGRESSION: ESTATE: Send Item to Trash')
|
|
deleteFunction = self.verifyItems[0]
|
|
deleteFunctionArgs = self.verifyItems[1:]
|
|
self.__cleanupVerifyDelete()
|
|
deleteFunction(*deleteFunctionArgs)
|
|
|
|
def __cleanupVerifyDelete(self, *args):
|
|
if self.nonDeletableItem:
|
|
self.nonDeletableItem.cleanup()
|
|
self.nonDeletableItem = None
|
|
if self.verifyFrame:
|
|
self.verifyFrame.hide()
|
|
if self.itemIval:
|
|
self.itemIval.finish()
|
|
self.itemIval = None
|
|
if self.itemPanel:
|
|
self.itemPanel.destroy()
|
|
self.itemPanel = None
|
|
self.verifyItems = None
|
|
return
|
|
|
|
def __enableItemButtons(self, enabled):
|
|
self.notify.debug('__enableItemButtons %d' % enabled)
|
|
if enabled:
|
|
buttonState = DGG.NORMAL
|
|
else:
|
|
buttonState = DGG.DISABLED
|
|
if hasattr(self, 'inAtticButton'):
|
|
self.inAtticButton['state'] = buttonState
|
|
if hasattr(self, 'inRoomButton'):
|
|
self.inRoomButton['state'] = buttonState
|
|
if hasattr(self, 'inTrashButton'):
|
|
self.inTrashButton['state'] = buttonState
|
|
pickers = [self.atticPicker, self.inRoomPicker, self.inTrashPicker]
|
|
for picker in pickers:
|
|
if picker:
|
|
for panel in picker['items']:
|
|
if not panel.isEmpty():
|
|
panel.enable(enabled)
|
|
|
|
def __resetAndCleanup(self, *args):
|
|
self.__enableItemButtons(1)
|
|
self.__cleanupVerifyDelete()
|
|
|
|
def requestDelete(self, item, itemIndex, deleteFunction):
|
|
self.__cleanupVerifyDelete()
|
|
if self.furnitureManager.ownerId != base.localAvatar.doId or not item.isDeletable():
|
|
self.warnNonDeletableItem(item)
|
|
return
|
|
self.createVerifyDialog(item, TTLocalizer.HDDeleteItem, self.__handleVerifyDeleteOK, self.__resetAndCleanup)
|
|
self.verifyItems = (deleteFunction, item, itemIndex)
|
|
|
|
def requestRoomDelete(self, dfitem, objectId, itemIndex):
|
|
self.__cleanupVerifyDelete()
|
|
item = dfitem.item
|
|
if self.furnitureManager.ownerId != base.localAvatar.doId or not item.isDeletable():
|
|
self.warnNonDeletableItem(item)
|
|
return
|
|
self.createVerifyDialog(item, TTLocalizer.HDDeleteItem, self.__handleVerifyDeleteOK, self.__resetAndCleanup)
|
|
self.verifyItems = (self.deleteItemFromRoom,
|
|
dfitem,
|
|
objectId,
|
|
itemIndex)
|
|
|
|
def warnNonDeletableItem(self, item):
|
|
message = TTLocalizer.HDNonDeletableItem
|
|
if not item.isDeletable():
|
|
if item.getFlags() & CatalogFurnitureItem.FLBank:
|
|
message = TTLocalizer.HDNonDeletableBank
|
|
elif item.getFlags() & CatalogFurnitureItem.FLCloset:
|
|
message = TTLocalizer.HDNonDeletableCloset
|
|
elif item.getFlags() & CatalogFurnitureItem.FLPhone:
|
|
message = TTLocalizer.HDNonDeletablePhone
|
|
elif item.getFlags() & CatalogFurnitureItem.FLTrunk:
|
|
message = TTLocalizer.HDNonDeletableTrunk
|
|
if self.furnitureManager.ownerId != base.localAvatar.doId:
|
|
message = TTLocalizer.HDNonDeletableNotOwner % self.furnitureManager.ownerName
|
|
self.nonDeletableItem = TTDialog.TTDialog(text=message, style=TTDialog.Acknowledge, fadeScreen=0, command=self.__resetAndCleanup)
|
|
self.nonDeletableItem.show()
|
|
|
|
def requestReturnToAttic(self, item, objectId):
|
|
self.__cleanupVerifyDelete()
|
|
itemIndex = None
|
|
for i in xrange(len(self.inRoomPanels)):
|
|
if self.inRoomPanels[i].itemId == objectId:
|
|
itemIndex = i
|
|
self.__enableItemButtons(0)
|
|
break
|
|
|
|
if self.deleteMode:
|
|
dfitem = self.objectDict[objectId].dfitem
|
|
self.requestRoomDelete(dfitem, objectId, itemIndex)
|
|
return
|
|
self.createVerifyDialog(item, TTLocalizer.HDReturnVerify, self.__handleVerifyReturnOK, self.__resetAndCleanup)
|
|
self.verifyItems = (item, objectId)
|
|
return
|
|
|
|
def __handleVerifyReturnOK(self):
|
|
item, objectId = self.verifyItems
|
|
self.__cleanupVerifyDelete()
|
|
self.pickInRoom(objectId)
|
|
self.sendItemToAttic()
|
|
|
|
def requestReturnToAtticFromTrash(self, item, itemIndex):
|
|
self.__cleanupVerifyDelete()
|
|
self.__enableItemButtons(0)
|
|
self.createVerifyDialog(item, TTLocalizer.HDReturnFromTrashVerify, self.__handleVerifyReturnFromTrashOK, self.__resetAndCleanup)
|
|
self.verifyItems = (item, itemIndex)
|
|
|
|
def __handleVerifyReturnFromTrashOK(self):
|
|
if base.config.GetBool('want-qa-regression', 0):
|
|
self.notify.info('QA-REGRESSION: ESTATE: Send Item to Attic')
|
|
item, itemIndex = self.verifyItems
|
|
self.__cleanupVerifyDelete()
|
|
self.recoverDeletedItem(item, itemIndex)
|
|
|
|
def recoverDeletedItem(self, item, itemIndex):
|
|
messenger.send('wakeup')
|
|
self.furnitureManager.recoverDeletedItem(item, itemIndex, self.__recoverDeletedItemCallback)
|
|
|
|
def __recoverDeletedItemCallback(self, retcode, item, itemIndex):
|
|
self.__cleanupVerifyDelete()
|
|
if retcode < 0:
|
|
if retcode == ToontownGlobals.FM_HouseFull:
|
|
self.showHouseFullDialog()
|
|
self.notify.info('Unable to recover deleted item %s, reason %s.' % (itemIndex, retcode))
|
|
return
|
|
self.__enableItemButtons(1)
|
|
self.inTrashPanels[itemIndex].destroy()
|
|
del self.inTrashPanels[itemIndex]
|
|
for i in xrange(itemIndex, len(self.inTrashPanels)):
|
|
self.inTrashPanels[i].itemId -= 1
|
|
|
|
self.regenerateInTrashPicker()
|
|
itemType = item.getTypeCode()
|
|
if itemType == CatalogItemTypes.WALLPAPER_ITEM or itemType == CatalogItemTypes.FLOORING_ITEM or itemType == CatalogItemTypes.MOULDING_ITEM or itemType == CatalogItemTypes.WAINSCOTING_ITEM:
|
|
itemIndex = len(self.atticWallpaperPanels)
|
|
bringCommand = self.bringWallpaperFromAttic
|
|
elif itemType == CatalogItemTypes.WINDOW_ITEM:
|
|
itemIndex = len(self.atticWindowPanels)
|
|
bringCommand = self.bringWindowFromAttic
|
|
else:
|
|
itemIndex = len(self.atticItemPanels)
|
|
bringCommand = self.bringItemFromAttic
|
|
panel = FurnitureItemPanel(item, itemIndex, command=bringCommand, deleteMode=self.deleteMode, helpCategory='FurnitureItemPanelAttic')
|
|
if itemType == CatalogItemTypes.WALLPAPER_ITEM or itemType == CatalogItemTypes.FLOORING_ITEM or itemType == CatalogItemTypes.MOULDING_ITEM or itemType == CatalogItemTypes.WAINSCOTING_ITEM:
|
|
self.atticWallpaperPanels.append(panel)
|
|
elif itemType == CatalogItemTypes.WINDOW_ITEM:
|
|
self.atticWindowPanels.append(panel)
|
|
else:
|
|
self.atticItemPanels.append(panel)
|
|
self.regenerateAtticPicker()
|
|
|
|
def showHouseFullDialog(self):
|
|
self.cleanupDialog()
|
|
self.dialog = TTDialog.TTDialog(style=TTDialog.Acknowledge, text=TTLocalizer.HDHouseFull, text_wordwrap=15, command=self.cleanupDialog)
|
|
self.dialog.show()
|
|
|
|
def bindHelpText(self, button, category):
|
|
button.bind(DGG.ENTER, self.showHelpText, extraArgs=[category, None])
|
|
button.bind(DGG.EXIT, self.hideHelpText)
|
|
return
|
|
|
|
def showHelpText(self, category, itemName, xy):
|
|
|
|
def showIt(task):
|
|
helpText = TTLocalizer.HDHelpDict.get(category)
|
|
if helpText:
|
|
if itemName:
|
|
helpText = helpText % itemName
|
|
self.helpText['text'] = helpText
|
|
self.helpText.show()
|
|
else:
|
|
print 'category: %s not found'
|
|
|
|
taskMgr.doMethodLater(0.75, showIt, 'showHelpTextDoLater')
|
|
|
|
def hideHelpText(self, xy):
|
|
taskMgr.remove('showHelpTextDoLater')
|
|
self.helpText['text'] = ''
|
|
self.helpText.hide()
|