Poodletooth-iLand/toontown/nametag/Nametag2d.py
2015-04-09 17:05:57 +03:00

322 lines
11 KiB
Python

from direct.task.Task import Task
import math
from panda3d.core import PGButton, VBase4, DepthWriteAttrib, Point3
from toontown.chat.ChatBalloon import ChatBalloon
from toontown.margins import MarginGlobals
from toontown.margins.MarginVisible import MarginVisible
from toontown.nametag import NametagGlobals
from toontown.nametag.Nametag import Nametag
from toontown.toontowngui.Clickable2d import Clickable2d
class Nametag2d(Nametag, Clickable2d, MarginVisible):
CONTENTS_SCALE = 0.25
CHAT_TEXT_MAX_ROWS = 6
CHAT_TEXT_WORD_WRAP = 8
CHAT_BALLOON_ALPHA = 0.4
ARROW_OFFSET = -1.0
ARROW_SCALE = 1.5
def __init__(self):
Nametag.__init__(self)
Clickable2d.__init__(self, 'Nametag2d')
MarginVisible.__init__(self)
self.actualChatText = ''
self.arrow = None
self.textNodePath = None
self.contents.setScale(self.CONTENTS_SCALE)
self.hideThought()
self.accept('MarginVisible-update', self.update)
def destroy(self):
self.ignoreAll()
Nametag.destroy(self)
if self.textNodePath is not None:
self.textNodePath.removeNode()
self.textNodePath = None
if self.arrow is not None:
self.arrow.removeNode()
self.arrow = None
Clickable2d.destroy(self)
def getUniqueName(self):
return 'Nametag2d-' + str(id(self))
def getChatBalloonModel(self):
return NametagGlobals.chatBalloon2dModel
def getChatBalloonWidth(self):
return NametagGlobals.chatBalloon2dWidth
def getChatBalloonHeight(self):
return NametagGlobals.chatBalloon2dHeight
def setChatText(self, chatText):
self.actualChatText = chatText
Nametag.setChatText(self, chatText)
def updateClickRegion(self):
if self.chatBalloon is not None:
right = self.chatBalloon.width / 2.0
left = -right
top = self.chatBalloon.height / 2.0
bottom = -top
self.setClickRegionFrame(left, right, bottom, top)
self.region.setActive(True)
elif self.panel is not None:
centerX = (self.textNode.getLeft()+self.textNode.getRight()) / 2.0
centerY = (self.textNode.getBottom()+self.textNode.getTop()) / 2.0
left = centerX - (self.panelWidth/2.0)
right = centerX + (self.panelWidth/2.0)
bottom = centerY - (self.panelHeight/2.0)
top = centerY + (self.panelHeight/2.0)
self.setClickRegionFrame(left, right, bottom, top)
self.region.setActive(True)
else:
if self.region is not None:
self.region.setActive(False)
def isClickable(self):
if self.getChatText() and self.hasChatButton():
return True
return NametagGlobals.wantActiveNametags and Clickable2d.isClickable(self)
def setClickState(self, clickState):
if self.isClickable():
self.applyClickState(clickState)
else:
self.applyClickState(PGButton.SInactive)
Clickable2d.setClickState(self, clickState)
def enterDepressed(self):
if self.isClickable():
base.playSfx(NametagGlobals.clickSound)
def enterRollover(self):
if self.isClickable() and (self.lastClickState != PGButton.SDepressed):
base.playSfx(NametagGlobals.rolloverSound)
def update(self):
self.contents.node().removeAllChildren()
Nametag.update(self)
if self.cell is not None:
# We're in the margin display. Reposition our content, and update
# the click region:
self.reposition()
self.updateClickRegion()
else:
# We aren't in the margin display. Disable the click region if one
# is present:
if self.region is not None:
self.region.setActive(False)
def tick(self, task):
if (self.avatar is None) or self.avatar.isEmpty():
return Task.cont
if (self.cell is None) or (self.arrow is None):
return Task.cont
location = self.avatar.getPos(NametagGlobals.me)
rotation = NametagGlobals.me.getQuat(base.cam)
camSpacePos = rotation.xform(location)
arrowRadians = math.atan2(camSpacePos[0], camSpacePos[1])
arrowDegrees = (arrowRadians/math.pi) * 180
self.arrow.setR(arrowDegrees - 90)
return Task.cont
def drawChatBalloon(self, model, modelWidth, modelHeight):
if self.chatFont is None:
# We can't draw this without a font.
return
# Prefix the nametag text:
self.chatTextNode.setText(self.getText() + ': ' + self.actualChatText)
# Set our priority in the margin system:
self.setPriority(MarginGlobals.MP_normal)
if self.textNodePath is not None:
self.textNodePath.removeNode()
self.textNodePath = None
if self.arrow is not None:
self.arrow.removeNode()
self.arrow = None
if self.isClickable():
foreground, background = self.chatColor[self.clickState]
else:
foreground, background = self.chatColor[PGButton.SInactive]
if self.chatType == NametagGlobals.SPEEDCHAT:
background = self.speedChatColor
if background[3] > self.CHAT_BALLOON_ALPHA:
background = VBase4(
background[0], background[1], background[2],
self.CHAT_BALLOON_ALPHA)
self.chatBalloon = ChatBalloon(
model, modelWidth, modelHeight, self.chatTextNode,
foreground=foreground, background=background,
reversed=self.chatReversed,
button=self.chatButton[self.clickState])
self.chatBalloon.reparentTo(self.contents)
# Calculate the center of the TextNode:
left, right, bottom, top = self.chatTextNode.getFrameActual()
center = self.contents.getRelativePoint(
self.chatBalloon.textNodePath,
((left+right) / 2.0, 0, (bottom+top) / 2.0))
# Translate the chat balloon along the inverse:
self.chatBalloon.setPos(self.chatBalloon, -center)
def drawNametag(self):
# Set our priority in the margin system:
self.setPriority(MarginGlobals.MP_low)
if self.textNodePath is not None:
self.textNodePath.removeNode()
self.textNodePath = None
if self.arrow is not None:
self.arrow.removeNode()
self.arrow = None
if self.font is None:
# We can't draw this without a font.
return
# Attach the icon:
if self.icon is not None:
self.contents.attachNewNode(self.icon)
if self.isClickable():
foreground, background = self.nametagColor[self.clickState]
else:
foreground, background = self.nametagColor[PGButton.SInactive]
# Set the color of the TextNode:
self.textNode.setTextColor(foreground)
# Attach the TextNode:
self.textNodePath = self.contents.attachNewNode(self.textNode, 1)
self.textNodePath.setTransparency(foreground[3] < 1)
self.textNodePath.setAttrib(DepthWriteAttrib.make(0))
self.textNodePath.setY(self.TEXT_Y_OFFSET)
# Attach a panel behind the TextNode:
self.panel = NametagGlobals.cardModel.copyTo(self.contents, 0)
self.panel.setColor(background)
self.panel.setTransparency(background[3] < 1)
# Reposition the panel:
x = (self.textNode.getLeft()+self.textNode.getRight()) / 2.0
z = (self.textNode.getBottom()+self.textNode.getTop()) / 2.0
self.panel.setPos(x, 0, z)
# Resize the panel:
self.panelWidth = self.textNode.getWidth() + self.PANEL_X_PADDING
self.panelHeight = self.textNode.getHeight() + self.PANEL_Z_PADDING
self.panel.setScale(self.panelWidth, 1, self.panelHeight)
# Add an arrow:
self.arrow = NametagGlobals.arrowModel.copyTo(self.contents)
self.arrow.setZ(self.ARROW_OFFSET + self.textNode.getBottom())
self.arrow.setScale(self.ARROW_SCALE)
self.arrow.setColor(self.nametagColor[4] if len(self.nametagColor) >= 5 else self.nametagColor[0][0])
def marginVisibilityChanged(self):
if self.cell is not None:
# We're in the margin display. Reposition our content, and update
# the click region:
self.reposition()
self.updateClickRegion()
else:
# We aren't in the margin display. Disable the click region if one
# is present:
if self.region is not None:
self.region.setActive(False)
def reposition(self):
if self.contents is None:
return
origin = Point3()
self.contents.setPos(origin)
if self.chatBalloon is not None:
self.chatBalloon.removeNode()
self.chatBalloon = None
self.contents.node().removeAllChildren()
if (self.cell in base.leftCells) or (self.cell in base.rightCells):
text = self.getChatText().replace('\x01WLDisplay\x01', '').replace('\x02', '')
textWidth = self.chatTextNode.calcWidth(text)
if (textWidth / self.CHAT_TEXT_WORD_WRAP) > self.CHAT_TEXT_MAX_ROWS:
self.chatTextNode.setWordwrap(textWidth / (self.CHAT_TEXT_MAX_ROWS-0.5))
else:
self.chatTextNode.setWordwrap(self.CHAT_TEXT_WORD_WRAP)
model = self.getChatBalloonModel()
modelWidth = self.getChatBalloonWidth()
modelHeight = self.getChatBalloonHeight()
self.drawChatBalloon(model, modelWidth, modelHeight)
nodePath = self.chatBalloon.textNodePath
left, right, bottom, top = self.chatTextNode.getFrameActual()
left -= self.chatBalloon.BALLOON_X_PADDING
right += self.chatBalloon.BALLOON_X_PADDING
bottom -= self.chatBalloon.BALLOON_Z_PADDING
top += self.chatBalloon.BALLOON_Z_PADDING
elif self.panel is not None:
nodePath = self.textNodePath
left, right, bottom, top = self.textNode.getFrameActual()
left -= self.PANEL_X_PADDING
right += self.PANEL_X_PADDING
bottom -= self.PANEL_Z_PADDING
top += self.PANEL_Z_PADDING
# Compensate for the arrow:
bottom -= self.ARROW_SCALE
else:
return
if self.cell in base.bottomCells:
# Move the origin to the bottom center of the node path:
origin = self.contents.getRelativePoint(
nodePath, ((left+right) / 2.0, 0, bottom))
elif self.cell in base.leftCells:
# Move the origin to the left center of the node path:
origin = self.contents.getRelativePoint(
nodePath, (left, 0, (bottom+top) / 2.0))
elif self.cell in base.rightCells:
# Move the origin to the right center of the node path:
origin = self.contents.getRelativePoint(
nodePath, (right, 0, (bottom+top) / 2.0))
self.contents.setPos(self.contents, -origin)