diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fab3c77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +*.pyo +*.log diff --git a/libotp/__init__.py b/libotp/__init__.py new file mode 100644 index 0000000..e709f2c --- /dev/null +++ b/libotp/__init__.py @@ -0,0 +1,5 @@ +from movement.CImpulse import CImpulse +from movement.CMover import CMover +from movement.CMoverGroup import CMoverGroup +from nametag import * +from settings.Settings import Settings diff --git a/libotp/movement/CImpulse.py b/libotp/movement/CImpulse.py new file mode 100644 index 0000000..395a7cd --- /dev/null +++ b/libotp/movement/CImpulse.py @@ -0,0 +1,37 @@ +from direct.directnotify import DirectNotifyGlobal +from direct.showbase import DirectObject + + +class CImpulse(DirectObject.DirectObject): + notify = DirectNotifyGlobal.directNotify.newCategory('CImpulse') + + def __init__(self): + self.mover = None + self.nodePath = None + self.VecType = None + + def isCpp(self): + return 1 + + def process(self, dt): + pass + + def setMover(self, mover): + if self.mover != mover: + self.mover = mover + self.nodePath = self.mover.getNodePath() + self.VecType = self.mover.VecType + + def getMover(self): + return self.mover + + def clearMover(self, mover): + if self.mover == mover: + self.mover = None + self.nodePath = None + self.VecType = None + else: + self.notify.warning('clearMover: unknown CMover') + + def getNodePath(self): + return self.nodePath diff --git a/libotp/movement/CMover.py b/libotp/movement/CMover.py new file mode 100644 index 0000000..8e85cd7 --- /dev/null +++ b/libotp/movement/CMover.py @@ -0,0 +1,91 @@ +from direct.directnotify import DirectNotifyGlobal +from panda3d.core import * + + +class CMover: + notify = DirectNotifyGlobal.directNotify.newCategory('CMover') + + def __init__(self, objNodePath, fwdSpeed=1, rotSpeed=1): + self.objNodePath = objNodePath + self.fwdSpeed = fwdSpeed + self.rotSpeed = rotSpeed + self.VecType = Vec3(0, 0, 0) + self.dt = 1.0 + self.dtClock = globalClock.getFrameTime() + self.shove = Vec3(0, 0, 0) + self.rotShove = Vec3(0, 0, 0) + self.force = Vec3(0, 0, 0) + self.rotForce = Vec3(0, 0, 0) + self.cImpulses = {} + + def setFwdSpeed(self, fwdSpeed): + self.fwdSpeed = fwdSpeed + + def getFwdSpeed(self): + return self.fwdSpeed + + def setRotSpeed(self, rotSpeed): + self.rotSpeed = rotSpeed + + def getRotSpeed(self): + return self.rotSpeed + + def getNodePath(self): + return self.objNodePath + + def getDt(self): + return self.dt + + def resetDt(self): + self.dt = 1.0 + self.dtClock = globalClock.getFrameTime() + + def addCImpulse(self, name, cImpulse): + if not cImpulse: + return + + self.removeCImpulse(name) + self.cImpulses[name] = cImpulse + cImpulse.setMover(self) + + def removeCImpulse(self, name): + if name in self.cImpulses: + cImpulse = self.cImpulses[name] + cImpulse.clearMover(self) + del self.cImpulses[name] + return True + + return False + + def processCImpulses(self, dt): + self.dt = dt + if self.getDt() == -1.0: + clockDelta = globalClock.getFrameTime() + self.dt = clockDelta - self.dtClock + self.dtClock = clockDelta + + for cImpulse in self.cImpulses.values(): + cImpulse.process(self.getDt()) + + def addShove(self, shove): + self.shove += shove + + def addRotShove(self, rotShove): + self.rotShove += rotShove + + def addForce(self, force): + self.force += force + + def addRotForce(self, rotForce): + self.rotForce += rotForce + + def integrate(self): + if not self.objNodePath or self.objNodePath.isEmpty(): + return + + self.shove *= self.getDt() + self.objNodePath.setFluidPos(self.objNodePath, self.shove) + self.rotShove *= self.getDt() + self.objNodePath.setHpr(self.objNodePath, self.rotShove) + self.shove = Vec3(0, 0, 0) + self.rotShove = Vec3(0, 0, 0) diff --git a/libotp/movement/CMoverGroup.py b/libotp/movement/CMoverGroup.py new file mode 100644 index 0000000..254baa2 --- /dev/null +++ b/libotp/movement/CMoverGroup.py @@ -0,0 +1,42 @@ +from direct.directnotify import DirectNotifyGlobal + + +class CMoverGroup: + notify = DirectNotifyGlobal.directNotify.newCategory('CMoverGroup') + + def __init__(self): + self.dt = 1.0 + self.dtClock = globalClock.getFrameTime() + self.cMovers = {} + + def setDt(self, dt): + self.dt = dt + if self.dt == -1.0: + clockDelta = globalClock.getFrameTime() + self.dt = clockDelta - self.dtClock + self.dtClock = clockDelta + + def resetDt(self): + self.dt = 1.0 + self.dtClock = globalClock.getFrameTime() + + def addCMover(self, name, cMover): + if not cMover: + return + + self.removeCMover(name) + self.cMovers[name] = cMover + + def removeCMover(self, name): + if name in self.cMovers: + del self.cMovers[name] + + def processCImpulsesAndIntegrate(self): + if self.dt == -1.0: + clockDelta = globalClock.getFrameTime() + self.dt = clockDelta - self.dtClock + self.dtClock = clockDelta + + for cMover in self.cMovers.values(): + cMover.processCImpulses(self.dt) + cMover.integrate() diff --git a/libotp/movement/__init__.py b/libotp/movement/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/libotp/nametag/ChatBalloon.py b/libotp/nametag/ChatBalloon.py new file mode 100644 index 0000000..2735847 --- /dev/null +++ b/libotp/nametag/ChatBalloon.py @@ -0,0 +1,229 @@ +from direct.directnotify import DirectNotifyGlobal +from panda3d.core import * + +import NametagGlobals + + +class ChatBalloon: + notify = DirectNotifyGlobal.directNotify.newCategory('ChatBalloon') + + def __init__(self, node=None): + if isinstance(node, NodePath): + node = node.node() + + self.m_copy_node = None + self.m_top_node = None + self.m_top_mat = None + self.m_middle_node = None + self.m_middle_mat = None + self.m_bottom_node = None + self.m_bottom_mat = None + + self.m_hscale = 0 + self.m_text_height = 0 + self.m_text_frame = Vec4(0) + + self.scan(node) + + @staticmethod + def find_geom_node(node): + if node.isGeomNode(): + return node + + for i in xrange(node.getNumChildren()): + n = ChatBalloon.find_geom_node(node.getChild(i)) + if n: + return n + + return None + + @staticmethod + def find_middle_geom(node): + if not node.getNumChildren(): + return None + + child = None + for i in xrange(node.getNumChildren()): + child = node.getChild(i) + if child.getName() == 'middle': + return n + + n = ChatBalloon.find_middle_geom(child) + if n: + return n + + return ChatBalloon.find_geom_node(child) + + def scan(self, node): + if node.getName() == 'chatBalloon': + return self.scan_balloon(node) + + for i in xrange(node.getNumChildren()): + if self.scan(node.getChild(i)): + return True + + return False + + def scan_balloon(self, node): + self.m_copy_node = node.copySubgraph() + + for i in xrange(node.getNumChildren()): + child = node.getChild(i) + if child.getName() == 'top': + self.m_top_node = child + self.m_top_mat = child.getTransform().getMat() + + elif child.getName() == 'middle': + self.m_middle_node = child + self.m_middle_mat = child.getTransform().getMat() + + elif child.getName() == 'bottom': + self.m_bottom_node = child + self.m_bottom_mat = child.getTransform().getMat() + + if self.m_top_node and self.m_middle_node and self.m_bottom_node: + return True + + else: + self.notify.warning('ChatBalloon geometry does not include top, middle, and bottom nodes.') + return False + + def generate(self, text, font, wordwrap, text_color, balloon_color, for_3d, + has_draw_order, draw_order, page_button, space_for_button, + reversed, new_button): # new_button is a pointer, let's use a list hack here + chat_node = PandaNode('chat') + chat_node.setAttrib(CullFaceAttrib.make(0)) + text_node = NametagGlobals.getTextNode() + text_node.setFont(font) + text_node.setWordwrap(wordwrap) + text_node.setAlign(TextNode.ALeft) + text_node.setText(text) + + v116 = NametagGlobals._balloon_text_origin[0] + if reversed: + v116 = v116 + 9.0 + + v27 = (text_node.getRight() - text_node.getLeft()) * 0.11111111 + self.m_hscale = v27 + + if v27 < 0.25: + self.m_hscale = 0.25 + text_node.setAlign(TextNode.ACenter) + + v29 = v116 + if not reversed: + v116 = v29 + 4.5 + + else: + v116 = v29 - 4.5 + + elif reversed: + self.m_hscale = -self.m_hscale + + self.m_text_frame = text_node.getCardActual() + _space = 0.2 if space_for_button else 0.0 + num_rows = max(1, text_node.getNumRows()) + _num_rows = num_rows + line_h = text_node.getFont().getLineHeight() + + num_rows_minus_1 = num_rows - 1 + subgraph_copy_mat = Mat4(self.m_hscale, 0, 0, 0, + 0, 1.0, 0, 0, + 0, 0, 1.0, 0, + 0, 0, 0, 1.0) + text_h = _num_rows * line_h + _space + self.m_text_height = text_h + + v132 = num_rows_minus_1 * line_h + _space + + middle_mat = Mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, text_h, 0, + 0, 0, 0, 1) * self.m_middle_mat + top_mat = Mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, text_h - 1.0, 1) * self.m_top_mat + + v137 = v116 * self.m_hscale + v138 = 0.0 + v139 = NametagGlobals._balloon_text_origin[2] + v132 + 0.2 + + self.m_text_frame += Vec4(v137, v137, v139, v139) + + ''' + Correct code: + Python won't let us edit this transform, we'll have to copy it all + + if self.m_top_node: + self.m_top_node.setTransform(TransformState.makeMat(top_mat)) + + if self.m_middle_node: + self.m_middle_node.setTransform(TransformState.makeMat(middle_mat)) + + subgraph_copy = self.m_copy_node.copySubgraph() + chat_node.addChild(subgraph_copy) + subgraph_copy.setTransform(TransformState.makeMat(subgraph_copy_mat)) + ''' + + # BEGIN PYTHON CODE + subgraph_copy = self.m_copy_node.copySubgraph() + NodePath.anyPath(subgraph_copy).find('**/top').node().setTransform(TransformState.makeMat(top_mat)) + NodePath.anyPath(subgraph_copy).find('**/middle').node().setTransform(TransformState.makeMat(middle_mat)) + + chat_node.addChild(subgraph_copy) + subgraph_copy.setTransform(TransformState.makeMat(subgraph_copy_mat)) + # END PYTHON CODE + + if has_draw_order: + bin = config.GetString('nametag-fixed-bin', 'fixed') + subgraph_copy.setAttrib(CullBinAttrib.make(bin, draw_order)) + + subgraph_copy.setAttrib(ColorAttrib.makeFlat(balloon_color)) + if balloon_color[3] != 1.0: + subgraph_copy.setAttrib(TransparencyAttrib.make(1)) + + reducer = SceneGraphReducer() + reducer.applyAttribs(subgraph_copy) + reducer.flatten(chat_node, -1) + + generated_text = text_node.generate() + if for_3d: + v86 = ChatBalloon.find_middle_geom(chat_node) + if not v86: + v86 = ChatBalloon.find_geom_node(chat_node) + + v86.setEffect(DecalEffect.make()) + + else: + v86 = chat_node + if has_draw_order: + bin = config.GetString('nametag-fixed-bin', 'fixed') + generated_text.setAttrib(CullBinAttrib.make(bin, draw_order + 1)) + + np = NodePath.anyPath(v86) + v144 = np.attachNewNode(generated_text) + v144.setPos((v137, v138, v139)) + v144.setColor(text_color) + v144.setY(-0.01) # Panda3D 1.10 hack to prevent z-fighting. + if text_color[3] != 1.0: + v144.setTransparency(1) + + if page_button: + v116 = ModelNode('button') + new_button[0] = np.attachNewNode(v116) + button_copy = page_button.copyTo(new_button[0]) + if reversed: + button_copy.setPos(self.m_hscale * 1.7, 0, 1.8) + + else: + button_copy.setPos(self.m_hscale * 9.0, 0, 1.8) + + button_copy.setScale(8.0, 8.0, 8.0) + button_copy.setY(-0.01) # Panda3D 1.10 hack to prevent z-fighting. + + reducer = SceneGraphReducer() + reducer.applyAttribs(generated_text) + reducer.flatten(chat_node, 1) + + return chat_node diff --git a/libotp/nametag/ClickablePopup.py b/libotp/nametag/ClickablePopup.py new file mode 100644 index 0000000..c1fe122 --- /dev/null +++ b/libotp/nametag/ClickablePopup.py @@ -0,0 +1,114 @@ +from direct.showbase.DirectObject import DirectObject +from panda3d.core import * + +import NametagGlobals + + +class PopupMouseWatcherRegion(MouseWatcherRegion): + """ + This is an ultra hacky class! + The correct implementation of PopupMouseWatcherRegion cannot be done in Python. + This also assumes that m_mouse_watcher is NametagGlobals::_mouse_watcher. + """ + + class _Param: + def __init__(self, outside=False): + self.outside = outside + + def isOutside(self): + return self.outside + + def getButton(self): + return MouseButton.one() + + MOUSE_WATCHER_SETUP = False + + def __init__(self, obj, name, frame): + MouseWatcherRegion.__init__(self, '%s-%s' % (name, id(self)), frame) + + self.obj = obj + self.__inside = False + self.__active = False + + if not self.MOUSE_WATCHER_SETUP: + NametagGlobals._mouse_watcher.setEnterPattern('mouse-enter-%r') + NametagGlobals._mouse_watcher.setLeavePattern('mouse-leave-%r') + NametagGlobals._mouse_watcher.setButtonDownPattern('button-down-%r') + NametagGlobals._mouse_watcher.setButtonUpPattern('button-up-%r') + self.MOUSE_WATCHER_SETUP = True + + self.slaveObject = DirectObject() + self.activate() + + def activate(self): + if not self.__active: + self.__active = True + + self.slaveObject.accept(self.__getEvent(NametagGlobals._mouse_watcher.getEnterPattern()), self.__mouseEnter) + self.slaveObject.accept(self.__getEvent(NametagGlobals._mouse_watcher.getLeavePattern()), self.__mouseLeave) + self.slaveObject.accept(self.__getEvent(NametagGlobals._mouse_watcher.getButtonDownPattern()), + self.__buttonDown) + self.slaveObject.accept(self.__getEvent(NametagGlobals._mouse_watcher.getButtonUpPattern()), self.__buttonUp) + + def deactivate(self): + if self.__active: + self.__active = False + + self.slaveObject.ignoreAll() + + def __mouseEnter(self, region, extra): + self.__inside = True + self.obj.enterRegion(None) + + def __mouseLeave(self, region, extra): + self.__inside = False + self.obj.exitRegion(None) + + def __buttonDown(self, region, button): + if button == 'mouse1': + self.obj.press(PopupMouseWatcherRegion._Param()) + + def __buttonUp(self, region, button): + if button == 'mouse1': + self.obj.release(PopupMouseWatcherRegion._Param(not self.__inside)) + + def __getEvent(self, pattern): + return pattern.replace('%r', self.getName()) + + +class ClickablePopup: + def __init__(self): + self.m_state = PGButton.SReady + + def setState(self, state): + if state != self.m_state: + self.m_state = state + self.updateContents() + + def enterRegion(self, arg): + if NametagGlobals._rollover_sound: + NametagGlobals._rollover_sound.play() + + self.setState(PGButton.SRollover) + + def exitRegion(self, arg): + self.setState(PGButton.SReady) + + def press(self, arg): + if arg.getButton() == MouseButton.one(): + if NametagGlobals._click_sound: + NametagGlobals._click_sound.play() + self.setState(PGButton.SDepressed) + + def release(self, arg): + if arg.getButton() == MouseButton.one(): + if arg.isOutside(): + self.setState(PGButton.SReady) + + else: + self.setState(PGButton.SRollover) + self.click() + + def _createRegion(self, frame): + name = '%s-%s' % (self.__class__.__name__, self.getName()) + return PopupMouseWatcherRegion(self, name, frame) diff --git a/libotp/nametag/MarginManager.py b/libotp/nametag/MarginManager.py new file mode 100644 index 0000000..e56ec4c --- /dev/null +++ b/libotp/nametag/MarginManager.py @@ -0,0 +1,211 @@ +from panda3d.core import * + + +class PopupHandle: + def __init__(self, popup): + self.m_popup = popup # 12 + self.m_cell = -1 # 16 + self.m_wants_visible = False # 20 + self.m_score = 0 # 24 + self.m_objcode = id(self) # 28 + popup.setObjectCode(self.m_objcode) + + +class MarginCell: + def __init__(self): + self.m_mat = Mat4() # 0 + self.m_cell_width = 0 # 64 + self.m_popup = None # 68 + self.m_np = None # 72 + self.m_visible = False # 84 + self.m_objcode = 0 # 88 + self.m_time = 0 # 96 + + +class MarginManager(PandaNode): + def __init__(self): + PandaNode.__init__(self, 'popups') + + # self.setCullCallback() + self.cbNode = CallbackNode(self.getName() + '-cbNode') + self.cbNode.setCullCallback(PythonCallbackObject(self.cullCallback)) + self.addChild(self.cbNode) + + self.m_cells = [] + self.m_popups = {} # MarginPopup*: PopupHandle + self.m_code_map = {} # code: MarginPopup* + self.m_num_available = 0 + + def addGridCell(self, a2, a3, a4, a5, a6, a7): + v7 = (a5 - a4) * 0.16666667 + v8 = (a7 - a6) * 0.16666667 + v15 = v7 * a2 + a4 + v9 = a3 * v8 + a6 + v10 = v9 + v8 - 0.01 + v11 = v9 + 0.01 + v12 = v15 + v7 - 0.01 + v13 = v15 + 0.01 + return self.addCell(v13, v12, v11, v10) + + def addCell(self, left, right, bottom, top): + v5 = (top - bottom) * 0.5 + v19 = Vec3(v5, 0, 0) + scale = Vec3(v5, v5, v5) + shear = Vec3(0, 0, 0) + trans = Vec3((left + right) * 0.5, 0, (bottom + top) * 0.5) + + v18 = len(self.m_cells) + v9 = MarginCell() + self.m_cells.append(v9) + v9.m_available = True + + mat3 = Mat3() + composeMatrix(mat3, scale, shear, Vec3(0, 0, 0), 0) + v9.m_mat = Mat4(mat3, trans) + + v9.m_cell_width = (right - left) * 0.5 / v19[0] + v9.m_np = None + v9.m_popup = None + v9.m_objcode = 0 + v9.m_time = 0.0 + + self.m_num_available += 1 + return v18 + + def setCellAvailable(self, a2, a3): + v5 = self.m_cells[a2] + if v5.m_available: + self.m_num_available -= 1 + + v5.m_available = a3 + if v5.m_available: + self.m_num_available += 1 + + if v5.m_np: + self.hide(a2) + v5.m_popup = None + v5.m_objcode = 0 + + def getCellAvailable(self, a2): + return self.m_cells[a2].m_available + + def cullCallback(self, *args): + self.update() + + def managePopup(self, a2): + a2.setManaged(True) + self.m_popups[a2] = PopupHandle(a2) + self.m_code_map[a2.getObjectCode()] = a2 + + def unmanagePopup(self, a2): + v9 = self.m_popups.get(a2) + if v9: + if v9.m_cell >= 0: + self.hide(v9.m_cell) + v9.m_cell = -1 + + a2.setManaged(False) + del self.m_popups[a2] + del self.m_code_map[v9.m_objcode] + + def hide(self, a2): + cell = self.m_cells[a2] + cell.m_np.removeNode() + cell.m_time = globalClock.getFrameTime() + if cell.m_popup: + cell.m_popup.setVisible(False) + + def show(self, popup, cell_index): + v12 = self.m_cells[cell_index] + v12.m_popup = popup + v12.m_objcode = popup.getObjectCode() + v12.m_np = NodePath.anyPath(self).attachNewNode(popup) + v12.m_np.setMat(v12.m_mat) + self.m_popups[popup].m_cell = cell_index + popup.m_cell_width = v12.m_cell_width + popup.setVisible(True) + + def chooseCell(self, a2, a3): + now = globalClock.getFrameTime() + objcode = a2.getObjectCode() + + for cell in a3: + v7 = self.m_cells[cell] + if (v7.m_popup == a2 or v7.m_objcode == objcode) and (now - v7.m_time) <= 30.0: + result = cell + break + + else: + for cell in a3[::-1][1:]: # Iterate backwards, skip last item + v10 = self.m_cells[cell] + if (not v10.m_popup) or (now - v10.m_time) > 30.0: + result = cell + break + + else: + result = a3[-1] + + a3.remove(result) + return result + + def showVisibleNoConflict(self): + cells = [] + for i, cell in enumerate(self.m_cells): + if cell.m_available and not cell.m_np: + cells.append(i) + + for handle in self.m_popups.values(): + v7 = handle.m_popup + if handle.m_wants_visible and not v7.isVisible(): + v8 = self.chooseCell(v7, cells) + self.show(v7, v8) + + def showVisibleResolveConflict(self): + v4 = [] + + for handle in self.m_popups.values(): + score = 0 + if handle.m_wants_visible: + score = handle.m_score + + v4.append((handle, -score)) + + v4 = sorted(v4, key=lambda a: a[-1]) + for handle in v4[self.m_num_available:]: + if handle[0].m_popup.isVisible(): + self.hide(handle[0].m_cell) + handle[0].m_cell = -1 + + cells = [] + for i, cell in enumerate(self.m_cells): + if cell.m_available and not cell.m_np: + cells.append(i) + + for handle in v4[:self.m_num_available]: + v7 = handle[0].m_popup + if handle[0].m_wants_visible and not v7.isVisible(): + v8 = self.chooseCell(v7, cells) + self.show(v7, v8) + + def update(self): + num_want_visible = 0 + + for handle in self.m_popups.values(): + popup = handle.m_popup + handle.m_wants_visible = popup.considerVisible() + if handle.m_wants_visible and handle.m_objcode: + handle.m_score = popup.getScore() + num_want_visible += 1 + + elif popup.isVisible(): + self.hide(handle.m_cell) + handle.m_cell = -1 + + if num_want_visible > self.m_num_available: + self.showVisibleResolveConflict() + + else: + self.showVisibleNoConflict() + + for popup in self.m_popups.keys(): + popup.frameCallback() diff --git a/libotp/nametag/MarginPopup.py b/libotp/nametag/MarginPopup.py new file mode 100644 index 0000000..989a51d --- /dev/null +++ b/libotp/nametag/MarginPopup.py @@ -0,0 +1,51 @@ +from panda3d.core import * + +import NametagGlobals + + +class MarginPopup(PandaNode): + def __init__(self): + PandaNode.__init__(self, 'MarginPopup') + + self.m_managed = False + self.m_visible = False + self.m_np = None + self.m_cell_width = 1.0 + self.m_seq = NametagGlobals._margin_prop_seq + + def getCellWidth(self): + return self.m_cell_width + + def setManaged(self, value): + self.m_managed = value + if value: + self.m_np = NodePath.anyPath(self) + + else: + self.m_np = None + + def isManaged(self): + return self.m_managed + + def setVisible(self, value): + self.m_visible = value + + def isVisible(self): + return self.m_visible + + def getScore(self): + return 0.0 + + def getObjectCode(self): + return 0 + + def considerVisible(self): + if self.m_seq != NametagGlobals._margin_prop_seq: + self.m_seq = NametagGlobals._margin_prop_seq + self.updateContents() + + def updateContents(self): + pass + + def frameCallback(self): + pass diff --git a/libotp/nametag/Nametag.py b/libotp/nametag/Nametag.py new file mode 100644 index 0000000..16c97b3 --- /dev/null +++ b/libotp/nametag/Nametag.py @@ -0,0 +1,197 @@ +from direct.interval.IntervalGlobal import * + +from ClickablePopup import * +from _constants import * + + +class Nametag(ClickablePopup): + CName = 1 + CSpeech = 2 + CThought = 4 + + def __init__(self, wordwrap): + ClickablePopup.__init__(self) + + self.m_avatar = None + self.m_ival = None + self.m_popup_region = None + self.m_seq = 0 + self.m_mouse_watcher = None + self.m_draw_order = 0 + self.m_has_draw_order = False + + self.m_contents = CFSpeech | CFThought | CFQuicktalker + self.m_active = True + self.m_field_12 = 0 + self.m_group = None + self.m_wordwrap = wordwrap + self.m_has_region = False + self.m_ival_name = 'flash-%d' % id(self) + + def clearAvatar(self): + self.m_avatar = None + + def clearDrawOrder(self): + self.m_has_draw_order = False + self.updateContents() + + def click(self): + if self.m_group: + self.m_group.click() + + def deactivate(self): + if self.m_has_region: + if self.m_mouse_watcher: + self.m_popup_region.deactivate() + self.m_mouse_watcher.removeRegion(self.m_popup_region) + self.m_mouse_watcher = None + + self.m_has_region = None + + self.m_seq = 0 + + def determineContents(self): + if self.m_group and self.m_group.isManaged(): + v3 = self.m_contents & self.m_group.getContents() + v4 = self.m_group.m_chat_flags + + if v4 & CFSpeech: + if v3 & Nametag.CSpeech: + return Nametag.CSpeech + + elif v4 & CFThought and v3 & Nametag.CThought: + return Nametag.CThought + + if v3 & Nametag.CName and self.m_group.getName() and NametagGlobals._master_nametags_visible: + return Nametag.CName + + return 0 + + def displayAsActive(self): + if not self.m_active: + return 0 + + if self.m_group: + return self.m_group.displayAsActive() + + else: + return NametagGlobals._master_nametags_active + + def setAvatar(self, avatar): + self.m_avatar = avatar + + def getAvatar(self): + return self.m_avatar + + def setChatWordwrap(self, wordwrap): + self.m_wordwrap = wordwrap + + def getChatWordwrap(self): + return self.m_wordwrap + + def getGroup(self): + return self.m_group + + def getState(self): + if self.m_group: + if not (self.m_active and self.m_group.displayAsActive()): + return PGButton.SInactive + + elif not (self.m_active and NametagGlobals._master_nametags_active): + return PGButton.SInactive + + return self.m_state + + def hasGroup(self): + return self.m_group is not None + + def setActive(self, active): + self.m_active = active + self.updateContents() + + def isActive(self): + return self.m_active + + def isGroupManaged(self): + return self.m_group and self.m_group.isManaged() + + def keepRegion(self): + if self.m_popup_region: + self.m_seq = self.m_group.getRegionSeq() + + def manage(self, manager): + self.updateContents() + + def unmanage(self, manager): + self.updateContents() + self.deactivate() + + def setContents(self, contents): + self.m_contents = contents + self.updateContents() + + def setDrawOrder(self, draw_order): + self.m_draw_order = draw_order + self.m_has_draw_order = True + self.updateContents() + + def setRegion(self, frame, sort): + if self.m_popup_region: + self.m_popup_region.setFrame(frame) + + else: + self.m_popup_region = self._createRegion(frame) + + self.m_popup_region.setSort(int(sort)) + self.m_seq = self.m_group.getRegionSeq() + + def startFlash(self, np): + self.stopFlash() + self.m_ival = Sequence( + np.colorInterval(0.5, Vec4(1.0, 1.0, 1.0, 0.5), startColor=Vec4(1.0, 1.0, 1.0, 1.0), blendType='easeOut'), + np.colorInterval(0.5, Vec4(1.0, 1.0, 1.0, 1.0), startColor=Vec4(1.0, 1.0, 1.0, 0.5), blendType='easeIn')) + self.m_ival.loop() + + def stopFlash(self): + if self.m_ival: + self.m_ival.finish() + self.m_ival = None + + def updateRegion(self, seq): + if seq == self.m_seq: + is_active = self.displayAsActive() + + else: + is_active = False + + if self.m_has_region: + if self.m_mouse_watcher != NametagGlobals._mouse_watcher: + if self.m_mouse_watcher: + self.m_popup_region.deactivate() + self.m_mouse_watcher.removeRegion(self.m_popup_region) + + self.m_has_region = False + self.setState(PGButton.SReady) + + if is_active: + if (not self.m_has_region) and self.m_popup_region: + if self.m_mouse_watcher != NametagGlobals._mouse_watcher: + self.m_mouse_watcher = NametagGlobals._mouse_watcher + + if self.m_mouse_watcher: + self.m_popup_region.activate() + self.m_mouse_watcher.addRegion(self.m_popup_region) + + self.m_has_region = True + + elif self.m_has_region: + if self.m_mouse_watcher and self.m_popup_region: + self.m_popup_region.deactivate() + self.m_mouse_watcher.removeRegion(self.m_popup_region) + + self.m_has_region = False + self.m_mouse_watcher = None + self.setState(PGButton.SReady) + + def upcastToPandaNode(self): + return self diff --git a/libotp/nametag/Nametag2d.py b/libotp/nametag/Nametag2d.py new file mode 100644 index 0000000..0daf302 --- /dev/null +++ b/libotp/nametag/Nametag2d.py @@ -0,0 +1,329 @@ +import math + +from panda3d.core import * + +import NametagGlobals +from MarginPopup import MarginPopup +from Nametag import Nametag +from _constants import * + + +class Nametag2d(Nametag, MarginPopup): + def __init__(self): + Nametag.__init__(self, 8.075) + MarginPopup.__init__(self) + + self.m_copied_np = None + self.m_attached_np = None + self.m_arrow = None + self.m_unknown_np = None + + # self.setCullCallback() + self.cbNode = CallbackNode(self.getName() + '-cbNode') + self.cbNode.setCullCallback(PythonCallbackObject(self.cullCallback)) + self.addChild(self.cbNode) + + self.setName('unnamed') + + self.m_contents = 3 + self.m_chat_contents = 0 + self.updateContents() + self.m_on = NametagGlobals._master_arrows_on + self.m_seq2d = 0 + + self.m_trans_vec = Vec3(0, 0, 0) + + def setVisible(self, value): + self.m_visible = value + self.updateContents() + + def manage(self, manager): + self.updateContents() + manager.managePopup(self) + + def unmanage(self, manager): + Nametag.unmanage(self, manager) + manager.unmanagePopup(self) + + def setObjectCode(self, objcode): + if self.m_group: + self.m_group.setObjectCode(objcode) + + def getObjectCode(self): + if self.m_group: + return self.m_group.getObjectCode() + + return 0 + + def getScore(self): + if self.m_group: + return 1000 - self.getDistance2() + + return 0 + + def getDistance2(self): + if self.m_avatar: + np = self.m_avatar + + else: + np = self.m_group.getAvatar() + + if np.isEmpty(): + return 0 + + return np.getPos(NametagGlobals._toon).lengthSquared() + + def considerVisible(self): + from NametagGroup import NametagGroup + + v2 = 0 + do_update = True + if self.m_on != NametagGlobals._master_arrows_on: + self.m_on = NametagGlobals._master_arrows_on + v2 = 1 + + if self.m_seq2d == NametagGlobals._margin_prop_seq: + if not v2: + do_update = False + + else: + self.m_seq2d = NametagGlobals._margin_prop_seq + + if do_update: + self.updateContents() + + if not self.m_chat_contents: + return 0 + + result = self.m_group.m_nametag3d_flag != 2 + if NametagGlobals._onscreen_chat_forced and self.m_chat_contents & (Nametag.CSpeech | Nametag.CThought): + result = 1 + + self.m_group.setNametag3dFlag(0) + if result and self.m_group.getColorCode() in (NametagGroup.CCToonBuilding, + NametagGroup.CCSuitBuilding, + NametagGroup.CCHouseBuilding): + return self.getDistance2() < 1600 + + return result + + def updateContents(self): + self.stopFlash() + if self.m_group: + self.setName(self.m_group.getName()) + + else: + self.setName('unnamed') + + if self.m_copied_np: + self.m_copied_np.removeNode() + + if self.m_attached_np: + self.m_attached_np.removeNode() + + if self.m_arrow: + self.m_arrow.removeNode() + + if self.m_unknown_np: + self.m_unknown_np.removeNode() + + self.m_chat_contents = self.determineContents() + if not NametagGlobals._master_arrows_on: + self.m_chat_contents = self.m_chat_contents & ~1 + + if self.m_visible and self.isGroupManaged(): + v10 = self.m_chat_contents + if v10 & Nametag.CSpeech: + self.generateChat(NametagGlobals._speech_balloon_2d) + + elif v10 & Nametag.CThought: + self.generateChat(NametagGlobals._thought_balloon_2d) + + elif v10 & Nametag.CName: + self.generateName() + + def frameCallback(self): + if self.m_visible and self.m_popup_region: + self.m_seq = self.m_group.m_region_seq + + if self.m_group: + self.m_group.updateRegions() + + def rotateArrow(self): + if not self.m_arrow: + return + + if self.m_avatar: + np = self.m_avatar + + else: + np = self.m_group.getAvatar() + + if not np: + return + + relpos = np.getPos(NametagGlobals._camera) - NametagGlobals._toon.getPos(NametagGlobals._camera) + hpr = Vec3(0, 0, -math.atan2(relpos[1], relpos[0]) * 180 / math.pi) + scale = Vec3(0.5, 0.5, 0.5) + shear = Vec3(0, 0, 0) + + temp_mat_3 = Mat3() + composeMatrix(temp_mat_3, scale, shear, hpr) + arrow_mat = Mat4(temp_mat_3, self.m_trans_vec) + self.m_arrow.setMat(arrow_mat) + + def generateName(self): + v4 = self.getState() + v84 = Vec4(NametagGlobals.getNameFg(self.m_group.getColorCode(), v4)) + v75 = Vec4(NametagGlobals.getNameBg(self.m_group.getColorCode(), v4)) + v75[3] = max(v75[3], NametagGlobals._min_2d_alpha) + v75[3] = min(v75[3], NametagGlobals._max_2d_alpha) + + v67 = NametagGlobals._card_pad[3] + self.m_group.m_name_frame[3] + v68 = self.m_group.m_name_frame[2] - NametagGlobals._card_pad[2] + + wordwrap = self.m_group.getNameWordwrap() + v17 = self.m_cell_width / wordwrap * 2.0 + v66 = 0.333 * (1.0 / v17) - (v68 + v67) * 0.5 + v18 = min(1.0 / v17 - v67, v66) + + v69 = Mat4(v17, 0, 0, 0, + 0, v17, 0, 0, + 0, 0, v17, 0, + 0, 0, v18 * v17, 1.0) + a3 = v69 + + if v75[3] != 0.0: + card = CardMaker('nametag') + card.setFrame(self.m_group.m_name_frame[0] - NametagGlobals._card_pad[0], + self.m_group.m_name_frame[1] + NametagGlobals._card_pad[1], + v68, v67) + card.setColor(v75) + if NametagGlobals._nametag_card: + card.setSourceGeometry(NametagGlobals._nametag_card.node(), + NametagGlobals._nametag_card_frame) + + self.m_attached_np = self.m_np.attachNewNode(card.generate()) + self.m_attached_np.setMat(v69) + if v75[3] != 1.0: + self.m_attached_np.setTransparency(1) + + if self.m_has_draw_order: + bin = config.GetString('nametag-fixed-bin', 'fixed') + self.m_attached_np.setBin(bin, self.m_draw_order) + + self.m_copied_np = self.m_group.copyNameTo(self.m_np) + self.m_copied_np.setMat(a3) + if self.m_has_draw_order: + bin = config.GetString('nametag-fixed-bin', 'fixed') + self.m_copied_np.setBin(bin, self.m_draw_order) + + self.m_copied_np.setColor(v84) + if v84[3] != 1.0: + self.m_copied_np.setTransparency(1) + + reducer = SceneGraphReducer() + reducer.applyAttribs(self.m_copied_np.node()) + reducer.applyAttribs(self.m_attached_np.node()) + + if NametagGlobals._arrow_model: + self.m_arrow = NametagGlobals._arrow_model.copyTo(self.m_np) + if self.m_has_draw_order: + bin = config.GetString('nametag-fixed-bin', 'fixed') + self.m_arrow.setBin(bin, self.m_draw_order) + + self.m_trans_vec = a3.xformPoint(Point3(0, 0, v68 - 1.0)) + + color = Vec4(NametagGlobals.getArrowColor(self.m_group.getColorCode())) + self.m_arrow.setColor(color) + if color[3] != 1.0: + self.m_arrow.setTransparency(1) + + self.rotateArrow() + + elif self.m_arrow: + self.m_arrow.removeNode() + + v69 = self.m_np.getNetTransform().getMat() + v69 = a3 * v69 + + v77 = v69.xformPoint(Point3(self.m_group.m_name_frame[0] - NametagGlobals._card_pad[0], 0, v68)) + v80 = v69.xformPoint(Point3(self.m_group.m_name_frame[1] + NametagGlobals._card_pad[1], 0, v67)) + + frame = Vec4(v77[0], v80[0], v77[2], v80[2]) + self.setRegion(frame, 0) + + def generateChat(self, balloon): + v5 = self.getState() + text_color = Vec4(NametagGlobals.getChatFg(self.m_group.getColorCode(), v5)) + balloon_color = Vec4(NametagGlobals.getChatBg(self.m_group.getColorCode(), v5)) + + if self.m_group.m_chat_flags & CFQuicktalker: + balloon_color = Vec4(self.m_group.getQtColor()) + + balloon_color[3] = max(balloon_color[3], NametagGlobals._min_2d_alpha) + balloon_color[3] = min(balloon_color[3], NametagGlobals._max_2d_alpha) + + text = self.m_group.getChat() + if self.m_group.m_name: + text = '%s: %s' % (self.m_group.m_name, text) + + has_page_button = False + has_quit_button = False + if not self.m_group.m_has_timeout: + has_page_button = self.m_group.m_chat_flags & CFPageButton + if self.m_group.getPageNumber() >= self.m_group.getNumChatPages() - 1: + if self.m_group.m_chat_flags & CFQuitButton: + has_page_button = False + has_quit_button = True + + page_button = None + if has_page_button: + page_button = NametagGlobals.getPageButton(v5) + + elif has_quit_button: + page_button = NametagGlobals.getQuitButton(v5) + + reversed = self.m_group.m_chat_flags & CFReversed + new_button = [None] + balloon_result = balloon.generate(text, self.m_group.getChatFont(), self.m_wordwrap, + text_color, balloon_color, False, + self.m_has_draw_order, self.m_draw_order, + page_button, self.m_group.willHaveButton(), + reversed, new_button) + + self.m_unknown_np = self.m_np.attachNewNode(balloon_result) + + v88 = 8.0 # XXX THIS IS A GUESS + v49 = 2 * self.m_cell_width + a6 = v49 / (v88 + 1.0) + v50 = balloon.m_text_height * balloon.m_hscale + v85 = balloon.m_hscale * 5.0 + v88 = v50 * 0.5 + v113 = -(balloon.m_hscale * 0.5 + v85) + v51 = -(NametagGlobals._balloon_text_origin[2] + v88) + v118 = Mat4(a6, 0, 0, 0, + 0, a6, 0, 0, + 0, 0, a6, 0, + v113 * a6, 0, v51 * a6, 1.0) + + self.m_unknown_np.setMat(v118) + + reducer = SceneGraphReducer() + reducer.applyAttribs(self.m_unknown_np.node()) + + v66 = self.m_np.getNetTransform().getMat() + + # XXX THE LINES BELOW ARE A GUESS + v67 = v113 * a6 + v68 = v51 * a6 + v94 = v66.xformPoint(Point3(v67, 0.0, v68)) + v97 = v66.xformPoint(Point3(-v67, 0.0, -v68)) + + frame = Vec4(v94[0], v97[0], v94[2], v97[2]) + self.setRegion(frame, 0) + + def cullCallback(self, *args): + self.rotateArrow() + if self.m_visible and self.m_popup_region: + self.m_seq = self.m_group.getRegionSeq() diff --git a/libotp/nametag/Nametag3d.py b/libotp/nametag/Nametag3d.py new file mode 100644 index 0000000..2bb5173 --- /dev/null +++ b/libotp/nametag/Nametag3d.py @@ -0,0 +1,399 @@ +import math + +from panda3d.core import * + +import NametagGlobals +from Nametag import Nametag +from _constants import * + + +class Nametag3d(Nametag, PandaNode): + def __init__(self): + Nametag.__init__(self, 10.5) + PandaNode.__init__(self, 'unnamed') + + self.m_np_360 = None + self.m_np_372 = None + self.m_np_balloon = None + + # self.setCullCallback() + # safe_to_flatten_below: 0 + self.cbNode = CallbackNode(self.getName() + '-cbNode') + self.cbNode.setCullCallback(PythonCallbackObject(self.cullCallback)) + self.addChild(self.cbNode) + + self.m_billboard_offset = 3.0 + + self.m_np_top = NodePath.anyPath(PandaNode('top')) + self.m_is_3d = 1 + self.m_field_396 = 0 + self.m_name_frame = Vec4(0, 0, 0, 0) + self.m_chat_contents = None + + self.setBounds(BoundingSphere((0, 0, 0), 2.0)) + + def setBillboardOffset(self, billboard_offset): + self.m_billboard_offset = billboard_offset + + def getBillboardOffset(self): + return self.m_billboard_offset + + def cullCallback(self, traverse_data): + if self.isGroupManaged(): + # sort = CullBinManager.getGlobalPtr().getBinSort(traverse_data._state.getBinIndex()) + # np = traverse_data._node_path.getNodePath() + traverser = traverse_data.getTrav() + np = NodePath.anyPath(self) + sort = CullBinManager.getGlobalPtr().getBinSort(traverser.getInitialState().getBinIndex()) + self.adjustToCamera(np, sort) + + def manage(self, manager): + self.m_np_top.reparentTo(NodePath.anyPath(self)) + self.updateContents() + + def unmanage(self, manager): + self.m_np_top.detachNode() + Nametag.unmanage(self, manager) + + def updateContents(self): + self.stopFlash() + + if self.m_has_draw_order: + bin = config.GetString('nametag-fixed-bin', 'fixed') + self.m_np_top.setBin(bin, self.m_draw_order) + + else: + self.m_np_top.clearBin() + + if self.m_group: + self.setName(self.m_group.getName()) + + else: + self.setName('unnamed') + + if self.m_np_360: + self.m_np_360.removeNode() + + if self.m_np_372: + self.m_np_372.removeNode() + + if self.m_np_balloon: + self.m_np_balloon.removeNode() + + self.m_np_top.node().removeAllChildren() + + self.m_chat_contents = self.determineContents() + if self.isGroupManaged(): + if self.m_chat_contents & 2: + self.generateChat(NametagGlobals._speech_balloon_3d) + + elif self.m_chat_contents & 4: + self.generateChat(NametagGlobals._thought_balloon_3d) + + elif self.m_chat_contents & 1: + self.generateName() + + def release(self, arg): + if arg.getButton() == MouseButton.one(): + self.setState(PGButton.SRollover) + if self.m_group: + self.m_group.click() + + def generateChat(self, balloon): + v5 = self.getState() + text_color = Vec4(NametagGlobals.getChatFg(self.m_group.getColorCode(), v5)) + balloon_color = Vec4(NametagGlobals.getChatBg(self.m_group.getColorCode(), v5)) + + if self.m_group.m_chat_flags & CFQuicktalker: + balloon_color = Vec4(self.m_group.getQtColor()) + + text = self.m_group.getChat() + has_page_button = False + has_quit_button = False + if not self.m_group.m_has_timeout: + has_page_button = self.m_group.m_chat_flags & CFPageButton + if self.m_group.getPageNumber() >= self.m_group.getNumChatPages() - 1: + if self.m_group.m_chat_flags & CFQuitButton: + has_page_button = False + has_quit_button = True + + page_button = None + if has_page_button: + page_button = NametagGlobals.getPageButton(v5) + + elif has_quit_button: + page_button = NametagGlobals.getQuitButton(v5) + + reversed = self.m_group.m_chat_flags & CFReversed + new_button = [None] + balloon_result = balloon.generate(text, self.m_group.getChatFont(), self.m_wordwrap, + text_color, balloon_color, self.m_is_3d, + self.m_has_draw_order, self.m_draw_order, + page_button, self.m_group.willHaveButton(), + reversed, new_button) + + self.m_np_balloon = self.m_np_top.attachNewNode(balloon_result) + if new_button[0]: + self.startFlash(new_button[0]) + + self.m_name_frame = balloon.m_text_frame + self.m_field_396 = 1 + + def generateName(self): + v4 = self.getState() + v56 = Vec4(NametagGlobals.getNameFg(self.m_group.getColorCode(), v4)) + v54 = Vec4(NametagGlobals.getNameBg(self.m_group.getColorCode(), v4)) + + self.m_name_frame = Vec4(*self.m_group.getNameFrame()) + self.m_name_frame[0] -= NametagGlobals._card_pad[0] + self.m_name_frame[1] += NametagGlobals._card_pad[1] + self.m_name_frame[2] -= NametagGlobals._card_pad[2] + self.m_name_frame[3] += NametagGlobals._card_pad[3] + self.m_field_396 = 1 + + v47 = None + if v54[3] != 0.0: + card = CardMaker('nametag') + card.setFrame(self.m_name_frame) + card.setColor(v54) + if NametagGlobals._nametag_card: + card.setSourceGeometry(NametagGlobals._nametag_card.node(), + NametagGlobals._nametag_card_frame) + + self.m_np_372 = self.m_np_top.attachNewNode(card.generate()) + self.m_np_372.setTransparency(1) + v47 = self.m_np_372.find('**/+GeomNode') + + label86 = False + if self.m_is_3d: + if self.m_group.m_name_icon: + self.m_group.m_name_icon.instanceTo(self.m_np_top) + + if v47: + self.m_np_360 = self.m_group.copyNameTo(v47) + self.m_np_360.setDepthWrite(0) + self.m_np_360.setY(-0.01) # Panda3D 1.10 hack to prevent z-fighting. + v47.node().setEffect(DecalEffect.make()) + + else: + label86 = True + + else: + label86 = True + + if label86: + self.m_np_360 = self.m_group.copyNameTo(self.m_np_top) + if self.m_has_draw_order: + bin = config.GetString('nametag-fixed-bin', 'fixed') + self.m_name_icon.setBin(bin, self.m_draw_order + 1) + self.m_np_360.setBin(bin, self.m_draw_order + 2) + + self.m_np_360.setColor(v56) + if v56[3] != 1.0: + self.m_np_360.setTransparency(1) + + def adjustToCamera(self, np, sort): + if self.m_is_3d: + lens = NametagGlobals._camera.node().getLens(0) + if self.m_avatar or not self.m_group: + v131 = self.m_avatar + + else: + v131 = self.m_group.m_avatar + + v130 = NametagGlobals._camera.getTransform(np) + v25 = v130.getMat() + v204 = v25.xformVec(Vec3.up()) + v203 = v25.xformVec(Vec3.forward()) + + v193 = Mat3() + lookAt(v193, Vec3(v203), Vec3(v204)) + v177 = Mat4(v193) + v177_3_0 = v177[3][0] + v177_3_1 = v177[3][1] + + a3 = np.getTransform(NametagGlobals._camera).getMat() + v122 = a3[3][1] + v30 = max(v122, 0.1) + v31 = v30 * 0.02 + v121 = (v31 ** 0.5) * NametagGlobals.getGlobalNametagScale() * 0.56 + if self.m_billboard_offset == 0.0: + v42 = 0 + + else: + v32 = v25[0][1] + v33 = v25[0][0] + v136 = v25[0][2] + v134 = v33 + v127 = self.m_billboard_offset + v144 = math.sqrt(v136 * v136 + v32 * v32 + v134 * v134) + v129 = self.m_billboard_offset / v144 + if v122 > 0.0: + if isinstance(lens, PerspectiveLens): + v37 = lens.getNear() + 0.001 + if v122 - v129 < v37: + v129 = v122 - v37 + v127 = v129 * v144 + + v121 = (v122 - v129) / v122 * v121 + + v38 = v25[3][0] + v39 = v25[3][1] + v126 = v25[3][2] + v125 = v39 + v129 = v126 * v126 + v39 * v39 + v38 * v38 + if v129 == 0.0: + v125 = 0.0 + v38 = 0.0 + v126 = 0.0 + + else: + v40 = v129 - 1.0 + if abs(v40) > 0.0: # if ( v40 >= 1.0e-12 || v40 <= -1.0e-12 ) NOT ALMOST ZERO + v41 = 1.0 / math.sqrt(v129) + v38 *= v41 + v125 *= v41 + v126 *= v41 + + v126 *= v127 + v177_3_0 = v38 * v127 + v177_3_1 = v125 * v127 + v42 = v126 + + v205 = Mat4(v177[0][0] * v121, v177[0][1] * v121, v177[0][2] * v121, v177[0][3] * v121, + v177[1][0] * v121, v177[1][1] * v121, v177[1][2] * v121, v177[1][3] * v121, + v177[2][0] * v121, v177[2][1] * v121, v177[2][2] * v121, v177[2][3] * v121, + v177_3_0, v177_3_1, v42, v177[3][3]) + self.m_np_top.setMat(v205) + + v51 = 0 + if self.displayAsActive(): + if not self.m_chat_contents & (2 | 4): + v51 = 1 + + elif not self.m_group: + v51 = 1 + + elif self.m_group.m_has_timeout: + v51 = 1 + + elif not self.m_group.willHaveButton(): + v51 = 1 + + elif self.m_group.getPageNumber() >= self.m_group.getNumChatPages() - 1: + v51 = 1 + + v123 = 0 + sorta = 0 + frame = Vec4(0, 0, 0, 0) + v150 = lens.getProjectionMat() + + if v51: + v138, v139, v140 = v205.xformVec(Vec3(-2.5, 0.0, 1.0)) + v124, v125, v126 = v205.xformVec(Vec3(2.5, 0.0, 1.0)) + + v121 = np.getTransform(v131) + if v121.isInvalid(): + return + + v64 = v121.getMat() + v138, v139, v140 = v64.xformPoint(Point3(v138, v139, v140)) + v124, v125, v126 = v64.xformPoint(Point3(v124, v125, v126)) + + v122 = v131.getTransform(NametagGlobals._camera) + if v122.isInvalid(): + return + + v124, v125, v126 = v122.getMat().xformPoint(Point3(v124, v125, v126)) + v134, v135, v136 = v122.getMat().xformPoint(Point3(v138, v139, 0.0)) + + a2 = v150.xform(Vec4(v124, v125, v126, 1.0)) + frame = v150.xform(Vec4(v134, v135, v136, 1.0)) + + if a2[3] <= 0.0 or frame[3] <= 0.0: + self.m_group.m_nametag3d_flag &= (self.m_group.m_nametag3d_flag <= 0) - 1 + self.deactivate() + return + + v123 = 1 + v133 = 1.0 / frame[3] + v128 = 1.0 / a2[3] + frame = Vec4(frame[0] * v133, a2[0] * v128, frame[1] * v133, a2[1] * v128) + + v89 = 0 + if self.m_field_396: + v124, v125, v126 = v205.xformPoint(Point3(self.m_name_frame[0] - 0.5, 0.0, self.m_name_frame[2] - 1.0)) + v138, v139, v140 = v205.xformPoint(Point3(self.m_name_frame[1] + 0.5, 0.0, self.m_name_frame[3] + 1.0)) + + v124, v125, v126 = a3.xformPoint(Point3(v124, v125, v126)) + v138, v139, v140 = a3.xformPoint(Point3(v138, v139, v140)) + + a2 = v150.xform(Vec4(v138, v139, v140, 1.0)) + v134, v135, v136, v137 = v150.xform(Vec4(v124, v125, v126, 1.0)) + + if v137 <= 0.0 or a2[3] <= 0.0: + v89 = 1 + + else: + v133 = 1.0 / v137 + v109 = 1.0 / a2[3] + v110 = v109 * a2[1] + v127 = v133 * v135 + v131 = v109 * a2[0] + v111 = v133 * v134 + v146 = v111 + if v111 < -1.0 or v131 > 1.0 or v127 < -1.0 or v110 > 1.0: + v89 = 1 + + if v123: + if frame[3] > v110: + v110 = frame[3] + if frame[2] >= v127: + v115 = v127 + else: + v115 = frame[2] + if frame[1] <= v131: + v116 = v131 + else: + v116 = frame[1] + if frame[0] >= v146: + frame[0] = v146 + + frame[1] = v116 + frame[2] = v115 + + else: + frame[0] = v146 + frame[1] = v131 + frame[2] = v127 + v123 = 1 + + frame[3] = v110 + sorta = int(v125 * -100.0) + + if v123 and self.displayAsActive(): + self.setRegion(frame, sorta) + + v118 = self.m_group.m_nametag3d_flag + if v89: + v118 = max(v118, 1) + + elif v118 <= 2: + v118 = 2 + + self.m_group.setNametag3dFlag(v118) + return + + self.m_group.incrementNametag3dFlag(2) + if not self.displayAsActive(): + return + + if not self.m_field_396: + return + + v12 = np.getNetTransform().getMat() + v124 = v12.xformPoint(Point3(self.m_name_frame[0] - 0.5, 0, self.m_name_frame[2] - 1.0)) + v16 = v12.xformPoint(Point3(self.m_name_frame[1] + 0.5, 0, self.m_name_frame[3] + 1.0)) + + v131 = Vec4(v124[0], v16[0], v124[2], v16[2]) + self.setRegion(v131, sort) diff --git a/libotp/nametag/NametagFloat2d.py b/libotp/nametag/NametagFloat2d.py new file mode 100644 index 0000000..57c1c70 --- /dev/null +++ b/libotp/nametag/NametagFloat2d.py @@ -0,0 +1,8 @@ +from Nametag3d import Nametag3d + + +class NametagFloat2d(Nametag3d): + def __init__(self): + Nametag3d.__init__(self) + self.m_is_3d = False + self.updateContents() diff --git a/libotp/nametag/NametagFloat3d.py b/libotp/nametag/NametagFloat3d.py new file mode 100644 index 0000000..74394be --- /dev/null +++ b/libotp/nametag/NametagFloat3d.py @@ -0,0 +1,6 @@ +from Nametag3d import Nametag3d + + +class NametagFloat3d(Nametag3d): + def __init__(self): + Nametag3d.__init__(self) diff --git a/libotp/nametag/NametagGlobals.py b/libotp/nametag/NametagGlobals.py new file mode 100644 index 0000000..123d188 --- /dev/null +++ b/libotp/nametag/NametagGlobals.py @@ -0,0 +1,489 @@ +from panda3d.core import * + +_speech_balloon_3d = None + + +def setSpeechBalloon3d(speech_balloon_3d): + global _speech_balloon_3d + _speech_balloon_3d = speech_balloon_3d + + +def getSpeechBalloon3d(): + return _speech_balloon_3d + + +_global_nametag_scale = 1.0 + + +def setGlobalNametagScale(global_nametag_scale): + global _global_nametag_scale + _global_nametag_scale = global_nametag_scale + + +def getGlobalNametagScale(): + return _global_nametag_scale + + +_camera = NodePath() + + +def setCamera(camera): + global _camera + _camera = camera + + +def getCamera(): + return _camera + + +_master_nametags_active = True + + +def setMasterNametagsActive(master_nametags_active): + global _master_nametags_active + _master_nametags_active = master_nametags_active + + +def getMasterNametagsActive(): + return _master_nametags_active + + +_min_2d_alpha = 0.0 + + +def setMin2dAlpha(min_2d_alpha): + global _min_2d_alpha + global _margin_prop_seq + _min_2d_alpha = min_2d_alpha + _margin_prop_seq += 1 + + +def getMin2dAlpha(): + return _min_2d_alpha + + +_arrow_color = [ + Vec4(1.0, 0.40000001, 0.2, 1.0), + Vec4(1.0, 0.40000001, 0.2, 1.0), + Vec4(1.0, 0.40000001, 0.2, 1.0), + Vec4(1.0, 0.40000001, 0.2, 1.0), + Vec4(0.30000001, 0.60000002, 1.0, 1.0), + Vec4(0.55000001, 0.55000001, 0.55000001, 1.0), + Vec4(0.30000001, 0.60000002, 1.0, 1.0), + Vec4(0.30000001, 0.69999999, 0.30000001, 1.0), + Vec4(0.30000001, 0.30000001, 0.69999999, 1.0) +] + + +def getArrowColor(index): + return _arrow_color[index] + + +_mouse_watcher = None + + +def setMouseWatcher(mouse_watcher): + global _mouse_watcher + _mouse_watcher = mouse_watcher + + +def getMouseWatcher(): + return _mouse_watcher + + +_master_arrows_on = True + + +def setMasterArrowsOn(master_arrows_on): + global _master_arrows_on + _master_arrows_on = master_arrows_on + + +def getMasterArrowsOn(): + return _master_arrows_on + + +_toon = NodePath() + + +def setToon(toon): + global _toon + _toon = toon + + +def getToon(): + return _toon + + +_master_nametags_visible = True + + +def setMasterNametagsVisible(master_nametags_visible): + global _master_nametags_visible + _master_nametags_visible = master_nametags_visible + + +def getMasterNametagsVisible(): + return _master_nametags_visible + + +_thought_balloon_2d = None + + +def setThoughtBalloon2d(thought_balloon_2d): + global _thought_balloon_2d + _thought_balloon_2d = thought_balloon_2d + + +def getThoughtBalloon2d(): + return _thought_balloon_2d + + +_max_2d_alpha = 0.6 + + +def setMax2dAlpha(max_2d_alpha): + global _max_2d_alpha + global _margin_prop_seq + _max_2d_alpha = max_2d_alpha + _margin_prop_seq += 1 + + +def getMax2dAlpha(): + return _max_2d_alpha + + +_onscreen_chat_forced = False + + +def setOnscreenChatForced(onscreen_chat_forced): + global _onscreen_chat_forced + _onscreen_chat_forced = onscreen_chat_forced + + +def getOnscreenChatForced(): + return _onscreen_chat_forced + + +_nametag_card = NodePath() + + +def setNametagCard(nametag_card, nametag_card_frame): + global _nametag_card + global _nametag_card_frame + _nametag_card = nametag_card + _nametag_card_frame = nametag_card_frame + + +def getNametagCard(): + return _nametag_card + + +_nametag_card_frame = Vec4(0, 0, 0, 0) + + +def getNametagCardFrame(): + return _nametag_card_frame + + +_rollover_sound = None + + +def setRolloverSound(rollover_sound): + global _rollover_sound + _rollover_sound = rollover_sound + + +def getRolloverSound(): + return _rollover_sound + + +_speech_balloon_2d = None + + +def setSpeechBalloon2d(speech_balloon_2d): + global _speech_balloon_2d + _speech_balloon_2d = speech_balloon_2d + + +def getSpeechBalloon2d(): + return _speech_balloon_2d + + +_text_node = TextNode('nametag') + + +def getTextNode(): + return _text_node + + +_click_sound = None + + +def setClickSound(click_sound): + global _click_sound + _click_sound = click_sound + + +def getClickSound(): + return _click_sound + + +_quit_button = [NodePath(), NodePath(), NodePath(), NodePath()] + + +def setQuitButton(state, quit_button): + global _quit_button + _quit_button[state] = quit_button + + +def getQuitButton(state): + return _quit_button[state] + + +_arrow_model = NodePath() + + +def setArrowModel(arrow_model): + global _arrow_model + _arrow_model = arrow_model + + +def getArrowModel(): + return _arrow_model + + +_thought_balloon_3d = None + + +def setThoughtBalloon3d(thought_balloon_3d): + global _thought_balloon_3d + _thought_balloon_3d = thought_balloon_3d + + +def getThoughtBalloon3d(): + return _thought_balloon_3d + + +_name_bg = [ + # CCNormal + Vec4(0.8, 0.8, 0.8, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5), + + # CCNoChat + Vec4(1, 1, 1, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5), + + # CCNonPlayer + Vec4(1, 1, 1, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5), + + # CCSuit + Vec4(0.8, 0.8, 0.8, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5), + + # CCToonBuilding + Vec4(0.8, 0.8, 0.8, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5), + + # CCSuitBuilding + Vec4(0.8, 0.8, 0.8, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5), + + # CCHouseBuilding + Vec4(0.8, 0.8, 0.8, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5), + + # CCSpeedChat + Vec4(1, 1, 1, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5), + + # CCFreeChat + Vec4(0.8, 0.8, 0.8, 0.5), + Vec4(0.2, 0.2, 0.2, 0.6), + Vec4(1, 1, 1, 1), + Vec4(0.8, 0.8, 0.8, 0.5) +] + + +def getNameBg(color_code, state): + return _name_bg[4 * color_code + state] + + +_page_button = [NodePath(), NodePath(), NodePath(), NodePath()] + + +def setPageButton(state, page_button): + global _page_button + _page_button[state] = page_button + + +def getPageButton(state): + return _page_button[state] + + +_name_fg = [ + # CCNormal + Vec4(0, 0, 1, 1), + Vec4(0.5, 0.5, 1, 1), + Vec4(0.5, 0.5, 1, 1), + Vec4(0.3, 0.3, 0.7, 1), + + # CCNoChat + Vec4(0.8, 0.4, 0, 1), + Vec4(1, 0.5, 0.5, 1), + Vec4(1, 0.5, 0, 1), + Vec4(0.6, 0.4, 0.2, 1), + + # CCNonPlayer + Vec4(0.8, 0.4, 0, 1), + Vec4(1, 0.5, 0.5, 1), + Vec4(1, 0.5, 0, 1), + Vec4(0.6, 0.4, 0.2, 1), + + # CCSuit + Vec4(0, 0, 0, 1), + Vec4(1, 1, 1, 1), + Vec4(0.5, 0.5, 0.5, 1), + Vec4(0.2, 0.2, 0.2, 1), + + # CCToonBuilding + Vec4(0, 0, 0, 1), + Vec4(1, 1, 1, 1), + Vec4(0.5, 0.5, 0.5, 1), + Vec4(0.3, 0.6, 1, 1), + + # CCSuitBuilding + Vec4(0, 0, 0, 1), + Vec4(1, 1, 1, 1), + Vec4(0.5, 0.5, 0.5, 1), + Vec4(0.55, 0.55, 0.55, 1), + + # CCHouseBuilding + Vec4(0, 0, 0, 1), + Vec4(1, 1, 1, 1), + Vec4(0.5, 0.5, 0.5, 1), + Vec4(0.3, 0.6, 1, 1), + + # CCSpeedChat + Vec4(0, 0.6, 0.2, 1), + Vec4(0, 0.6, 0.2, 1), + Vec4(0, 1, 0.5, 1), + Vec4(0.1, 0.4, 0.2, 1), + + # CCFreeChat + Vec4(0.3, 0.3, 0.7, 1), + Vec4(0.2, 0.2, 0.5, 1), + Vec4(0.5, 0.5, 1, 1), + Vec4(0.3, 0.3, 0.7, 1) +] + + +def getNameFg(color_code, state): + return _name_fg[4 * color_code + state] + + +def getNameWordwrap(): + return 7.5 + + +_card_pad = Vec4(0.1, 0.1, 0.1, 0) + + +def getCardPad(): + return _card_pad + + +_whisper_colors = [ + [ + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.3, 0.6, 0.8, 0.6)), + (Vec4(1.0, 0.5, 0.5, 1.0), Vec4(1.0, 1.0, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.4, 0.8, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.3, 0.6, 0.8, 0.6)) + ], + [ + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.3, 0.6, 0.8, 0.6)), + (Vec4(1.0, 0.5, 0.5, 1.0), Vec4(1.0, 1.0, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.4, 0.8, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.3, 0.6, 0.8, 0.6)) + ], + [ + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.8, 0.3, 0.6, 0.6)), + (Vec4(1.0, 0.5, 0.5, 1.0), Vec4(1.0, 1.0, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.8, 0.4, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.8, 0.3, 0.6, 0.6)) + ], + [ + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.8, 0.3, 0.6, 0.6)), + (Vec4(1.0, 0.5, 0.5, 1.0), Vec4(1.0, 1.0, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.8, 0.4, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.8, 0.3, 0.6, 0.6)) + ], + [ + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.3, 0.6, 0.8, 0.6)), + (Vec4(1.0, 0.5, 0.5, 1.0), Vec4(1.0, 1.0, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.4, 1.0, 1.0, 0.4)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.3, 0.8, 0.3, 0.6)) + ], + [ + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.97, 0.43, 0.1, 0.6)), + (Vec4(1.0, 0.5, 0.5, 1.0), Vec4(1.0, 1.0, 1.0, 1.0)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.98, 0.6, 0.38, 0.6)), + (Vec4(0.0, 0.0, 0.0, 1.0), Vec4(0.97, 0.43, 0.1, 0.6)) + ] +] + + +def getWhisperFg(color_code, state): + return Vec4(_whisper_colors[color_code][state][0]) + + +def getWhisperBg(color_code, state): + return Vec4(_whisper_colors[color_code][state][1]) + + +_balloon_modulation_color = Vec4(1.0, 1.0, 1.0, 1.0) + + +def setBalloonModulationColor(balloon_modulation_color): + global _balloon_modulation_color + _balloon_modulation_color = balloon_modulation_color + + +def getBalloonModulationColor(): + return _balloon_modulation_color + + +def getChatFg(color_code, state): + return [Vec4(0.0, 0.0, 0.0, 1.0), + Vec4(1.0, 0.5, 0.5, 1.0), + Vec4(0.0, 0.6, 0.6, 1.0), + Vec4(0.0, 0.0, 0.0, 1.0)][state] + + +def getChatBg(color_code, state): + return [Vec4(1.0, 1.0, 1.0, 1.0), + Vec4(1.0, 1.0, 1.0, 1.0), + Vec4(1.0, 1.0, 1.0, 1.0), + Vec4(1.0, 1.0, 1.0, 1.0)][state] + + +_margin_prop_seq = 0 +_default_qt_color = Vec4(0.8, 0.8, 1, 1) +_balloon_text_origin = Point3(1.0, 0, 2.0) diff --git a/libotp/nametag/NametagGroup.py b/libotp/nametag/NametagGroup.py new file mode 100644 index 0000000..70574f2 --- /dev/null +++ b/libotp/nametag/NametagGroup.py @@ -0,0 +1,426 @@ +from panda3d.core import * + +import NametagGlobals +from Nametag2d import Nametag2d +from Nametag3d import Nametag3d +from _constants import * + + +class NametagGroup: + CCNormal = 0 + CCNoChat = 1 + CCNonPlayer = 2 + CCSuit = 3 + CCToonBuilding = 4 + CCSuitBuilding = 5 + CCHouseBuilding = 6 + CCSpeedChat = 7 + CCFreeChat = 8 + + _unique_index = 0 + + def __init__(self): + self.m_nametags = [] + + self.m_name_font = None + self.m_chat_font = None + + self.m_avatar = None + self.m_node = None + + self.m_name = '' + self.m_display_name = '' + + self.m_chat_pages = [] + self.m_stomp_text = '' + self.m_unique_name = '' + + self.m_region_seq = 0 + + self.m_name_icon = NodePath.anyPath(PandaNode('icon')) + self.m_name_frame = Vec4(0, 0, 0, 0) + + self.m_wordwrap = -1.0 + self.m_color_code = 0 + self.m_qt_color = Vec4(NametagGlobals._default_qt_color) + self.m_balloon_color = Vec4(NametagGlobals._balloon_modulation_color) + self.m_shadow = (0, 0) + self.m_has_shadow = False + + self.m_timeout = 0.0 + self.m_timeout_start = 0.0 + self.m_has_timeout = False + self.m_stomp_time = 0.0 + self.m_stomp_chat_flags = None + self.m_chat_flags = 0 + self.m_page_number = 0 + self.m_stomp_delay = 0.5 + self.m_chat_stomp = 0 + + self.m_unique_name = 'nametag-%d' % NametagGroup._unique_index + NametagGroup._unique_index += 1 + + self.m_object_code = 0 + self.m_nametag3d_flag = 0 + self.m_manager = None + + self.m_region_seq += 1 + + self.m_contents = CFSpeech | CFThought | CFQuicktalker + self.m_is_active = 1 + self.m_active = NametagGlobals._master_nametags_active + self.m_visible = NametagGlobals._master_nametags_visible + + self.m_tag2d = Nametag2d() + self.m_tag3d = Nametag3d() + self.addNametag(self.m_tag2d) + self.addNametag(self.m_tag3d) + + def setFont(self, font): + self.setNameFont(font) + self.setChatFont(font) + + def setNameFont(self, font): + self.m_name_font = font + + def getNameFont(self): + return self.m_name_font + + def setChatFont(self, font): + self.m_chat_font = font + + def getChatFont(self): + return self.m_chat_font + + def setAvatar(self, avatar): + self.m_avatar = avatar + + def getAvatar(self): + return self.m_avatar + + def setNameIcon(self, icon): + self.m_name_icon = icon + + def getNameIcon(self): + return self.m_name_icon + + def setColorCode(self, code): + self.m_color_code = code + + def getColorCode(self): + return self.m_color_code + + def setContents(self, contents): + self.m_contents = contents + + def getContents(self): + return self.m_contents + + def setDisplayName(self, name): + self.m_display_name = name + + if name and self.m_name_font: + text_node = NametagGlobals.getTextNode() + text_node.setFont(self.m_name_font) + text_node.setWordwrap(self.getNameWordwrap()) + text_node.setAlign(TextNode.ACenter) + text_node.setText(name) + gen = text_node.generate() + self.m_node = gen + self.m_name_frame = text_node.getCardActual() + + if self.m_has_shadow: + self.m_node = PandaNode('name') + self.m_node.addChild(gen) + + pos = Point3(self.m_shadow[0], 0, -self.m_shadow[1]) + attached = NodePath.anyPath(self.m_node).attachNewNode(gen.copySubgraph()) + attached.setPos(pos) + attached.setColor(0, 0, 0, 1) + + else: + self.m_node = None + + self.updateContentsAll() + + def getDisplayName(self): + return self.m_display_name + + def setName(self, name): + self.m_name = name + self.setDisplayName(name) + + def getName(self): + return self.m_name + + def getNameFrame(self): + return self.m_name_frame + + def setNameWordwrap(self, wordwrap): + self.m_wordwrap = wordwrap + self.setDisplayName(self.m_display_name) + + def getNameWordwrap(self): + if self.m_wordwrap > 0.0: + return self.m_wordwrap + + wordwrap = NametagGlobals.getNameWordwrap() + return {self.CCNoChat: 7.8, + self.CCToonBuilding: 8.5, + self.CCSuitBuilding: 8.5, + self.CCHouseBuilding: 10.0}.get(self.m_color_code, wordwrap) + + def getNametag(self, index): + return self.m_nametags[index] + + def getNametag2d(self): + return self.m_tag2d + + def getNametag3d(self): + return self.m_tag3d + + def setNametag3dFlag(self, flag): + self.m_nametag3d_flag = flag + + def getNametag3dFlag(self): + return self.m_nametag3d_flag + + def getNumChatPages(self): + return len(self.m_chat_pages) + + def getNumNametags(self): + return len(self.m_nametags) + + def setObjectCode(self, code): + self.m_object_code = code + + def getObjectCode(self): + return self.m_object_code + + def setPageNumber(self, page): + if self.m_page_number == page: + return + + self.m_page_number = page + if self.willHaveButton(): + self.m_timeout_start = globalClock.getFrameTime() + 0.2 + self.m_has_timeout = True + + self.updateContentsAll() + + def getPageNumber(self): + return self.m_page_number + + def getBalloonModulationColor(self): + return self.m_balloon_color + + def setQtColor(self, color): + self.m_qt_color = color + + def getQtColor(self): + return self.m_qt_color + + def getRegionSeq(self): + return self.m_region_seq + + def setShadow(self, shadow): + self.m_shadow = shadow + + def getShadow(self): + return self.m_shadow + + def getStompDelay(self): + return self.m_stomp_delay + + def getStompText(self): + return self.m_stomp_text + + def setUniqueId(self, name): + self.m_unique_name = name + + def getUniqueId(self): + return self.m_unique_name + + def hasButton(self): + if self.m_has_timeout: + return False + + return self.willHaveButton() + + def hasNoQuitButton(self): + return (not self.m_has_timeout) and self.m_chat_flags & CFSpeech + + def hasQuitButton(self): + return (not self.m_has_timeout) and self.m_chat_flags & CFQuitButton + + def hasPageButton(self): + return (not self.m_has_timeout) and self.m_chat_flags & CFPageButton + + def hasShadow(self): + return self.m_has_shadow + + def clearShadow(self): + self.m_has_shadow = False + + def incrementNametag3dFlag(self, flag): + self.m_nametag3d_flag = max(self.m_nametag3d_flag, flag) + + def isManaged(self): + return self.m_manager is not None + + def manage(self, manager): + if not self.m_manager: + self.m_manager = manager + for nametag in self.m_nametags: + nametag.manage(manager) + + def unmanage(self, manager): + if self.m_manager: + self.m_manager = None + for nametag in self.m_nametags: + nametag.unmanage(manager) + + def addNametag(self, nametag): + if nametag.m_group: + print 'Attempt to add %s twice to %s.' % (nametag.__class__.__name__, self.m_name) + return + + nametag.m_group = self + nametag.updateContents() + self.m_nametags.append(nametag) + + if self.m_manager: + nametag.manage(self.m_manager) + + def removeNametag(self, nametag): + if not nametag.m_group: + print 'Attempt to removed %s twice from %s.' % (nametag.__class__.__name__, self.m_name) + return + + if self.m_manager: + nametag.unmanage(self.m_manager) + + nametag.m_group = None + nametag.updateContents() + self.m_nametags.remove(nametag) + + def setActive(self, active): + self.m_is_active = active + + def isActive(self): + return self.m_active + + def updateContentsAll(self): + for nametag in self.m_nametags: + nametag.updateContents() + + def updateRegions(self): + for nametag in self.m_nametags: + nametag.updateRegion(self.m_region_seq) + + self.m_region_seq += 1 + + now = globalClock.getFrameTime() + if self.m_stomp_time < now and self.m_chat_stomp > 1: + self.m_chat_stomp = 0 + self.setChat(self.m_stomp_text, self.m_stomp_chat_flags, self.m_page_number) + + if self.m_chat_flags & CFTimeout and now >= self.m_timeout: + self.clearChat() + self.m_chat_stomp = 0 + + v7 = False + if self.m_has_timeout and now >= self.m_timeout_start: + self.m_has_timeout = 0 + v7 = True + + if self.m_active != NametagGlobals._master_nametags_active: + self.m_active = NametagGlobals._master_nametags_active + v7 = True + + if self.m_visible == NametagGlobals._master_nametags_visible: + if not v7: + return + + else: + self.m_visible = NametagGlobals._master_nametags_visible + + self.updateContentsAll() + + def willHaveButton(self): + return self.m_chat_flags & (CFPageButton | CFQuitButton) + + def setChat(self, chat, chat_flags, page_number=0): + self.m_chat_flags = chat_flags + self.m_page_number = page_number + + now = globalClock.getFrameTime() + must_split = True + if chat_flags and chat: + self.m_chat_stomp += 1 + if self.m_chat_stomp >= 2 and self.m_stomp_delay >= 0.05: + self.m_stomp_text = chat + self.m_stomp_chat_flags = self.m_chat_flags + self.m_stomp_time = now + self.m_stomp_delay + self.m_chat_flags = 0 + must_split = False + + else: + self.m_chat_flags = 0 + self.m_chat_stomp = 0 + must_split = False + + if must_split: + self.m_chat_pages = chat.split('\x07') + else: + self.m_chat_pages = [] + + if self.m_chat_flags & CFTimeout and self.m_stomp_time < now: + timeout = len(chat) * 0.5 + timeout = min(12.0, max(timeout, 4.0)) + self.m_timeout = timeout + now + + if self.willHaveButton(): + self.m_has_timeout = True + self.m_timeout_start = now + 0.2 + + else: + self.m_has_timeout = False + self.m_timeout_start = 0.0 + + self.updateContentsAll() + + def getChat(self): + if self.m_chat_pages: + return self.m_chat_pages[self.m_page_number] + + return '' + + def clearChat(self): + self.setChat('', 0, 0) + + def getChatStomp(self): + return self.m_chat_stomp + + def clearAuxNametags(self): + for nametag in self.nametags[:]: + if nametag not in (self.m_tag2d, self.m_tag3d): + self.removeNametag(nametag) + + def click(self): + messenger.send(self.m_unique_name) + + def copyNameTo(self, to): + return to.attachNewNode(self.m_node.copySubgraph()) + + def displayAsActive(self): + if self.m_is_active and NametagGlobals._master_nametags_active: + return 1 + + return self.hasButton() + + def frameCallback(self): + # This should be in Nametag2d + # I have no idea where libotp called it + # so I'm doing it in MarginManager.update + self.updateRegions() diff --git a/libotp/nametag/WhisperPopup.py b/libotp/nametag/WhisperPopup.py new file mode 100644 index 0000000..b258bb8 --- /dev/null +++ b/libotp/nametag/WhisperPopup.py @@ -0,0 +1,156 @@ +from ClickablePopup import * +from MarginPopup import * + + +class WhisperPopup(ClickablePopup, MarginPopup): + WTNormal = 0 + WTQuickTalker = 1 + WTSystem = 2 + WTBattleSOS = 3 + WTEmote = 4 + WTToontownBoardingGroup = 5 + + def __init__(self, text, font, type): + ClickablePopup.__init__(self) + MarginPopup.__init__(self) + + self.m_text = text + self.m_font = font + self.m_type = type + + self.m_np_balloon = None + self.m_avname = '' + self.m_region = None + self.m_mouse_watcher = None + self.m_manager = None + + # self.setCullCallback() + self.cbNode = CallbackNode(self.getName() + '-cbNode') + self.cbNode.setCullCallback(PythonCallbackObject(self.cullCallback)) + self.addChild(self.cbNode) + + self.m_time = 0 + self.m_culled = False + self.m_clickable = False + self.m_avid = 0 + self.m_is_player = False + self.m_is_player_id = None + self.m_state = 3 + self.m_objcode = 0 + + def setClickable(self, avatar_name, avatar_id, is_player_id=False): + self.m_clickable = True + self.m_avname = avatar_name + self.m_avid = avatar_id + self.m_is_player_id = is_player_id + self.m_state = 0 + + def click(self): + messenger.send('clickedWhisper', [self.m_avid, self.m_is_player]) + + def considerVisible(self): + if self.m_clickable and self.m_visible and self.m_mouse_watcher != NametagGlobals._mouse_watcher: + return False + + if self.m_seq != NametagGlobals._margin_prop_seq: + self.m_seq = NametagGlobals._margin_prop_seq + self.updateContents() + + return True + + def manage(self, manager): + self.m_manager = manager + manager.managePopup(self) + + def unmanage(self, manager): + manager.unmanagePopup(self) + del self.m_manager + + def cullCallback(self, *args): + if not self.m_culled: + self.m_culled = True + self.m_time = globalClock.getFrameTime() + + def setVisible(self, value): + MarginPopup.setVisible(self, value) + self.updateContents() + + if self.m_clickable: + if self.m_region: + if self.m_visible: + self.m_region.activate() + self.m_mouse_watcher = NametagGlobals._mouse_watcher + self.m_mouse_watcher.addRegion(self.m_region) + + elif self.m_mouse_watcher: + self.m_region.deactivate() + self.m_mouse_watcher.removeRegion(self.m_region) + self.m_mouse_watcher = None + + def setRegion(self, frame, sort): + if self.m_region: + self.m_region.setFrame(frame) + + else: + self.m_region = self._createRegion(frame) + + self.m_region.setSort(sort) + + def updateContents(self): + if self.m_np_balloon: + self.m_np_balloon.removeNode() + self.m_np_balloon = None + + if self.m_visible: + self.generateText(NametagGlobals._speech_balloon_2d, self.m_text, self.m_font) + + def generateText(self, balloon, text, font): + text_color = Vec4(NametagGlobals.getWhisperFg(self.m_type, self.m_state)) + balloon_color = Vec4(NametagGlobals.getWhisperBg(self.m_type, self.m_state)) + balloon_color[3] = max(balloon_color[3], NametagGlobals._min_2d_alpha) + balloon_color[3] = min(balloon_color[3], NametagGlobals._max_2d_alpha) + + balloon_result = balloon.generate(text, font, 8.0, text_color, balloon_color, + False, False, 0, None, False, False, None) + + self.m_np_balloon = self.m_np.attachNewNode(balloon_result) + + v34 = self.m_cell_width * 0.22222222 + v35 = balloon.m_text_height * balloon.m_hscale * 0.5 + v57 = -balloon.m_hscale * 5.5 + v16 = -(NametagGlobals._balloon_text_origin[2] + v35) + + v64 = Mat4(v34, 0, 0, 0, + 0, v34, 0, 0, + 0, 0, v34, 0, + v57 * v34, 0, v16 * v34, 1.0) + + self.m_np_balloon.setMat(v64) + + reducer = SceneGraphReducer() + reducer.applyAttribs(self.m_np_balloon.node()) + + if self.m_clickable: + v22 = self.m_np.getNetTransform().getMat() + v39, _, v41 = v22.xformPoint(Point3(v57 * v34, 0.0, v16 * v34)) + v27, _, v28 = v22.xformPoint(Point3(-v57 * v34, 0.0, -v16 * v34)) + self.setRegion(Vec4(v39, v27, v41, v28), 0) + + def setObjectCode(self, objcode): + self.m_objcode = objcode + + def getObjectCode(self): + return self.m_objcode + + def getScore(self): + result = 2000 + + if self.m_culled: + elapsed = globalClock.getFrameTime() - self.m_time + result -= elapsed * 200 + + # moved from considerManage: + if elapsed > 15.0: + self.unmanage(self.m_manager) + + return result diff --git a/libotp/nametag/__init__.py b/libotp/nametag/__init__.py new file mode 100644 index 0000000..10c788f --- /dev/null +++ b/libotp/nametag/__init__.py @@ -0,0 +1,13 @@ +import NametagGlobals +from ChatBalloon import ChatBalloon +from ClickablePopup import ClickablePopup +from MarginManager import MarginManager +from MarginPopup import MarginPopup +from Nametag import Nametag +from Nametag2d import Nametag2d +from Nametag3d import Nametag3d +from NametagFloat2d import NametagFloat2d +from NametagFloat3d import NametagFloat3d +from NametagGroup import NametagGroup +from WhisperPopup import WhisperPopup +from _constants import * diff --git a/libotp/nametag/_constants.py b/libotp/nametag/_constants.py new file mode 100644 index 0000000..0f75f38 --- /dev/null +++ b/libotp/nametag/_constants.py @@ -0,0 +1,9 @@ +CFSpeech = 1 +CFThought = 2 +CFQuicktalker = 4 +CFTimeout = 8 +CFPageButton = 16 +CFQuitButton = 32 +CFReversed = 64 +CFSndOpenchat = 128 +CFNoQuitButton = 256 diff --git a/libotp/settings/Settings.py b/libotp/settings/Settings.py new file mode 100644 index 0000000..4179d72 --- /dev/null +++ b/libotp/settings/Settings.py @@ -0,0 +1,32 @@ +class Settings: + @staticmethod + def readSettings(): + pass # todo + + @staticmethod + def getWindowedMode(): + return 1 + + @staticmethod + def getMusic(): + return 1 + + @staticmethod + def getSfx(): + return 1 + + @staticmethod + def getToonChatSounds(): + return 1 + + @staticmethod + def getMusicVolume(): + return 1 + + @staticmethod + def getSfxVolume(): + return 1 + + @staticmethod + def getResolution(): + return 1 diff --git a/libotp/settings/__init__.py b/libotp/settings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/otp/launcher/LauncherBase.py b/otp/launcher/LauncherBase.py index 1d12bae..4d87576 100644 --- a/otp/launcher/LauncherBase.py +++ b/otp/launcher/LauncherBase.py @@ -3,7 +3,7 @@ import os import time import string import __builtin__ -from pandac.libpandaexpressModules import * +from panda3d.core import * from direct.showbase.MessengerGlobal import * from direct.showbase.DirectObject import DirectObject from direct.showbase.EventManagerGlobal import * @@ -1855,7 +1855,7 @@ class LauncherBase(DirectObject): self.notify.info("Third party programs installed:") for hack in hacksInstalled.keys(): self.notify.info(hack) - + if len(hacksRunning) > 0: self.notify.info("Third party programs running:") for hack in hacksRunning.keys(): diff --git a/otp/otpbase/OTPLocalizer.py b/otp/otpbase/OTPLocalizer.py index b651766..f2f9644 100644 --- a/otp/otpbase/OTPLocalizer.py +++ b/otp/otpbase/OTPLocalizer.py @@ -1,9 +1,10 @@ -from pandac.libpandaexpressModules import * +from panda3d.core import * +from direct.showbase import DConfig import string import types try: - language = getConfigExpress().GetString('language', 'english') - checkLanguage = getConfigExpress().GetBool('check-language', 0) + language = DConfig.GetString('language', 'english') + checkLanguage = DConfig.GetBool('check-language', 0) except: language = simbase.config.GetString('language', 'english') checkLanguage = simbase.config.GetBool('check-language', 0) diff --git a/toontown/launcher/ToontownLauncher.py b/toontown/launcher/ToontownLauncher.py index eb4ea7c..d478d89 100644 --- a/toontown/launcher/ToontownLauncher.py +++ b/toontown/launcher/ToontownLauncher.py @@ -39,7 +39,7 @@ if 1: from otp.launcher.LauncherBase import LauncherBase from otp.otpbase import OTPLauncherGlobals -from pandac.libpandaexpressModules import * +from panda3d.core import * from toontown.toonbase import TTLocalizer class ToontownLauncher(LauncherBase): diff --git a/toontown/toonbase/TTLocalizer.py b/toontown/toonbase/TTLocalizer.py index fb0ed77..ab54c80 100644 --- a/toontown/toonbase/TTLocalizer.py +++ b/toontown/toonbase/TTLocalizer.py @@ -1,9 +1,10 @@ -from pandac.libpandaexpressModules import * +from panda3d.core import * +from direct.showbase import DConfig import string import types try: - language = getConfigExpress().GetString('language', 'english') - checkLanguage = getConfigExpress().GetBool('check-language', 0) + language = DConfig.GetString('language', 'english') + checkLanguage = DConfig.GetBool('check-language', 0) except: language = simbase.config.GetString('language', 'english') checkLanguage = simbase.config.GetBool('check-language', 0) diff --git a/toontown/toonbase/ToonBase.py b/toontown/toonbase/ToonBase.py index f96b66e..7dc4737 100644 --- a/toontown/toonbase/ToonBase.py +++ b/toontown/toonbase/ToonBase.py @@ -8,6 +8,7 @@ import ToontownLoader from direct.gui import DirectGuiGlobals from direct.gui.DirectGui import * from pandac.PandaModules import * +from libotp import * import sys import os import math @@ -196,9 +197,9 @@ class ToonBase(OTPBase.OTPBase): self.useDrive() self.disableMouse() if self.mouseInterface: - self.mouseInterface.reparentTo(self.dataUnused) + self.mouseInterface.detachNode() if base.mouse2cam: - self.mouse2cam.reparentTo(self.dataUnused) + self.mouse2cam.detachNode() def __walking(self, pressed): self.walking = pressed @@ -399,3 +400,8 @@ class ToonBase(OTPBase.OTPBase): def playMusic(self, music, looping = 0, interrupt = 1, volume = None, time = 0.0): OTPBase.OTPBase.playMusic(self, self.resetMusic) OTPBase.OTPBase.playMusic(self, music, looping, interrupt, volume, time) + + def isMainWindowOpen(self): + if self.win != None: + return self.win.isValid() + return 0 diff --git a/toontown/toonbase/ToontownAccess.py b/toontown/toonbase/ToontownAccess.py index 5498800..147e8af 100644 --- a/toontown/toonbase/ToontownAccess.py +++ b/toontown/toonbase/ToontownAccess.py @@ -1,4 +1,4 @@ -from pandac.PandaModules import listProcessModules +#from pandac.PandaModules import listProcessModules from direct.task import Task from toontown.hood import ZoneUtil from toontown.toonbase import ToontownGlobals @@ -28,7 +28,7 @@ class ToontownAccess: return task.again def getModuleList(self): - moduleString = listProcessModules() + moduleString = '' #listProcessModules() moduleList = [] if moduleString: moduleList = moduleString.split(',') diff --git a/toontown/toonbase/ToontownStart.py b/toontown/toonbase/ToontownStart.py index 516198c..73658fb 100644 --- a/toontown/toonbase/ToontownStart.py +++ b/toontown/toonbase/ToontownStart.py @@ -31,7 +31,7 @@ if launcher.isDummy(): http = HTTPClient() else: http = launcher.http -tempLoader = PandaLoader() +tempLoader = Loader() backgroundNode = tempLoader.loadSync(Filename('phase_3/models/gui/loading-background')) from direct.gui import DirectGuiGlobals print 'ToontownStart: setting default font'