def generateOtherPlayerGui(self): for avId in self.doId2Frame.keys(): self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId] = {} headNumber = -1 frame = self.doId2Frame[avId][0] otherPlayerHeadsFrame = DirectFrame(relief=None, scale=0.85, parent=frame) otherPlayerHeadsFrame['image'] = frame['image'] otherPlayerHeadsFrame['image_color'] = frame['image_color'] otherPlayerHeadsFrame[ 'image_scale'] = self.otherPlayerHeadHolderTransforms['scale'] otherPlayerHeadsFrame.setPos( self.otherPlayerHeadHolderTransforms['pos']) otherPlayerHeadsFrame.setBin('gui-popup', 70) self.frameList.append(otherPlayerHeadsFrame) for otherAvId in self.doId2Frame.keys(): if otherAvId != avId: headNumber += 1 otherAv = base.cr.doId2do.get(otherAvId) headFrame = otherPlayerHeadsFrame.attachNewNode( 'otherPlayerHeadFrame') headFrame.setPosHprScale( self.otherPlayerHeadXValues[headNumber], 5, -0.1, 180, 0, 0, 0.2, 0.2, 0.2) headFrame.setColorScale(self.state2Color[0]) head = ToonGlobals.generateGuiHead(otherAv) head.reparentTo(headFrame) self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId][ otherAvId] = headFrame
def generate(self, gender, head, headtype, color, doId, name, valueLabel = 1): gui = loader.loadModel("phase_3/models/gui/pick_a_toon_gui.bam") bg = gui.find('**/av-chooser_Square_UP') container = DirectFrame(relief=None, scale=0.3, parent=base.a2dTopLeft) container['image'] = bg container['image_color'] = self.frameColors[len(self.frameList)] container.setBin('gui-popup', 60) container.setPos(self.framePositions[len(self.frameList)]) headframe = container.attachNewNode('head') headframe.setPosHprScale(0, 5, -0.1, 180, 0, 0, 0.24, 0.24, 0.24) toon = ToonHead(None) toon.generateHead(gender, head, headtype) r, g, b = color color = (r, g, b, 1.0) toon.setHeadColor(color) toon.setDepthWrite(1) toon.setDepthTest(1) toon.reparentTo(headframe) nameLbl = DirectLabel(text=name, text_wordwrap=7.0, parent=container, text_scale=0.13, text_fg=(1,1,1,1), text_shadow=(0,0,0,1), relief=None, pos=(0, 0, 0.25)) if valueLabel: someValueToBroadcast = DirectLabel(text="0", parent=container, text_scale=0.15, text_fg=(1,1,1,1), text_shadow=(0,0,0,1), relief=None, pos=(0.26, 0, -0.28)) self.frameList.append(container) if valueLabel: self.doId2Frame[doId] = tuple((container, headframe, toon, nameLbl, someValueToBroadcast)) else: self.doId2Frame[doId] = tuple((container, headframe, toon, nameLbl))
def _createPartyEditorPage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerEditorPage') self.LayoutTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerEditorTitle, pos=self.gui.find('**/title_locator').getPos() + Point3(0.0, 0.0, 0.075), scale=self.titleScale) self.costLabel = DirectLabel(parent=page, pos=(-0.74, 0.0, 0.17), relief=None, text=TTLocalizer.PartyPlannerTotalCost % 0, text_align=TextNode.ACenter, scale=TTLocalizer.PPcostLabel, textMayChange=True) self.partyGridBackground = DirectFrame(parent=page, relief=None, geom=self.gui.find('**/partyGrid_flat')) self.partyGroundsLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerPartyGrounds, text_font=ToontownGlobals.getSignFont(), text_fg=VBase4(1.0, 0.0, 0.0, 1.0), text_scale=TTLocalizer.PPpartyGroundsLabel, pos=self.gui.find('**/step_05_partyGrounds_text_locator').getPos(), scale=0.1) self.activityBackground = DirectFrame(parent=page, relief=None, geom=self.gui.find('**/activitiesDecorations_flat1'), pos=(0.0, 0.0, 0.04)) pos = self.gui.find('**/step_05_instructions_locator').getPos() self.instructionLabel = DirectLabel(parent=page, relief=None, text=' ', text_pos=(pos[0], pos[2]), text_scale=TTLocalizer.PPinstructionLabel, textMayChange=True, geom=self.gui.find('**/instructions_flat')) self.elementTitleLabel = DirectLabel(parent=page, relief=None, text=' ', pos=self.gui.find('**/step_05_activitiesName_text_locator').getPos() + Point3(0.0, 0.0, 0.04), text_scale=TTLocalizer.PPelementTitleLabel, textMayChange=True) self.elementPriceNode = TextNode('ElementPrice') self.elementPriceNode.setAlign(TextNode.ALeft) self.elementPriceNode.setTextColor(0.0, 0.0, 0.0, 1.0) self.elementPriceNode.setFont(ToontownGlobals.getToonFont()) self.elementPrice = page.attachNewNode(self.elementPriceNode) self.elementPrice.setScale(TTLocalizer.PPelementPriceNode) self.elementPrice.setPos(self.gui.find('**/step_05_activityPrice_text_locator').getPos() + Point3(-0.02, 0.0, 0.04)) self.elementDescriptionNode = TextNode('ElementDescription') self.elementDescriptionNode.setAlign(TextNode.ACenter) self.elementDescriptionNode.setWordwrap(8) self.elementDescriptionNode.setFont(ToontownGlobals.getToonFont()) self.elementDescriptionNode.setTextColor(0.0, 0.0, 0.0, 1.0) self.elementDescription = page.attachNewNode(self.elementDescriptionNode) self.elementDescription.setScale(TTLocalizer.PPelementDescription) self.elementDescription.setPos(self.gui.find('**/step_05_activityDescription_text_locator').getPos() + Point3(0.0, 0.0, 0.04)) self.totalMoney = base.localAvatar.getTotalMoney() catalogGui = loader.loadModel('phase_5.5/models/gui/catalog_gui') self.beanBank = DirectLabel(parent=page, relief=None, text=str(self.totalMoney), text_align=TextNode.ARight, text_scale=0.075, text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_pos=(0.495, -0.53), text_font=ToontownGlobals.getSignFont(), textMayChange=True, image=catalogGui.find('**/bean_bank'), image_scale=(0.65, 0.65, 0.65), scale=0.9, pos=(-0.75, 0.0, 0.6)) catalogGui.removeNode() del catalogGui self.accept(localAvatar.uniqueName('moneyChange'), self.__moneyChange) self.accept(localAvatar.uniqueName('bankMoneyChange'), self.__moneyChange) self.partyEditor = PartyEditor(self, page) self.partyEditor.request('Hidden') pos = self.gui.find('**/step_05_add_text_locator').getPos() self.elementBuyButton = DirectButton(parent=page, relief=None, text=TTLocalizer.PartyPlannerBuy, text_pos=(pos[0], pos[2]), text_scale=TTLocalizer.PPelementBuyButton, geom=(self.gui.find('**/add_up'), self.gui.find('**/add_down'), self.gui.find('**/add_rollover')), geom3_color=VBase4(0.5, 0.5, 0.5, 1.0), textMayChange=True, pos=(0.0, 0.0, 0.04), command=self.partyEditor.buyCurrentElement) self.okWithPartyGroundsLayoutEvent = 'okWithPartyGroundsLayoutEvent' self.accept(self.okWithPartyGroundsLayoutEvent, self.okWithPartyGroundsLayout) self.okWithGroundsGui = TTDialog.TTGlobalDialog(dialogName=self.uniqueName('PartyEditorOkGui'), doneEvent=self.okWithPartyGroundsLayoutEvent, message=TTLocalizer.PartyPlannerOkWithGroundsLayout, style=TTDialog.YesNo, okButtonText=OTPLocalizer.DialogYes, cancelButtonText=OTPLocalizer.DialogNo) self.okWithGroundsGui.doneStatus = '' self.okWithGroundsGui.hide() return page
def generateOtherPlayerGui(self): for avId in self.doId2Frame.keys(): self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId] = {} headNumber = -1 frame = self.doId2Frame[avId][0] otherPlayerHeadsFrame = DirectFrame(relief=None, scale=0.85, parent=frame) otherPlayerHeadsFrame['image'] = frame['image'] otherPlayerHeadsFrame['image_color'] = frame['image_color'] otherPlayerHeadsFrame[ 'image_scale'] = self.otherPlayerHeadHolderTransforms['scale'] otherPlayerHeadsFrame.setPos( self.otherPlayerHeadHolderTransforms['pos']) otherPlayerHeadsFrame.setBin('gui-popup', 70) self.frameList.append(otherPlayerHeadsFrame) for otherAvId in self.doId2Frame.keys(): if otherAvId != avId: headNumber += 1 otherAv = base.cr.doId2do.get(otherAvId) gender = otherAv.getGender() head, color = otherAv.getHeadStyle() animal = otherAv.getAnimal() headFrame = otherPlayerHeadsFrame.attachNewNode( 'otherPlayerHeadFrame') headFrame.setPosHprScale( self.otherPlayerHeadXValues[headNumber], 5, -0.1, 180, 0, 0, 0.2, 0.2, 0.2) headFrame.setColorScale(self.state2Color[0]) toon = ToonHead(None) toon.generateHead(gender, animal, head) r, g, b, _ = color color = (r, g, b, 1.0) toon.setHeadColor(color) toon.setDepthWrite(1) toon.setDepthTest(1) toon.reparentTo(headFrame) self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId][ otherAvId] = headFrame
def generate(self, gender, head, headtype, color, doId, name, valueLabel = 1): gui = loader.loadModel('phase_3/models/gui/pick_a_toon_gui.bam') bg = gui.find('**/av-chooser_Square_UP') container = DirectFrame(relief=None, scale=0.3, parent=base.a2dTopLeft) container['image'] = bg container['image_color'] = self.frameColors[len(self.frameList)] container.setBin('gui-popup', 60) container.setPos(self.framePositions[len(self.frameList)]) headframe = container.attachNewNode('head') headframe.setPosHprScale(0, 5, -0.1, 180, 0, 0, 0.24, 0.24, 0.24) toon = ToonHead(None) toon.generateHead(gender, head, headtype) r, g, b = color color = (r, g, b, 1.0) toon.setHeadColor(color) toon.setDepthWrite(1) toon.setDepthTest(1) toon.reparentTo(headframe) nameLbl = DirectLabel(text=name, text_wordwrap=7.0, parent=container, text_scale=0.13, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), relief=None, pos=(0, 0, 0.25)) if valueLabel: someValueToBroadcast = DirectLabel(text='0', parent=container, text_scale=0.15, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), relief=None, pos=(0.26, 0, -0.28)) self.frameList.append(container) if valueLabel: self.doId2Frame[doId] = tuple((container, headframe, toon, nameLbl, someValueToBroadcast)) else: self.doId2Frame[doId] = tuple((container, headframe, toon, nameLbl)) return
def generateOtherPlayerGui(self): for avId in self.doId2Frame.keys(): self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId] = {} headNumber = -1 frame = self.doId2Frame[avId][0] otherPlayerHeadsFrame = DirectFrame(relief=None, scale=0.85, parent=frame) otherPlayerHeadsFrame['image'] = frame['image'] otherPlayerHeadsFrame['image_color'] = frame['image_color'] otherPlayerHeadsFrame['image_scale'] = self.otherPlayerHeadHolderTransforms['scale'] otherPlayerHeadsFrame.setPos(self.otherPlayerHeadHolderTransforms['pos']) otherPlayerHeadsFrame.setBin('gui-popup', 70) self.frameList.append(otherPlayerHeadsFrame) for otherAvId in self.doId2Frame.keys(): if otherAvId != avId: headNumber += 1 otherAv = base.cr.doId2do.get(otherAvId) gender = otherAv.getGender() head, color = otherAv.getHeadStyle() animal = otherAv.getAnimal() headFrame = otherPlayerHeadsFrame.attachNewNode('otherPlayerHeadFrame') headFrame.setPosHprScale(self.otherPlayerHeadXValues[headNumber], 5, -0.1, 180, 0, 0, 0.2, 0.2, 0.2) headFrame.setColorScale(self.state2Color[0]) toon = ToonHead(None) toon.generateHead(gender, animal, head) r, g, b, _ = color color = (r, g, b, 1.0) toon.setHeadColor(color) toon.setDepthWrite(1) toon.setDepthTest(1) toon.reparentTo(headFrame) self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId][otherAvId] = headFrame return
class GuiFrame(DirectObject, HasKeybinds): #should be able to show/hide, do conditional show hide #position where you want #parent to other frames TEXT_MAGIC_NUMBER = .833333333334 #5/6 ?!? DRAW_ORDER={ 'frame':('unsorted',0), 'frame_bg':('unsorted', 0), 'items':('unsorted', 0), 'title':('unsorted', 0), 'border':('unsorted', 0), } def __init__(self, title, shortcut = None, # XXX obsolete, but needs a non deco replacement x = 0, y = .1, width = .2, height = .8, #scale = .05, # there is some black magic here :/ bdr_thickness = 2, bdr_color = (.1, .1, .1, 1), bg_color = (.7, .7, .7, .5), text_color = (0, 0, 0, 1), text_font = TextNode.getDefaultFont(), #text_h = .05, # do not use directly text_height_mm = 4, items = tuple(), ): #item_w_pad = 1 #item_h_pad = 1 self.title = title self.do_xywh(x, y, width, height) self.bdr_thickness = bdr_thickness # FIXME ?? self.bdr_color = bdr_color self.bg_color = bg_color self.text_color = text_color self.text_font = text_font self.text_height_mm = text_height_mm #set up variables self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() self.__ar__ = base.camLens.getAspectRatio() self.__was_dragging__ = False self.__first_item__ = None self.__add_head__ = None self.items = OrderedDict() # ordered dict to allow sequential addition #self.BT = buttonThrower if buttonThrower else base.buttonThrowers[0].node() self.BT = base.buttonThrowers[0].node() # get our aspect ratio, and pixels per mm self.pixels_per_mm = render.getPythonTag('system_data')['max_ppmm'] self.getWindowData() self.accept('window-event', self.getWindowData) #set the text height using the above data self.setTextHeight() # get the root for all frames in the scene self.frameRoot = aspect2d.find('frameRoot') if not self.frameRoot: self.frameRoot = aspect2d.attachNewNode('frameRoot') # create the parent node for this frame #parent = self.frameRoot.find('frame-*') #if not parent: #parent = self.frameRoot self.frame = self.frameRoot.attachNewNode('frame-%s-%s'%(title, id(self))) self.frame.setBin(*self.DRAW_ORDER['frame']) # background l,r,b,t = 0, self.width, 0, self.height self.frame_bg = DirectFrame(parent=self.frame, frameColor=self.bg_color, pos=LVecBase3f(self.x, 0, self.y), frameSize=(l,r,b,t), state=DGG.NORMAL, # FIXME framesize is >_< suppressMouse=1) self.frame_bg.setBin(*self.DRAW_ORDER['frame_bg']) # border self.__make_border__(self.frame_bg, self.bdr_thickness, self.bdr_color, l, r, b, t) # setup for items self.itemsParent = self.frame_bg.attachNewNode('items parent') # title self.title_button = self.__create_item__(title, self.title_toggle_vis) # add any items that we got for item in items: self.__create_item__(*item) # FIXME when we call frame adjust we will loose the record of any data items # dragging self.title_button.bind(DGG.B1PRESS, self.__startDrag) self.title_button.bind(DGG.B1RELEASE, self.__stopDrag) # raise if we click the frame background self.frame_bg.bind(DGG.B1PRESS, self.raise_) #self.frame_bg.bind(DGG.B1RELEASE, self.__stopDrag) # this can cause problems w/ was dragging # toggle vis if shortcut: self.accept(shortcut, self.toggle_vis) # adjust the frame self.frame_adjust() @property def text_s(self): return self.text_h * self.TEXT_MAGIC_NUMBER def setTextHeight(self): h_units = 2 * base.a2dTop units_per_pixel = h_units / self.__winy__ text_h = self.text_height_mm * self.pixels_per_mm * units_per_pixel self.text_h = text_h def do_xywh(self, x, y, w, h): """ makes negative wneg xidths and heights work as well as negative x and y (bottom right is 0) """ if x < 0: x = 1 + x if y < 0: y = 1 + y if w < 0: x, w = x + w, -w if h < 0: y, h = y + h, -h self.x = self.fix_x(x) # for top left self.y = self.fix_y(y) # for top left self.width = self.fix_w(w) self.height = self.fix_h(h) def getWindowData(self, window=None): x = base.win.getXSize() y = base.win.getYSize() if x != self.__winx__ or y != self.__winy__: self.__ar__ = base.camLens.getAspectRatio() # w/h self.__winx__ = x self.__winy__ = y self.frame_adjust() def raise_(self, *args): """ function that raises windows call FIRST inside any function that should raise """ self.frame.reparentTo(self.frameRoot) # self.frame doesn't move so no wrt def frame_adjust(self): # FIXME sometimes this fails to call, also calls too often at startup self.setTextHeight() MI = self.getMaxItems() # does not count title >_< LI = len(self.items) DI = MI - LI if DI >= 0: for i in range(DI+1): self.__create_item__(' blank') else: for i in range(-(DI+1)): k,v = self.items.popitem() # remove the last nodes in order v.removeNode() # FIXME consider keeping these around? for k,b in self.items.items(): if k == 'title': if self.frame_bg.isHidden(): x, y, z = self.frame_bg.getPos() self.title_button.setPos(LVecBase3f(x, y , z-self.text_h)) else: self.title_button.setPos(LVecBase3f(0, 0, -self.text_h)) elif k == self.__first_item__: b.setPos(LVecBase3f(0, 0, -(self.text_h * 2))) else: b.setPos(LVecBase3f(0, 0, -self.text_h)) b['frameSize'] = 0, self.width, 0, self.text_h b['text_scale'] = self.text_s, self.text_s b['text_pos'] = 0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s def getWindowSize(self, event=None): # TODO see if we really need this self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() m = max(self.__winx__, self.__winy__) self.__xscale__ = self.__winx__ / m self.__yscale__ = self.__winy__ / m # put origin in top left and positive down and right @staticmethod def fix_x(x): return (x - .5) * 2 # TODO * base.a2dLeft? @staticmethod def fix_y(y): return (y - .5) * -2 # TODO * base.a2dTop? @staticmethod def fix_w(n): return n * 2 @staticmethod def fix_h(n): return -n * 2 def add_item(self, text, command = None, args = tuple()): args = list(args) if text[0] != ' ': text = ' '+text items = list(self.items) last_slot = len(self.items) if self.__add_head__ == last_slot: print('all slots are full, cannot add item to %s'%self) return None button = self.items[items[self.__add_head__]] button['text'] = text button['command'] = command button['extraArgs'] = args + button['extraArgs'] # blank buttons always have [self,id] self.__add_head__ += 1 def __create_item__(self, text, command = None, args = tuple()): args = list(args) #if not len(self.items): #parent = self.frame if len(self.items) <= 1: parent = self.itemsParent #everyone else parents off 2nd text else: parent = list(self.items.values())[-1] if command != None: def cmd(*args): """ any item should raise """ self.raise_() command(*args) else: cmd = self.raise_ b = DirectButton( parent=parent, frameColor=(1,1,1,.0), # a = 0 => no border overlap frameSize=(0, self.width, 0, self.text_h), text=' '+text, # hack to keep spacing from border text_font=self.text_font, text_fg=self.text_color, text_scale=self.text_s, text_pos=(0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s), command=cmd, relief=DGG.FLAT, text_align=TextNode.ALeft, ) b.setPos(LVecBase3f(0, 0, -self.text_h)) b.setName('DirectButton-'+text) if not len(self.items): self.items['title'] = b b.setBin(*self.DRAW_ORDER['title']) else: b['extraArgs'] = args+[self, id(b)] b.node().setPythonTag('id', id(b)) b.setBin(*self.DRAW_ORDER['items']) if len(self.items) is 1: # the first item that is not the title b.setPos(LVecBase3f(0, 0, -(self.text_h * 2))) self.__first_item__ = id(b) self.items[id(b)] = b if text == ' blank': if self.__add_head__ is None: self.__add_head__ = 1 return b def del_all(self): if self.__first_item__ != None: for id_, button in self.items.items(): if id_ != 'title': button['text'] = ' blank' button['command'] = None button['extraArgs'] = [self, id_] self.__add_head__ = 1 def del_item(self, text): # FIXME uniqueness problems #d = self.itemsParent.find('*%s*'%text) if text[0] != ' ': text = ' '+text d = [i for i in self.items.values() if i.getName().count(text)] try: self.__del_item__(d[0].getPythonTag('id')) except IndexError: print('that item does not seem to exist') # if we have a name then there shouldn't be key errors def __del_item__(self, index): """ I have no idea how this is going to work """ out = self.items[index] p = out.getParent() if out.getNumChildren(): # avoid the printing of the AssertionError :/ c = out.getChild(0) c.reparentTo(p) if index == self.__first_item__: # XXX is fails, ints from id != c.setPos(LVecBase3f(out.getPos())) id_ = c.getPythonTag('id') self.__first_item__ = id_ out.setPos(LVecBase3f(0, 0, -self.text_h)) self.items.pop(index) parent = list(self.items.values())[-1] out['text'] = ' del blank' #out['command'] = None out['extraArgs'] = [self, index] out.reparentTo(parent) self.items[index] = out if self.__add_head__ > 1: # title is always at 0 self.__add_head__ -= 1 @classmethod def __make_border__(cls, parent, thickness, color, l, r , b, t): moveto_drawto = ( ((l,0,t), (l,0,b)), ((r,0,t), (r,0,b)), ((l,0,b), (r,0,b)), ((l,0,t), (r,0,t)), ) for moveto, drawto in moveto_drawto: Border = LineSegs() Border.setThickness(thickness) Border.setColor(*color) Border.moveTo(*moveto) Border.drawTo(*drawto) b = parent.attachNewNode(Border.create()) b.setBin(*cls.DRAW_ORDER['border']) def getMaxItems(self): return int(abs(self.height / self.text_h) - 1) @event_callback def toggle_vis(self): if self.frame_bg.isHidden(): self.frame_bg.show() self.raise_() else: self.frame_bg.hide() def title_toggle_vis(self): if not self.__was_dragging__: self.toggle_vis() if self.frame_bg.isHidden(): self.title_button.wrtReparentTo(self.frame) self.title_button['frameColor'] = (1, 1, 1, .5) # TODO else: self.title_button.wrtReparentTo(self.frame_bg) self.title_button['frameColor'] = (1, 1, 1, 0) # TODO else: self.__was_dragging__ = False def __startDrag(self, crap): self.raise_() self._ox, self._oy = base.mouseWatcherNode.getMouse() taskMgr.add(self.__drag,'dragging %s'%self.title) self.origBTprefix=self.BT.getPrefix() self.BT.setPrefix('dragging frame') def __drag(self, task): if base.mouseWatcherNode.hasMouse(): x, y = base.mouseWatcherNode.getMouse() if x != self._ox or y != self._oy: m_old = aspect2d.getRelativePoint(render2d, Point3(self._ox, self._oy, 0)) m_new = aspect2d.getRelativePoint(render2d, Point3(x, y, 0)) dx, dy, _ = m_new - m_old self.setPos(self.x + dx, self.y + dy) self._ox = x self._oy = y self.__was_dragging__ = True return task.cont def __stopDrag(self,crap): taskMgr.remove('dragging %s'%self.title) self.BT.setPrefix(self.origBTprefix) def setPos(self, x, y): """ actually sets the title button position since it is really the parent node """ self.x = x self.y = y #- self.text_h # FIXME is hard :/ self.frame_bg.setPos(LVecBase3f(x, 0, y)) if self.frame_bg.isHidden(): self.title_button.setPos(LVecBase3f(x, 0, y - self.text_h)) def __enter__(self): #load the position #load other saved state pass def __exit__(self): #save the position! #save other state pass
class DropDownMenu(DirectObject): ALeft = 0 ACenter = 1 ARight = 2 ENone = 0 EFade = 1 ESlide = 2 EStretch = 3 PLeft = 0 PRight = 1 PBottom = 2 PTop = 3 parents = (('a2dBottomLeft', 'a2dLeftCenter', 'a2dTopLeft'), ('a2dTopRight', 'a2dRightCenter', 'a2dBottomRight'), ('a2dBottomLeft', 'a2dBottomCenter', 'a2dBottomRight'), ('a2dTopLeft', 'a2dTopCenter', 'a2dTopRight')) def __init__(self, items, parent=None, sidePad=.0, edgePos=PTop, align=ALeft, effect=ENone, buttonThrower=None, font=None, baselineOffset=.0, scale=.05, itemHeight=1., leftPad=.0, separatorHeight=.5, underscoreThickness=1, BGColor=(0, 0, 0, .7), BGBorderColor=(1, .85, .4, 1), separatorColor=(1, 1, 1, 1), frameColorHover=(1, .85, .4, 1), frameColorPress=(0, 1, 0, 1), textColorReady=(1, 1, 1, 1), textColorHover=(0, 0, 0, 1), textColorPress=(0, 0, 0, 1), textColorDisabled=(.5, .5, .5, 1), draggable=False, onMove=None): ''' sidePad : additional space on the left and right of the text item edgePos : menu bar position on the screen, use DropDownMenu.PLeft, PRight, PBottom, or PTop align : menu items alignment on menu bar, use DropDownMenu.ALeft, ACenter, or ARight effect : the drop down appearance effect, use DropDownMenu.ENone, EFade, ESlide, or EStretch draggable : menu bar's draggability status onMove : a function which will be called after changing edge position Read the remaining options documentation in PopupMenu class. ''' self.parent = parent if parent else getattr( base, DropDownMenu.parents[edgePos][align]) self.BT = buttonThrower if buttonThrower else base.buttonThrowers[ 0].node() self.menu = self.parent.attachNewNode('dropdownmenu-%s' % id(self)) self.font = font if font else TextNode.getDefaultFont() self.baselineOffset = baselineOffset self.scale = scale self.itemHeight = itemHeight self.sidePad = sidePad self.edgePos = edgePos self.alignment = align self.effect = effect self.leftPad = leftPad self.underscoreThickness = underscoreThickness self.separatorHeight = separatorHeight self.BGColor = BGColor self.BGBorderColor = BGBorderColor self.separatorColor = separatorColor self.frameColorHover = frameColorHover self.frameColorPress = frameColorPress self.textColorReady = textColorReady self.textColorHover = textColorHover self.textColorPress = textColorPress self.textColorDisabled = textColorDisabled self.draggable = draggable self.onMove = onMove self.dropDownMenu = self.whoseDropDownMenu = None self.gapFromEdge = gapFromEdge = .008 texMargin = self.font.getTextureMargin() * self.scale * .25 b = DirectButton(parent=NodePath(''), text='^|g_', text_font=self.font, scale=self.scale) fr = b.node().getFrame() b.getParent().removeNode() baselineToCenter = (fr[2] + fr[3]) * self.scale LH = (fr[3] - fr[2]) * self.itemHeight * self.scale baselineToTop = (fr[3] * self.itemHeight * self.scale / LH) / (1. + self.baselineOffset) baselineToBot = LH / self.scale - baselineToTop self.height = LH + .01 l, r, b, t = 0, 5, -self.height, 0 self.menuBG = DirectFrame(parent=self.menu, frameColor=BGColor, frameSize=(l, r, b, t), state=DGG.NORMAL, suppressMouse=1) if self.draggable: self.setDraggable(1) LSborder = LineSegs() LSborder.setThickness(2) LSborder.setColor(0, 0, 0, 1) LSborder.moveTo(l, 0, b) LSborder.drawTo(r, 0, b) self.menuBG.attachNewNode(LSborder.create()) self.itemsParent = self.menu.attachNewNode('menu items parent') x = sidePad * self.scale + gapFromEdge for t, menuItemsGenerator in items: underlinePos = t.find('_') t = t.replace('_', '') b = DirectButton( parent=self.itemsParent, text=t, text_font=self.font, pad=(sidePad, 0), scale=self.scale, pos=(x, 0, -baselineToTop * self.scale - gapFromEdge), text_fg=textColorReady, # text color when mouse over text2_fg=textColorHover, # text color when pressed text1_fg=textColorPress, # framecolor when pressed frameColor=frameColorPress, command=self.__createMenu, extraArgs=[True, menuItemsGenerator], text_align=TextNode.ALeft, relief=DGG.FLAT, rolloverSound=0, clickSound=0) b['extraArgs'] += [b.getName()] b.stateNodePath[2].setColor( *frameColorHover) # framecolor when mouse over b.stateNodePath[0].setColor(0, 0, 0, 0) # framecolor when ready fr = b.node().getFrame() b['frameSize'] = (fr[0], fr[1], -baselineToBot, baselineToTop) self.accept(DGG.ENTER + b.guiId, self.__createMenu, [False, menuItemsGenerator, b.getName()]) if underlinePos > -1: tn = TextNode('') tn.setFont(self.font) tn.setText(t[:underlinePos + 1]) tnp = NodePath(tn.getInternalGeom()) underlineXend = tnp.getTightBounds()[1][0] tnp.removeNode() tn.setText(t[underlinePos]) tnp = NodePath(tn.getInternalGeom()) b3 = tnp.getTightBounds() underlineXstart = underlineXend - (b3[1] - b3[0])[0] tnp.removeNode() LSunder = LineSegs() LSunder.setThickness(underscoreThickness) LSunder.moveTo(underlineXstart + texMargin, 0, -.7 * baselineToBot) LSunder.drawTo(underlineXend - texMargin, 0, -.7 * baselineToBot) underline = b.stateNodePath[0].attachNewNode(LSunder.create()) underline.setColor(Vec4(*textColorReady), 1) underline.copyTo(b.stateNodePath[1], 10).setColor(Vec4(*textColorPress), 1) underline.copyTo(b.stateNodePath[2], 10).setColor(Vec4(*textColorHover), 1) self.accept('alt-' + t[underlinePos].lower(), self.__createMenu, [True, menuItemsGenerator, b.getName()]) x += (fr[1] - fr[0]) * self.scale self.width = x - 2 * gapFromEdge self.align(align) self.setEdgePos(edgePos) self.minZ = base.a2dBottom + self.height if edgePos == DropDownMenu.PBottom else None viewPlaneNode = PlaneNode('cut menu') viewPlaneNode.setPlane(Plane(Vec3(0, 0, -1), Point3(0, 0, -LH))) self.clipPlane = self.menuBG.attachNewNode(viewPlaneNode) def __createMenu(self, clicked, menuItemsGenerator, DBname, crap=None): itself = self.dropDownMenu and self.whoseDropDownMenu == DBname if not (clicked or self.dropDownMenu) or (not clicked and itself): return self.__removeMenu() if clicked and itself: return # removes any context menu if clicked: self.__removePopupMenu() self.dropDownMenu = PopupMenu( items=menuItemsGenerator(), parent=self.parent, buttonThrower=self.BT, font=self.font, baselineOffset=self.baselineOffset, scale=self.scale, itemHeight=self.itemHeight, leftPad=self.leftPad, separatorHeight=self.separatorHeight, underscoreThickness=self.underscoreThickness, BGColor=self.BGColor, BGBorderColor=self.BGBorderColor, separatorColor=self.separatorColor, frameColorHover=self.frameColorHover, frameColorPress=self.frameColorPress, textColorReady=self.textColorReady, textColorHover=self.textColorHover, textColorPress=self.textColorPress, textColorDisabled=self.textColorDisabled, minZ=self.minZ) self.acceptOnce(self.dropDownMenu.BTprefix + 'destroyed', setattr, [self, 'dropDownMenu', None]) self.whoseDropDownMenu = DBname item = self.menu.find('**/%s' % DBname) fr = item.node().getFrame() #~ if self.edgePos==DropDownMenu.PLeft: #~ x=max(fr[1],self.dropDownMenu.menu.getX(item)) #~ z=fr[2] #~ elif self.edgePos==DropDownMenu.PRight: #~ x=min(fr[0],self.dropDownMenu.menu.getX(item)) #~ z=fr[2]-self.dropDownMenu.maxWidth #~ elif self.edgePos in (DropDownMenu.PBottom,DropDownMenu.PTop): #~ x=fr[1]-self.dropDownMenu.maxWidth if self.alignment==DropDownMenu.ARight else fr[0] #~ z=fr[2] if self.edgePos==DropDownMenu.PTop else fr[3]+self.dropDownMenu.height if self.edgePos == DropDownMenu.PLeft: x = max(fr[1], self.dropDownMenu.menu.getX(item)) z = fr[3] - (self.height - self.gapFromEdge) / self.scale elif self.edgePos == DropDownMenu.PRight: x = min(fr[0], self.dropDownMenu.menu.getX(item)) z = fr[3] - (self.height - self.gapFromEdge ) / self.scale - self.dropDownMenu.maxWidth elif self.edgePos in (DropDownMenu.PBottom, DropDownMenu.PTop): x = fr[ 1] - self.dropDownMenu.maxWidth if self.alignment == DropDownMenu.ARight else fr[ 0] z = fr[3] - ( self.height - self.gapFromEdge ) / self.scale if self.edgePos == DropDownMenu.PTop else fr[2] + ( self.height) / self.scale + self.dropDownMenu.height self.dropDownMenu.menu.setPos(item, x, 0, z) if self.effect == DropDownMenu.EFade: self.dropDownMenu.menu.colorScaleInterval( .3, Vec4(1), Vec4(1, 1, 1, 0), blendType='easeIn').start() elif self.effect == DropDownMenu.ESlide: pos = self.dropDownMenu.menu.getPos() if self.edgePos == DropDownMenu.PTop: startPos = Point3(0, 0, self.dropDownMenu.height * self.scale) elif self.edgePos == DropDownMenu.PBottom: startPos = Point3(0, 0, -self.dropDownMenu.height * self.scale) elif self.edgePos == DropDownMenu.PLeft: startPos = Point3(-self.dropDownMenu.maxWidth * self.scale, 0, 0) elif self.edgePos == DropDownMenu.PRight: startPos = Point3(self.dropDownMenu.maxWidth * self.scale, 0, 0) self.dropDownMenu.menu.posInterval(.3, pos, pos + startPos, blendType='easeIn').start() self.dropDownMenu.menu.setClipPlane(self.clipPlane) elif self.effect == DropDownMenu.EStretch: if self.edgePos == DropDownMenu.PTop: startHpr = Vec3(0, -90, 0) elif self.edgePos == DropDownMenu.PBottom: dz = self.dropDownMenu.height * self.scale for c in asList(self.dropDownMenu.menu.getChildren()): c.setZ(c.getZ() + dz) self.dropDownMenu.menu.setZ(self.dropDownMenu.menu, -dz) startHpr = Vec3(0, 90, 0) elif self.edgePos == DropDownMenu.PLeft: startHpr = Vec3(90, 0, 0) elif self.edgePos == DropDownMenu.PRight: dx = self.dropDownMenu.maxWidth * self.scale for c in asList(self.dropDownMenu.menu.getChildren()): c.setX(c.getX() - dx) self.dropDownMenu.menu.setX(self.dropDownMenu.menu, dx) startHpr = Vec3(-90, 0, 0) self.dropDownMenu.menu.hprInterval(.3, Vec3(0), startHpr, blendType='easeIn').start() def __removeMenu(self): if self.dropDownMenu: self.dropDownMenu.destroy() self.dropDownMenu = None def __removePopupMenu(self): menuEvents = messenger.find('menu-') if menuEvents: menuEvent = menuEvents.keys() activeMenu = menuEvents[menuEvent[0]].values()[0][0].im_self activeMenu.destroy(delParents=True) def __reverseItems(self): tmp = NodePath('') self.itemsParent.getChildren().reparentTo(tmp) children = asList(tmp.getChildren()) for c in reversed(children): c.reparentTo(self.itemsParent) tmp.removeNode() x = self.sidePad * self.scale + self.gapFromEdge for c in asList(self.itemsParent.getChildren()): c.setX(x) fr = c.node().getFrame() x += (fr[1] - fr[0]) * self.scale def __startDrag(self, crap): taskMgr.add(self.__drag, 'dragging menu bar', extraArgs=[Point2(base.mouseWatcherNode.getMouse())]) self.__removePopupMenu() self.origBTprefix = self.BT.getPrefix() self.BT.setPrefix('dragging menu bar') def __drag(self, origMpos): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() if mpos != origMpos: x, y = mpos.getX(), mpos.getY(), deltas = [x + 1, 1 - x, y + 1, 1 - y] closestEdge = deltas.index(min(deltas)) if closestEdge != self.edgePos: self.setEdgePos(closestEdge) return Task.cont def __stopDrag(self, crap): taskMgr.remove('dragging menu bar') self.BT.setPrefix(self.origBTprefix) def destroy(self): self.__removeMenu() self.ignoreAll() self.menu.removeNode() def isDraggable(self): ''' Returns menu bar's draggable status ''' return self.draggable def setDraggable(self, d): ''' Sets menu bar's draggable status ''' self.draggable = d if d: self.menuBG.bind(DGG.B1PRESS, self.__startDrag) self.menuBG.bind(DGG.B1RELEASE, self.__stopDrag) else: self.menuBG.unbind(DGG.B1PRESS) self.menuBG.unbind(DGG.B1RELEASE) def align(self, align=None): ''' Aligns menu text on menu bar. Use one of DropDownMenu.ALeft, DropDownMenu.ACenter, or DropDownMenu.ARight. ''' self.parent = getattr( base, DropDownMenu.parents[self.edgePos] [self.alignment if align is None else align]) self.menu.reparentTo(self.parent) if align is not None: self.itemsParent.setX(-.5 * self.width * align) self.menuBG.setX(-.5 * (5 - self.width) * align) self.alignment = align def setEdgePos(self, edge): ''' Sticks menu bar to 4 possible screen edges : DropDownMenu.PLeft, DropDownMenu.PRight, DropDownMenu.PBottom, or DropDownMenu.PTop. ''' lastEdge = self.edgePos reverseItems = lastEdge == DropDownMenu.PLeft self.edgePos = edge self.itemsParent.setZ(0) self.menuBG.setSz(1) alignment = None if self.edgePos == DropDownMenu.PLeft: self.menu.setR(-90) if self.alignment != DropDownMenu.ACenter: alignment = 2 - self.alignment self.__reverseItems() self.minZ = None else: if self.edgePos == DropDownMenu.PRight: self.menu.setR(90) self.minZ = None elif self.edgePos == DropDownMenu.PBottom: self.menu.setR(0) self.menuBG.setSz(-1) self.itemsParent.setZ(-self.menuBG.node().getFrame()[2]) self.minZ = base.a2dBottom + self.height elif self.edgePos == DropDownMenu.PTop: self.menu.setR(0) self.minZ = None if reverseItems: if self.alignment != DropDownMenu.ACenter: alignment = 2 - self.alignment self.__reverseItems() self.align(alignment) if callable(self.onMove): self.onMove()
class QuestMap(DirectFrame): def __init__(self, av, **kw): DirectFrame.__init__(self, relief=None, sortOrder=50) self.initialiseoptions(QuestMap) self.container = DirectFrame(parent=self, relief=None) self.marker = DirectFrame(parent=self.container, relief=None) self.cogInfoFrame = DirectFrame(parent=self.container, relief=None) cm = CardMaker('bg') cm.setFrame(-0.5, 0.5, -0.5, 0.5) bg = self.cogInfoFrame.attachNewNode(cm.generate()) bg.setTransparency(1) bg.setColor(0.5, 0.5, 0.5, 0.5) bg.setBin('fixed', 0) self.cogInfoFrame['geom'] = bg self.cogInfoFrame['geom_pos'] = (0, 0, 0) self.cogInfoFrame['geom_scale'] = (6, 1, 2) self.cogInfoFrame.setScale(0.05) self.cogInfoFrame.setPos(0, 0, 0.6) self.buildingMarkers = [] self.av = av self.wantToggle = False if base.config.GetBool('want-toggle-quest-map', True): self.wantToggle = True self.updateMarker = True self.cornerPosInfo = None self.hqPosInfo = None self.fishingSpotInfo = None self.load() self.setScale(1.5) bg.removeNode() self.hoodId = None self.zoneId = None self.suitPercentage = {} for currHoodInfo in SuitPlannerBase.SuitPlannerBase.SuitHoodInfo: tracks = currHoodInfo[SuitPlannerBase.SuitPlannerBase.SUIT_HOOD_INFO_TRACK] self.suitPercentage[currHoodInfo[SuitPlannerBase.SuitPlannerBase.SUIT_HOOD_INFO_ZONE]] = tracks return def load(self): gui = loader.loadModel('phase_4/models/questmap/questmap_gui') icon = gui.find('**/tt_t_gui_qst_arrow') iconNP = aspect2d.attachNewNode('iconNP') icon.reparentTo(iconNP) icon.setR(90) self.marker['geom'] = iconNP self.marker['image'] = iconNP self.marker.setScale(0.05) iconNP.removeNode() self.mapOpenButton = DirectButton(image=(gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapTryToOpen')), relief=None, pos=(-0.08, 0, 0.37), parent=base.a2dBottomRight, scale=0.205, command=self.show) self.mapCloseButton = DirectButton(image=(gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapTryToClose')), relief=None, pos=(-0.08, 0, 0.37), parent=base.a2dBottomRight, scale=0.205, command=self.hide) self.mapOpenButton.hide() self.mapCloseButton.hide() gui.removeNode() icons = loader.loadModel('phase_3/models/gui/cog_icons') cIcon = icons.find('**/CorpIcon') lIcon = icons.find('**/LegalIcon') mIcon = icons.find('**/MoneyIcon') sIcon = icons.find('**/SalesIcon') cogInfoTextColor = (0.2, 0.2, 0.2, 1) textPos = (1.2, -0.2) textScale = 0.8 self.cInfo = DirectLabel(parent=self.cogInfoFrame, text='', text_fg=cogInfoTextColor, text_pos=textPos, text_scale=textScale, geom=cIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None) self.cInfo.setPos(-2.2, 0, 0.5) self.lInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=lIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None) self.lInfo.setPos(-2.2, 0, -0.5) self.mInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=mIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None) self.mInfo.setPos(0.8, 0, 0.5) self.sInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=sIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None) self.sInfo.setPos(0.8, 0, -0.5) icons.removeNode() return def updateCogInfo(self): currPercentage = self.suitPercentage.get(self.zoneId) if currPercentage is None: return self.cInfo['text'] = '%s%%' % currPercentage[0] self.lInfo['text'] = '%s%%' % currPercentage[1] self.mInfo['text'] = '%s%%' % currPercentage[2] self.sInfo['text'] = '%s%%' % currPercentage[3] return def destroy(self): self.ignore('questPageUpdated') self.mapOpenButton.destroy() self.mapCloseButton.destroy() del self.mapOpenButton del self.mapCloseButton DirectFrame.destroy(self) def putBuildingMarker(self, pos, hpr = (0, 0, 0), mapIndex = None): marker = DirectLabel(parent=self.container, text='', text_pos=(-0.05, -0.15), text_fg=(1, 1, 1, 1), relief=None) gui = loader.loadModel('phase_4/models/parties/schtickerbookHostingGUI') icon = gui.find('**/startPartyButton_inactive') iconNP = aspect2d.attachNewNode('iconNP') icon.reparentTo(iconNP) icon.setX(-12.0792 / 30.48) icon.setZ(-9.7404 / 30.48) marker['text'] = '%s' % mapIndex marker['text_scale'] = 0.7 marker['image'] = iconNP marker['image_color'] = (1, 0, 0, 1) marker['image_scale'] = 6 marker.setScale(0.05) relX, relY = self.transformAvPos(pos) marker.setPos(relX, 0, relY) self.buildingMarkers.append(marker) iconNP.removeNode() gui.removeNode() return def updateQuestInfo(self): for marker in self.buildingMarkers: marker.destroy() self.buildingMarkers = [] for (i, questDesc) in enumerate(self.av.quests): mapIndex = i + 1 quest = Quests.getQuest(questDesc[0]) toNpcId = questDesc[2] completed = quest.getCompletionStatus(self.av, questDesc) == Quests.COMPLETE if not completed: if quest.getType() == Quests.RecoverItemQuest: if quest.getHolder() == Quests.AnyFish: self.putBuildingMarker(self.fishingSpotInfo, mapIndex=mapIndex) continue elif quest.getType() not in ( Quests.DeliverGagQuest, Quests.DeliverItemQuest, Quests.VisitQuest, Quests.TrackChoiceQuest): continue if toNpcId == Quests.ToonHQ: self.putBuildingMarker(self.hqPosInfo, mapIndex=mapIndex) continue npcZoneId = NPCToons.getNPCZone(toNpcId) hoodId = ZoneUtil.getCanonicalHoodId(npcZoneId) branchId = ZoneUtil.getCanonicalBranchZone(npcZoneId) if (self.hoodId != hoodId) or (self.zoneId != branchId): continue for blockIndex in xrange(base.cr.playGame.dnaStore.getNumBlockNumbers()): blockNumber = base.cr.playGame.dnaStore.getBlockNumberAt(blockIndex) zoneId = base.cr.playGame.dnaStore.getZoneFromBlockNumber(blockNumber) interiorZoneId = (zoneId - (zoneId%100)) + 500 + blockNumber if npcZoneId == interiorZoneId: self.putBuildingMarker( base.cr.playGame.dnaStore.getDoorPosHprFromBlockNumber(blockNumber).getPos(render), base.cr.playGame.dnaStore.getDoorPosHprFromBlockNumber(blockNumber).getHpr(render), mapIndex=mapIndex) def transformAvPos(self, pos): if self.cornerPosInfo is None: return (0, 0) topRight = self.cornerPosInfo[0] bottomLeft = self.cornerPosInfo[1] relativeX = (pos.getX() - bottomLeft.getX()) / (topRight.getX() - bottomLeft.getX()) - 0.5 relativeY = (pos.getY() - bottomLeft.getY()) / (topRight.getY() - bottomLeft.getY()) - 0.5 return (relativeX, relativeY) def update(self, task): if self.av: if self.updateMarker: relX, relY = self.transformAvPos(self.av.getPos()) self.marker.setPos(relX, 0, relY) self.marker.setHpr(0, 0, -180 - self.av.getH()) i = 0 for buildingMarker in self.buildingMarkers: buildingMarker.setScale((math.sin(task.time * 16.0 + i * math.pi / 3.0) + 1) * 0.005 + 0.04) i = i + 1 return Task.cont def updateMap(self): if self.av: hoodId = ZoneUtil.getCanonicalHoodId(self.av.getLocation()[1]) zoneId = ZoneUtil.getCanonicalBranchZone(self.av.getLocation()[1]) try: mapsGeom = loader.loadModel('phase_4/models/questmap/%s_maps' % ToontownGlobals.dnaMap[hoodId]) except: self.stop() return mapImage = mapsGeom.find('**/%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) if not mapImage.isEmpty(): self.container['image'] = mapImage self.resetFrameSize() self.cornerPosInfo = QuestMapGlobals.CornerPosTable.get('%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) self.hqPosInfo = QuestMapGlobals.HQPosTable.get('%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) self.fishingSpotInfo = QuestMapGlobals.FishingSpotPosTable.get('%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) self.cogInfoPos = QuestMapGlobals.CogInfoPosTable.get('%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) self.cogInfoFrame.setPos(self.cogInfoPos) self.hide() self.hoodId = hoodId self.zoneId = zoneId self.updateQuestInfo() self.updateCogInfo() taskMgr.add(self.update, 'questMapUpdate') else: self.stop() mapsGeom.removeNode() def start(self): self.container.show() self.accept('questPageUpdated', self.updateMap) self.handleMarker() self.updateMap() def initMarker(self, task): if self.av: if not hasattr(base.cr.playGame.getPlace(), 'isInterior') or not base.cr.playGame.getPlace().isInterior: relX, relY = self.transformAvPos(self.av.getPos()) self.marker.setPos(relX, 0, relY) self.marker.setHpr(0, 0, -180 - self.av.getH()) self.marker['geom_scale'] = 1.4 * task.time % 0.5 * 10 + 1 self.marker['geom_color'] = (1, 1, 1, 0.8 - 1.4 * task.time % 0.5 * 2 / 0.8 + 0.2) if task.time < 1: return Task.cont else: self.marker['geom_color'] = (1, 1, 1, 0) return Task.done def show(self): taskMgr.add(self.initMarker, 'questMapInit') DirectFrame.show(self) self.mapOpenButton.hide() if self.container['image']: self.mapCloseButton.show() def hide(self): taskMgr.remove('questMapInit') DirectFrame.hide(self) if self.container['image']: self.mapOpenButton.show() self.mapCloseButton.hide() def toggle(self): if self.isHidden(): self.show() else: self.hide() def obscureButton(self): self.mapOpenButton.hide() self.mapCloseButton.hide() def stop(self): self.container['image'] = None for marker in self.buildingMarkers: marker.destroy() self.buildingMarkers = [] self.container.hide() self.hide() self.obscureButton() self.ignore('questPageUpdated') taskMgr.remove('questMapUpdate') return def handleMarker(self): if hasattr(base.cr.playGame.getPlace(), 'isInterior') and base.cr.playGame.getPlace().isInterior: self.updateMarker = False else: self.updateMarker = True def acceptOnscreenHooks(self): if self.wantToggle: self.accept(ToontownGlobals.MapHotkey, self.toggle) else: self.accept(ToontownGlobals.MapHotkeyOn, self.show) self.accept(ToontownGlobals.MapHotkeyOff, self.hide) self.updateMap() def ignoreOnscreenHooks(self): self.ignore(ToontownGlobals.MapHotkey) self.ignore(ToontownGlobals.MapHotkeyOn) self.ignore(ToontownGlobals.MapHotkeyOff) self.obscureButton()
class RaceGUI: GagPie = 0 gagRoot = 'phase_3.5/maps/inventory_' class RacerInfo: def __init__(self, face, mapSpot): self.curvetime = 0 self.maxlaphit = 0 self.face = face self.mapspot = mapSpot self.place = 1 self.enabled = True self.finished = False self.gag = None return def update(self, curvetime=None, maxlaphit=None, faceX=None, mapspotPt=None, place=None, finished=None): if self.enabled: if not curvetime == None: self.curvetime = curvetime if not maxlaphit == None: self.maxlaphit = maxlaphit if not faceX == None: self.face.setX(faceX) if not mapspotPt == None: self.mapspot.setPos(mapspotPt) if not place == None: self.place = place if not finished == None: self.finished = finished return def disable(self): self.enabled = False if not self.finished: self.face.hide() self.mapspot.hide() def enable(self): self.enabled = True self.face.show() self.mapspot.show() def __init__(self, distRace): self.race = distRace self.timerEnabled = False self.maxLapHit = 0 self.photoFinish = False toonInteriorTextures = loader.loadModel( 'phase_3.5/models/modules/toon_interior_textures') invTextures = loader.loadModel('phase_3.5/models/gui/inventory_icons') racingTextures = loader.loadModel( 'phase_6/models/karting/racing_textures') self.gagTextures = [ toonInteriorTextures.find('**/couch'), invTextures.find('**/inventory_bannana_peel'), racingTextures.find('**/boost_arrow'), invTextures.find('**/inventory_anvil'), invTextures.find('**/inventory_creampie') ] self.gagTextures[1].setScale(7.5) self.gagTextures[3].setScale(7.5) self.gagTextures[4].setScale(7.5) self.cardMaker = CardMaker('card') self.racerDict = {} self.render2dRoot = render2d.attachNewNode('RaceGuiRender2dRoot') self.render2dRoot.setDepthWrite(1) self.directObjList = [] self.aspect2dRoot = aspect2d.attachNewNode('RaceGuiAspect2dRoot') self.aspect2dRoot.setDepthWrite(1) self.raceModeRoot = self.aspect2dRoot.attachNewNode('RaceModeRoot') gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=1.05, text=TTLocalizer.KartRace_Leave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(-0.99, 0, 0.925), command=self.race.leaveRace) self.closeButton.reparentTo(self.aspect2dRoot) self.directObjList.append(self.closeButton) self.raceTimeDelta = 0 self.raceModeReady = False self.resultModeReady = False self.gagCycleSound = base.loadSfx( 'phase_3.5/audio/sfx/tick_counter.mp3') if hasattr(self.gagCycleSound, 'setPlayRate'): self.gagCycleSound.setPlayRate(0.2) self.gagCycleSound.setLoop(1) self.gagAcquireSound = base.loadSfx( 'phase_6/audio/sfx/SZ_MM_gliss.mp3') self.disable() return def initRaceMode(self): self.mapScene = self.raceModeRoot.attachNewNode('MapScene') self.mapScene.setPos(1.1, 0, 0.75) self.mapScene.setScale(0.25, 0.001, 0.25) maxT = self.race.curve.getMaxT() pt = Vec3(0, 0, 0) ls = LineSegs('MapLines') ls.setColor(1, 1, 1, 1) ls.setThickness(2) for x in range(101): self.race.curve.getPoint(x / 100.0 * maxT, pt) if x == 0: ls.moveTo(pt[0], pt[1], pt[2]) else: ls.drawTo(pt[0], pt[1], pt[2]) self.mapLines = self.mapScene.attachNewNode(ls.create()) self.mapLines.setScale(0.00025 * RaceGlobals.TrackDict[self.race.trackId][6]) self.mapLines.setP(90) self.faceStartPos = Vec3(-0.8, 0, 0.93) self.faceEndPos = Vec3(0.8, 0, 0.93) self.placeLabelNum = DirectLabel( relief=None, pos=TTLocalizer.RGUIplaceLabelNumPos, text='1', text_scale=0.35, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.placeLabelNum.reparentTo(self.raceModeRoot) self.directObjList.append(self.placeLabelNum) self.placeLabelStr = DirectLabel( relief=None, pos=TTLocalizer.RGUIplaceLabelStrPos, text=TTLocalizer.KartRace_FirstSuffix, text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.placeLabelStr.reparentTo(self.raceModeRoot) self.directObjList.append(self.placeLabelStr) self.lapLabel = DirectLabel(relief=None, pos=(1.1, 0, 0.45), text='1/' + str(self.race.lapCount), text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.lapLabel.reparentTo(self.raceModeRoot) self.directObjList.append(self.lapLabel) self.photoFinishLabel = DirectLabel( relief=None, pos=(0, 0, -0.1), text=TTLocalizer.KartRace_PhotoFinish, text_scale=TTLocalizer.RGUIphotoFinish, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.photoFinishLabel.hide() self.directObjList.append(self.photoFinishLabel) self.wrongWayLabel = DirectLabel( relief=None, pos=(1.1, 0, 0.85), text=TTLocalizer.KartRace_WrongWay, text_scale=0.1, text_fg=(0.95, 0, 0, 1), text_font=ToontownGlobals.getSignFont()) self.wrongWayLabel.reparentTo(self.raceModeRoot) self.directObjList.append(self.wrongWayLabel) self.wrongWayLabel.setColorScale(Vec4(1, 1, 1, 0)) self.wrongWaySeq = Sequence( self.wrongWayLabel.colorScaleInterval(0.25, colorScale=Vec4(1, 1, 1, 1), startColorScale=Vec4( 1, 1, 1, 0)), self.wrongWayLabel.colorScaleInterval(0.25, colorScale=Vec4(1, 1, 1, 0), startColorScale=Vec4( 1, 1, 1, 1))) interpolateFacePos = lambda x: self.faceStartPos * ( 1.0 - x) + self.faceEndPos * x self.timeLabels = [] for x in range(self.race.lapCount): minLabel = DirectLabel( relief=None, pos=(interpolateFacePos( (2.0 * x + 1) / (self.race.lapCount * 2))[0] - 0.06, 0, 0.84), text="0'", text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight) minLabel.reparentTo(self.raceModeRoot) self.directObjList.append(minLabel) secLabel = DirectLabel( relief=None, pos=(interpolateFacePos( (2.0 * x + 1) / (self.race.lapCount * 2))[0] + 0.06, 0, 0.84), text="00''", text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight) secLabel.reparentTo(self.raceModeRoot) self.directObjList.append(secLabel) fractionLabel = DirectLabel( relief=None, pos=(interpolateFacePos( (2.0 * x + 1) / (self.race.lapCount * 2))[0] + 0.14, 0, 0.84), text='00', text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight) fractionLabel.reparentTo(self.raceModeRoot) self.directObjList.append(fractionLabel) self.timeLabels.append((minLabel, secLabel, fractionLabel)) self.cardMaker.reset() self.cardMaker.setName('GagIndicator') self.cardMaker.setFrame(-0.5, 0.5, -0.5, 0.5) self.cardMaker.setColor(1, 1, 1, 1) self.gagPanel = DirectFrame( parent=self.raceModeRoot, relief=None, image=loader.loadModel('phase_6/models/karting/gag_panel'), image_scale=0.25, pos=(-1.13, 0, -0.5)) self.directObjList.append(self.gagPanel) self.gag = self.gagPanel.attachNewNode('gag') self.gag.setScale(0.2) for gag in self.gagTextures: gag.reparentTo(self.gag) gag.hide() self.cardMaker.reset() self.cardMaker.setName('RaceProgressLine') self.cardMaker.setFrame(-0.5, 0.5, -0.5, 0.5) line = self.raceModeRoot.attachNewNode(self.cardMaker.generate()) line.setScale(self.faceEndPos[0] - self.faceStartPos[0], 1, 0.01) line.setPos(0, 0, self.faceStartPos[2]) self.cardMaker.setName('RaceProgressLineHash') for n in range(self.race.lapCount + 1): hash = self.raceModeRoot.attachNewNode(self.cardMaker.generate()) hash.setScale(line.getScale()[2], 1, line.getScale()[2] * 5) t = float(n) / self.race.lapCount hash.setPos( self.faceStartPos[0] * (1 - t) + self.faceEndPos[0] * t, self.faceStartPos[1], self.faceStartPos[2]) self.raceModeReady = True self.disable() return def initResultMode(self): self.endPanel = RaceEndPanel(len(self.race.avIds), self.race) self.endPanel.reparentTo(self.aspect2dRoot) self.directObjList.append(self.endPanel) self.resultModeReady = True self.disable() def showGag(self, gagIndex): if gagIndex < len(self.gagTextures): for gag in self.gagTextures: gag.hide() self.gagTextures[gagIndex].show() def updateGag(self, gagIndex): if self.gag: if hasattr(self, 'gagCycleInterval'): self.gagCycleInterval.finish() del self.gagCycleInterval self.gag.setHpr(0, 0, 0) self.showGag(gagIndex) if gagIndex == 0: self.gag.hide() else: self.gag.show() self.gagAcquireSound.play() self.gagAcquireInterval = LerpHprInterval(self.gag, duration=0.5, blendType='easeOut', startHpr=Point3( 0, -90, 0), hpr=Point3(0, 0, 0)) self.gagAcquireInterval.start() def waitingOnGag(self, cycleTime): if self.gag: numTextures = len(self.gagTextures) startOffset = random.choice(range(0, numTextures)) self.gag.show() self.gagCycleInterval = Parallel( LerpFunc(self.showNextGag, fromData=startOffset, toData=numTextures * 2 * cycleTime + startOffset, blendType='easeOut', duration=cycleTime), LerpHprInterval(self.gag, duration=cycleTime, hpr=Point3( 0, 180 * numTextures * 2 * cycleTime - 90, 0), blendType='easeOut', startHpr=Point3(0, 0, 0)), SoundInterval(self.gagCycleSound, loop=1, duration=cycleTime, startTime=0), name='gagCycleInterval') self.gagCycleInterval.start() def showNextGag(self, t): if self.gag: currGagIndex = int(t % (len(self.gagTextures) - 1)) + 1 self.showGag(currGagIndex) def enableSpeedometer(self): self.race.localKart.showSpeedometer() def disableSpeedometer(self): self.race.localKart.hideSpeedometer() def disableRaceMode(self): self.disableSpeedometer() self.render2dRoot.hide() self.raceModeRoot.hide() for x in self.timeLabels: for y in x: y.hide() self.setTimerEnabled(False) def disableResultMode(self): self.endPanel.disable() def disable(self): self.closeButton.hide() taskMgr.removeTasksMatching('clearRaceEndPanel') if self.raceModeReady: self.disableRaceMode() if self.resultModeReady: self.disableResultMode() def enableRaceMode(self): self.enableSpeedometer() self.render2dRoot.show() self.raceModeRoot.show() self.maxLapHit = min(self.maxLapHit, self.race.lapCount - 1) for x in range(self.maxLapHit + 1): for y in self.timeLabels[x]: y.configure(text_font=ToontownGlobals.getSignFont()) y.show() for y in self.timeLabels[self.maxLapHit]: y.configure(text_font=ToontownGlobals.getSignFont()) def enableResultMode(self): self.endPanel.enable() if not self.race.circuitLoop: taskMgr.doMethodLater(180, self.endPanel.closeButtonPressed, 'clearRaceEndPanel', extraArgs=[]) def destroy(self): self.disable() if hasattr(self, 'wrongWaySeq'): self.wrongWaySeq.finish() self.wrongWaySeq = None taskMgr.removeTasksMatching('removeIt') taskMgr.removeTasksMatching('removeCam*') taskMgr.removeTasksMatching('clearRaceEndPanel') for obj in self.directObjList: obj.destroy() if hasattr(self, 'mapScene'): self.mapScene.removeNode() self.mapScene = None self.aspect2dRoot.removeNode() self.aspect2dRoot = None self.raceModeRoot.removeNode() self.raceModeRoot = None self.render2dRoot.removeNode() self.render2dRoot = None self.closeButton = None self.gag = None self.lapLabel = None self.timeLabels = None self.placeLabelStr = None self.placeLabelNum = None self.photoFinishLabel = None self.mapScene = None self.race = None return def setSpotAsymptotic(self, diffT, spot): p = (-1, 1)[diffT > 0] * (1 - 1 / pow(abs(diffT) / self.cutoff + 1, 2)) spot.setX(p) def setSpotRaceLinear(self, t, spot): spot.setX(-1.0 + 2.0 * (t / self.lapCount)) def setSpotLapLinear(self, t, spot): spot.setX(-1.0 + 2.0 * (t - int(t))) def update(self, time): placeSorter = [] placeCount = 0 for key in self.racerDict.keys(): racer = self.racerDict[key] curvetime = racer.curvetime face = racer.face mapspot = racer.mapspot maxlaphit = racer.maxlaphit if not racer.finished and racer.enabled: placeSorter.append((curvetime, key)) if racer.finished or racer.enabled: placeCount += 1 pt = Vec3(0, 0, 0) mapT = (curvetime % 1 + self.race.startT / self.race.curve.getMaxT()) % 1 * self.race.curve.getMaxT() self.race.curve.getPoint(mapT, pt) self.race.curve.getPoint(mapT % self.race.curve.getMaxT(), pt) lapT = clampScalar(curvetime / self.race.lapCount, 0.0, 1.0) faceX = self.faceStartPos[0] * (1 - lapT) + self.faceEndPos[0] * lapT racer.update(faceX=faceX, mapspotPt=pt) t = time - self.race.baseTime - self.raceTimeDelta if key == localAvatar.doId: if self.race.laps > maxlaphit: racer.update(maxlaphit=self.race.laps) self.maxLapHit = racer.maxlaphit if self.maxLapHit < self.race.lapCount: for y in self.timeLabels[self.maxLapHit - 1]: y.configure( text_font=ToontownGlobals.getSignFont()) for y in self.timeLabels[self.maxLapHit]: y.show() for y in self.timeLabels[self.maxLapHit]: y.configure( text_font=ToontownGlobals.getSignFont()) self.raceTimeDelta = globalClock.getFrameTime( ) - self.race.baseTime lapNotice = DirectLabel() lapNotice.setScale(0.1) if self.maxLapHit == self.race.lapCount - 1: lapNotice[ 'text'] = TTLocalizer.KartRace_FinalLapText else: lapNotice[ 'text'] = TTLocalizer.KartRace_LapText % str( self.maxLapHit + 1) taskMgr.doMethodLater(2, lapNotice.remove, 'removeIt', extraArgs=[]) self.lapLabel['text'] = str( clampScalar(self.maxLapHit + 1, 1, self.race.lapCount)) + '/' + str( self.race.lapCount) suffix = { 1: TTLocalizer.KartRace_FirstSuffix, 2: TTLocalizer.KartRace_SecondSuffix, 3: TTLocalizer.KartRace_ThirdSuffix, 4: TTLocalizer.KartRace_FourthSuffix } placeSorter.sort() for x, p in zip(placeSorter, xrange(len(placeSorter), 0, -1)): self.racerDict[x[1]].update(place=p + placeCount - len(placeSorter)) localRacer = self.racerDict[localAvatar.doId] nearDiff, farDiff = RaceGlobals.TrackDict[self.race.trackId][8] if not localRacer.finished and self.faceEndPos[ 0] - localRacer.face.getX() < nearDiff: for racerId in self.racerDict.keys(): racer = self.racerDict[racerId] if not racer.enabled or racerId == localAvatar.doId or racer.face.getX( ) >= self.faceEndPos[0]: continue if self.faceEndPos[0] - racer.face.getX() < farDiff: self.photoFinish = True if self.photoFinish: self.photoFinishLabel.show() self.placeLabelNum['text'] = '' self.placeLabelStr['text'] = '' else: self.photoFinishLabel.hide() self.placeLabelNum['text'] = str( self.racerDict[localAvatar.doId].place) self.placeLabelStr['text'] = suffix[self.racerDict[ localAvatar.doId].place] minutes = int(t / 60) t -= minutes * 60 seconds = int(t) padding = (seconds < 10 and ['0'] or [''])[0] t -= seconds fraction = str(t)[2:4] fraction = fraction + '0' * (2 - len(fraction)) if self.timerEnabled and self.maxLapHit < self.race.lapCount: self.timeLabels[self.maxLapHit][0]['text'] = "%d'" % minutes self.timeLabels[self.maxLapHit][1]['text'] = "%s%d''" % (padding, seconds) self.timeLabels[self.maxLapHit][2]['text'] = '%s' % fraction if self.race.wrongWay and not self.wrongWaySeq.isPlaying(): self.wrongWaySeq.loop() elif not self.race.wrongWay and self.wrongWaySeq.isPlaying(): self.wrongWaySeq.finish() def updateRacerInfo(self, avId, curvetime=None, maxlaphit=None): if avId in self.racerDict.keys(): self.racerDict[avId].update(curvetime=curvetime, maxlaphit=maxlaphit) def racerEntered(self, avId): toon = base.cr.doId2do.get(avId, None) kart = base.cr.doId2do.get(self.race.kartMap.get(avId, None), None) if not toon or not kart: return if kart.getBodyColor() == InvalidEntry: bodyColor = getDefaultColor() else: bodyColor = getAccessory(kart.getBodyColor()) headframe = RaceHeadFrame(av=toon, color=bodyColor) eyes = headframe.head.find('**/eyes*') eyes.setDepthTest(1) eyes.setDepthWrite(1) headframe.configure(geom_scale=(0.5, 0.5, 0.5)) headframe.setZ(self.faceStartPos[2]) headframe.setDepthWrite(True) headframe.setDepthTest(True) headframe.reparentTo(self.raceModeRoot) self.directObjList.append(headframe) mapspot = loader.loadModel('phase_6/models/karting/race_mapspot') mapspot.setColor(bodyColor) mapspot.reparentTo(self.mapLines) mapspot.setHpr(self.mapScene, 0, 0, 0) self.racerDict[avId] = self.RacerInfo(headframe, mapspot) for key, i in zip(self.racerDict.keys(), range(len(self.racerDict.keys()))): face = self.racerDict[key].face mapspot = self.racerDict[key].mapspot face.setX(self.faceStartPos[0]) face.setY(-1 - 5 * (i + 1)) face.setScale(0.15) mapspot.getChild(0).setY((-5 - 5 * (i + 1)) * 1000) mapspot.setScale(self.mapScene, 0.15) mapspot.setPos(self.race.startingPos[0][0]) if key == localAvatar.doId: face.setY(-1) face.setScale(face.getScale() * 1.25) mapspot.getChild(0).setY(-5 * 1000) mapspot.setScale(mapspot.getScale() * 1.25) self.face = face self.mapspot = mapspot return def racerLeft(self, avId, unexpected=False): racer = self.racerDict.get(avId, None) if racer: racer.disable() return def racerFinished(self, avId, trackId, place, totalTime, entryFee, qualify, winnings, bonus, trophies, circuitPoints, circuitTime): racer = self.racerDict.get(avId, None) if racer: racer.update(finished=True) racer.disable() self.endPanel.displayRacer(place, entryFee, qualify, winnings, trackId, bonus, trophies, racer.face, base.cr.doId2do[avId].getName(), totalTime, circuitPoints, circuitTime) self.directObjList.remove(racer.face) if avId == localAvatar.doId: self.disableRaceMode() self.enableResultMode() self.endPanel.startWinningsPanel(entryFee, winnings, trackId, bonus, trophies) return def racerFinishedCircuit(self, avId, place, entryFee, winnings, bonus, trophies): racer = self.racerDict.get(avId, None) if racer: newTotalTickets = winnings + entryFee + bonus self.endPanel.updateWinnings(place, newTotalTickets) if avId == localAvatar.doId: self.endPanel.updateWinningsFromCircuit( place, entryFee, winnings, bonus, trophies) return def circuitFinished(self, placeFixup): self.endPanel.circuitFinished(placeFixup) def setTimerEnabled(self, enabled): self.timerEnabled = enabled
class DeathNotifications(DirectObject): MESSAGE_LIFE = 5 MAX_NUM_MESSAGES = 10 def __init__(self): self.textNodes = [] self.rootFrame = DirectFrame(pos = (-0.05, 0, -0.25), frameColor = (0, 0, 0, 0), frameSize = (0, 1, 0, 1), parent = base.a2dTopRight) self.rootFrame.setBin('fixed', GUIOrder.ORDER[GUIOrder.CHAT]) self.displayFrame = DirectFrame(pos = (0, 0, 0), frameColor = (0, 0, 0, 0), frameSize = (0, 1, 0, 0.42), parent = self.rootFrame) self.accept(PlayerDeathEvent.EventName, self.OnPlayerDeathEvent) def OnPlayerDeathEvent(self, event): player = event.GetPlayer() attacker = event.GetAttacker() wasHS = event.WasHeadshot() if(not attacker.currentItem): itemName = '???' else: itemName = attacker.currentItem.GetName() self.AddMessage(victimName = player.GetPlayerState().GetValue(PlayerState.NAME), attackerName = attacker.GetPlayerState().GetValue(PlayerState.NAME), itemName = itemName, attackerColor = Globals.TEAM_COLORS[attacker.GetPlayerState().GetValue(PlayerState.TEAM)], victimColor = Globals.TEAM_COLORS[player.GetPlayerState().GetValue(PlayerState.TEAM)]) def AddMessage(self, victimName, attackerName, itemName, attackerColor = Globals.COLOR_WHITE, victimColor = Globals.COLOR_WHITE): parent = self.displayFrame.attachNewNode('messageParent') attackerTextNode = TextNode('attackerTextNode') attackerTextNode.setText(attackerName) attackerTextNode.setTextColor(attackerColor) attackerTextNode.setShadow(0.05, 0.05) attackerTextNode.setShadowColor(Globals.COLOR_BLACK) attackerTextNodePath = parent.attachNewNode(attackerTextNode) attackerTextNodePath.setScale(Settings.CHAT_HEIGHT) attackerTextNodePath.setPos(Vec3(-attackerTextNode.calcWidth('%s [%s] %s' % (attackerName, itemName, victimName)) * Settings.CHAT_HEIGHT, 0, 0)) itemNameTextNode = TextNode('itemNameTextNode') itemNameTextNode.setText('[%s]' % (itemName)) itemNameTextNode.setTextColor(Globals.COLOR_WHITE) itemNameTextNode.setShadow(0.05, 0.05) itemNameTextNode.setShadowColor(Globals.COLOR_BLACK) itemNameTextNodePath = parent.attachNewNode(itemNameTextNode) itemNameTextNodePath.setScale(Settings.CHAT_HEIGHT) itemNameTextNodePath.setPos(Vec3(-attackerTextNode.calcWidth('[%s] %s' % (itemName, victimName)) * Settings.CHAT_HEIGHT, 0, 0)) victimTextNode = TextNode('prefixMessage') victimTextNode.setText(victimName) victimTextNode.setTextColor(victimColor) victimTextNode.setShadow(0.05, 0.05) victimTextNode.setShadowColor(Globals.COLOR_BLACK) victimTextNodePath = parent.attachNewNode(victimTextNode) victimTextNodePath.setScale(Settings.CHAT_HEIGHT) victimTextNodePath.setPos(Vec3(-attackerTextNode.calcWidth(victimName) * Settings.CHAT_HEIGHT, 0, 0)) taskMgr.remove('HideMessageLog') taskMgr.doMethodLater(DeathNotifications.MESSAGE_LIFE, self.RemoveMessage, 'RemoveMessage', extraArgs = [parent]) self.textNodes.append(parent) if(len(self.textNodes) > DeathNotifications.MAX_NUM_MESSAGES): self.RemoveMessage(self.textNodes[0]) self.RedrawMessages() def RedrawMessages(self): n = len(self.textNodes) for i, textNode in enumerate(self.textNodes): LerpPosInterval(textNode, 0.5, (0, 0, -(n-i) * (Settings.CHAT_HEIGHT + 0.01))).start() def RemoveMessage(self, textNode): if(textNode in self.textNodes): self.textNodes.remove(textNode) textNode.removeNode() def Destroy(self): taskMgr.remove('HideMessageLog') self.rootFrame.destroy() self.entryFrame.destroy() self.chatarea.destroy() self.typeText.destroy() self.displayFrame.destroy() self.ignoreAll()
class QuestMap(DirectFrame): def __init__(self, av, **kw): DirectFrame.__init__(self, relief=None, sortOrder=50) self.initialiseoptions(QuestMap) self.container = DirectFrame(parent=self, relief=None) self.marker = DirectFrame(parent=self.container, relief=None) self.cogInfoFrame = DirectFrame(parent=self.container, relief=None) cm = CardMaker('bg') cm.setFrame(-0.5, 0.5, -0.5, 0.5) bg = self.cogInfoFrame.attachNewNode(cm.generate()) bg.setTransparency(1) bg.setColor(0.5, 0.5, 0.5, 0.5) bg.setBin('fixed', 0) self.cogInfoFrame['geom'] = bg self.cogInfoFrame['geom_pos'] = (0, 0, 0) self.cogInfoFrame['geom_scale'] = (6, 1, 2) self.cogInfoFrame.setScale(0.05) self.cogInfoFrame.setPos(0, 0, 0.6) self.buildingMarkers = [] self.av = av self.wantToggle = False if base.config.GetBool('want-toggle-quest-map', True): self.wantToggle = True self.updateMarker = True self.cornerPosInfo = None self.hqPosInfo = None self.fishingSpotInfo = None self.load() self.setScale(1.5) bg.removeNode() self.hoodId = None self.zoneId = None self.suitPercentage = {} for currHoodInfo in SuitPlannerBase.SuitPlannerBase.SuitHoodInfo: tracks = currHoodInfo[ SuitPlannerBase.SuitPlannerBase.SUIT_HOOD_INFO_TRACK] self.suitPercentage[currHoodInfo[ SuitPlannerBase.SuitPlannerBase.SUIT_HOOD_INFO_ZONE]] = tracks return def load(self): gui = loader.loadModel('phase_4/models/questmap/questmap_gui') icon = gui.find('**/tt_t_gui_qst_arrow') iconNP = aspect2d.attachNewNode('iconNP') icon.reparentTo(iconNP) icon.setR(90) self.marker['geom'] = iconNP self.marker['image'] = iconNP self.marker.setScale(0.05) iconNP.removeNode() self.mapOpenButton = DirectButton( image=(gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapTryToOpen')), relief=None, pos=(-0.084, 0, 0.37), parent=base.a2dBottomRight, scale=0.205, command=self.show) self.mapCloseButton = DirectButton( image=(gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapTryToClose')), relief=None, pos=(-0.084, 0, 0.37), parent=base.a2dBottomRight, scale=0.205, command=self.hide) self.mapOpenButton.hide() self.mapCloseButton.hide() gui.removeNode() icons = loader.loadModel('phase_3/models/gui/cog_icons') cIcon = icons.find('**/CorpIcon') lIcon = icons.find('**/LegalIcon') mIcon = icons.find('**/MoneyIcon') sIcon = icons.find('**/SalesIcon') cogInfoTextColor = (0.2, 0.2, 0.2, 1) textPos = (1.2, -0.2) textScale = 0.8 self.cInfo = DirectLabel(parent=self.cogInfoFrame, text='', text_fg=cogInfoTextColor, text_pos=textPos, text_scale=textScale, geom=cIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None) self.cInfo.setPos(-2.2, 0, 0.5) self.lInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=lIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None) self.lInfo.setPos(-2.2, 0, -0.5) self.mInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=mIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None) self.mInfo.setPos(0.8, 0, 0.5) self.sInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=sIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None) self.sInfo.setPos(0.8, 0, -0.5) icons.removeNode() return def updateCogInfo(self): currPercentage = self.suitPercentage.get(self.zoneId) if currPercentage is None: return self.cInfo['text'] = '%s%%' % currPercentage[0] self.lInfo['text'] = '%s%%' % currPercentage[1] self.mInfo['text'] = '%s%%' % currPercentage[2] self.sInfo['text'] = '%s%%' % currPercentage[3] return def destroy(self): self.ignore('questPageUpdated') self.mapOpenButton.destroy() self.mapCloseButton.destroy() del self.mapOpenButton del self.mapCloseButton DirectFrame.destroy(self) def putBuildingMarker(self, pos, hpr=(0, 0, 0), mapIndex=None): marker = DirectLabel(parent=self.container, text='', text_pos=(-0.05, -0.15), text_fg=(1, 1, 1, 1), relief=None) gui = loader.loadModel( 'phase_4/models/parties/schtickerbookHostingGUI') icon = gui.find('**/startPartyButton_inactive') iconNP = aspect2d.attachNewNode('iconNP') icon.reparentTo(iconNP) icon.setX(-12.0792 / 30.48) icon.setZ(-9.7404 / 30.48) marker['text'] = '%s' % mapIndex marker['text_scale'] = 0.7 marker['image'] = iconNP marker['image_color'] = (1, 0, 0, 1) marker['image_scale'] = 6 marker.setScale(0.05) relX, relY = self.transformAvPos(pos) marker.setPos(relX, 0, relY) self.buildingMarkers.append(marker) iconNP.removeNode() gui.removeNode() return def updateQuestInfo(self): for marker in self.buildingMarkers: marker.destroy() self.buildingMarkers = [] dnaStore = base.cr.playGame.dnaStore for questIndex in self.av.questPage.quests.keys(): questDesc = self.av.questPage.quests.get(questIndex) if questDesc is None: continue mapIndex = questIndex + 1 questId, fromNpcId, toNpcId, rewardId, toonProgress = questDesc quest = Quests.getQuest(questId) fComplete = quest.getCompletionStatus(self.av, questDesc) == Quests.COMPLETE if not fComplete: if quest.getType() == Quests.RecoverItemQuest: if quest.getHolder() == Quests.AnyFish: self.putBuildingMarker(self.fishingSpotInfo, mapIndex=mapIndex) continue elif quest.getType( ) != Quests.DeliverGagQuest and quest.getType( ) != Quests.DeliverItemQuest and quest.getType( ) != Quests.VisitQuest and quest.getType( ) != Quests.TrackChoiceQuest: continue if toNpcId == Quests.ToonHQ: self.putBuildingMarker(self.hqPosInfo, mapIndex=mapIndex) else: npcZone = NPCToons.getNPCZone(toNpcId) hoodId = ZoneUtil.getCanonicalHoodId(npcZone) branchId = ZoneUtil.getCanonicalBranchZone(npcZone) if self.hoodId == hoodId and self.zoneId == branchId: for blockIndex in xrange(dnaStore.getNumBlockTitles()): blockNumber = dnaStore.getTitleBlockAt(blockIndex) zone = dnaStore.getZoneFromBlockNumber(blockNumber) branchZone = zone - zone % 100 finalZone = branchZone + 500 + blockNumber buildingType = dnaStore.getBlockBuildingType( blockNumber) if npcZone == finalZone: self.putBuildingMarker( dnaStore.getDoorPosHprFromBlockNumber( blockNumber).getPos(), dnaStore.getDoorPosHprFromBlockNumber( blockNumber).getHpr(), mapIndex=mapIndex) return def transformAvPos(self, pos): if self.cornerPosInfo is None: return (0, 0) topRight = self.cornerPosInfo[0] bottomLeft = self.cornerPosInfo[1] relativeX = (pos.getX() - bottomLeft.getX()) / ( topRight.getX() - bottomLeft.getX()) - 0.5 relativeY = (pos.getY() - bottomLeft.getY()) / ( topRight.getY() - bottomLeft.getY()) - 0.5 return (relativeX, relativeY) def update(self, task): if self.av: if self.updateMarker: relX, relY = self.transformAvPos(self.av.getPos()) self.marker.setPos(relX, 0, relY) self.marker.setHpr(0, 0, -180 - self.av.getH()) i = 0 for buildingMarker in self.buildingMarkers: buildingMarker.setScale( (math.sin(task.time * 16.0 + i * math.pi / 3.0) + 1) * 0.005 + 0.04) i = i + 1 return Task.cont def updateMap(self): if self.av: try: hoodId = ZoneUtil.getCanonicalHoodId(self.av.getLocation()[1]) zoneId = ZoneUtil.getCanonicalBranchZone( self.av.getLocation()[1]) mapsGeom = loader.loadModel('phase_4/models/questmap/%s_maps' % ToontownGlobals.dnaMap[hoodId]) mapImage = mapsGeom.find( '**/%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) if not mapImage.isEmpty(): self.container['image'] = mapImage self.resetFrameSize() self.cornerPosInfo = QuestMapGlobals.CornerPosTable.get( '%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) self.hqPosInfo = QuestMapGlobals.HQPosTable.get( '%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) self.fishingSpotInfo = QuestMapGlobals.FishingSpotPosTable.get( '%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) self.cogInfoPos = QuestMapGlobals.CogInfoPosTable.get( '%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId)) self.cogInfoFrame.setPos(self.cogInfoPos) self.hide() self.hoodId = hoodId self.zoneId = zoneId self.updateQuestInfo() self.updateCogInfo() taskMgr.add(self.update, 'questMapUpdate') else: self.stop() mapsGeom.removeNode() except: self.stop() def start(self): self.container.show() self.accept('questPageUpdated', self.updateMap) self.handleMarker() self.updateMap() def initMarker(self, task): if self.av: if not hasattr(base.cr.playGame.getPlace(), 'isInterior' ) or not base.cr.playGame.getPlace().isInterior: relX, relY = self.transformAvPos(self.av.getPos()) self.marker.setPos(relX, 0, relY) self.marker.setHpr(0, 0, -180 - self.av.getH()) self.marker['geom_scale'] = 1.4 * task.time % 0.5 * 10 + 1 self.marker['geom_color'] = (1, 1, 1, 0.8 - 1.4 * task.time % 0.5 * 2 / 0.8 + 0.2) if task.time < 1: return Task.cont else: self.marker['geom_color'] = (1, 1, 1, 0) return Task.done def show(self): taskMgr.add(self.initMarker, 'questMapInit') DirectFrame.show(self) self.mapOpenButton.hide() if self.container['image']: self.mapCloseButton.show() def hide(self): taskMgr.remove('questMapInit') DirectFrame.hide(self) if self.container['image']: self.mapOpenButton.show() self.mapCloseButton.hide() def toggle(self): if self.isHidden(): self.show() else: self.hide() def obscureButton(self): self.mapOpenButton.hide() self.mapCloseButton.hide() def stop(self): self.container['image'] = None for marker in self.buildingMarkers: marker.destroy() self.buildingMarkers = [] self.container.hide() self.hide() self.obscureButton() self.ignore('questPageUpdated') taskMgr.remove('questMapUpdate') return def handleMarker(self): if hasattr(base.cr.playGame.getPlace(), 'isInterior') and base.cr.playGame.getPlace().isInterior: self.updateMarker = False else: self.updateMarker = True def acceptOnscreenHooks(self): if self.wantToggle: self.accept(ToontownGlobals.MapHotkey, self.toggle) else: self.accept(ToontownGlobals.MapHotkeyOn, self.show) self.accept(ToontownGlobals.MapHotkeyOff, self.hide) self.updateMap() def ignoreOnscreenHooks(self): self.ignore(ToontownGlobals.MapHotkey) self.ignore(ToontownGlobals.MapHotkeyOn) self.ignore(ToontownGlobals.MapHotkeyOff) self.obscureButton()
class ChatBox(DirectObject): MESSAGE_LIFE = 10 MAX_NUM_MESSAGES = 15 (TYPE_GLOBAL, TYPE_TEAM, TYPE_CONSOLE) = range(3) messageTypeToPrefix = { TYPE_GLOBAL : 'Global:', TYPE_TEAM : 'Team:', TYPE_CONSOLE : 'Console' } def __init__(self): self.textNodes = [] self.messageType = None self.rootFrame = DirectFrame(pos = (0.03, 0, 0.2), frameColor = (0, 0, 0, 0), frameSize = (0, 1, 0, 1), parent = base.a2dBottomLeft) self.rootFrame.setBin('fixed', GUIOrder.ORDER[GUIOrder.CHAT]) self.entryFrame = DirectFrame(pos = (0, 0, 0), frameColor = (0, 0, 0, 0.1), frameSize = (0, 1, 0, 0.1), parent = self.rootFrame) self.chatarea = DirectEntry(width = 27, scale = Settings.CHAT_HEIGHT, pos = (0, 0, 0), frameColor = (0, 0, 0, 0), text_fg = (1, 1, 1, 1), numLines = 1, cursorKeys = 1, rolloverSound = None, clickSound = None, focus = 0, command = self.OnChatEntered, parent = self.entryFrame) self.typeText = OnscreenText(text = '', pos = (0, Settings.CHAT_HEIGHT + 0.01), scale = Settings.CHAT_HEIGHT, fg = (1, 1, 1, 1), mayChange = True, align = TextNode.ALeft, parent = self.entryFrame) self.displayFrame = DirectFrame(pos = (0, 0, 0.1), frameColor = (0, 0, 0, 0), frameSize = (0, 1, 0, 0.42), parent = self.rootFrame) self.chatarea.enterText('') self.entryFrame.hide() self.chatarea['focus'] = 0 self.chatarea.setFocus() def OnChatEntered(self, enteredText): enteredText = enteredText.strip() self.Hide() if(len(enteredText) > 0): ChatEnteredEvent(self.messageType, enteredText).Fire() def AddMessage(self, prefix, prefixColor, message): parent = self.displayFrame.attachNewNode('messageParent') prefixTextNode = TextNode('prefixMessage') prefixTextNode.setText(prefix) prefixTextNode.setTextColor(prefixColor) prefixTextNode.setShadow(0.05, 0.05) prefixTextNode.setShadowColor(Globals.COLOR_BLACK) prefixTextNodePath = parent.attachNewNode(prefixTextNode) prefixTextNodePath.setScale(Settings.CHAT_HEIGHT) messageTextNode = TextNode('prefixMessage') messageTextNode.setText(message) messageTextNode.setTextColor(1, 1, 1, 1) messageTextNode.setShadow(0.05, 0.05) messageTextNode.setShadowColor(Globals.COLOR_BLACK) messageTextNodePath = parent.attachNewNode(messageTextNode) messageTextNodePath.setScale(Settings.CHAT_HEIGHT) messageTextNodePath.setPos(Vec3(prefixTextNode.calcWidth(prefix) * Settings.CHAT_HEIGHT, 0, 0)) taskMgr.remove('HideMessageLog') taskMgr.doMethodLater(ChatBox.MESSAGE_LIFE, self.HideMessageLog, 'HideMessageLog') self.ShowMessageLog() self.textNodes.append(parent) if(len(self.textNodes) > ChatBox.MAX_NUM_MESSAGES): self.RemoveMessage(self.textNodes[0]) self.RedrawMessages() def RedrawMessages(self): n = len(self.textNodes) for i, textNode in enumerate(self.textNodes): LerpPosInterval(textNode, 0.5, (0, 0, (n-i) * (Settings.CHAT_HEIGHT + 0.01))).start() def RemoveMessage(self, textNode): self.textNodes.remove(textNode) textNode.removeNode() def HideMessageLog(self, task = None): self.displayFrame.hide() def ShowMessageLog(self): self.displayFrame.show() def Hide(self): self.chatarea.enterText('') self.entryFrame.hide() self.chatarea['focus'] = 0 self.chatarea.setFocus() self.HideMessageLog() ChatCloseEvent().Fire() def Show(self, messageType): self.messageType = messageType self.entryFrame.show() self.chatarea['focus'] = 1 self.chatarea.setFocus() self.typeText.setText(ChatBox.GetPrefix(self.messageType)) self.ShowMessageLog() ChatOpenEvent().Fire() def EnableKeyboardListening(self): self.acceptOnce('escape', self.Hide) def DisableKeyboardListening(self): self.ignoreAll() @staticmethod def GetPrefix(messageType): return ChatBox.messageTypeToPrefix[messageType] def Destroy(self): taskMgr.remove('HideMessageLog') self.rootFrame.destroy() self.entryFrame.destroy() self.chatarea.destroy() self.typeText.destroy() self.displayFrame.destroy() self.ignoreAll()
class GuiFrame(DirectObject, HasKeybinds): #should be able to show/hide, do conditional show hide #position where you want #parent to other frames TEXT_MAGIC_NUMBER = .833333333334 #5/6 ?!? DRAW_ORDER = { 'frame': ('unsorted', 0), 'frame_bg': ('unsorted', 0), 'items': ('unsorted', 0), 'title': ('unsorted', 0), 'border': ('unsorted', 0), } def __init__( self, title, shortcut=None, # XXX obsolete, but needs a non deco replacement x=0, y=.1, width=.2, height=.8, #scale = .05, # there is some black magic here :/ bdr_thickness=2, bdr_color=(.1, .1, .1, 1), bg_color=(.7, .7, .7, .5), text_color=(0, 0, 0, 1), text_font=TextNode.getDefaultFont(), #text_h = .05, # do not use directly text_height_mm=4, items=tuple(), ): #item_w_pad = 1 #item_h_pad = 1 self.title = title self.do_xywh(x, y, width, height) self.bdr_thickness = bdr_thickness # FIXME ?? self.bdr_color = bdr_color self.bg_color = bg_color self.text_color = text_color self.text_font = text_font self.text_height_mm = text_height_mm #set up variables self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() self.__ar__ = base.camLens.getAspectRatio() self.__was_dragging__ = False self.__first_item__ = None self.__add_head__ = None self.items = OrderedDict() # ordered dict to allow sequential addition #self.BT = buttonThrower if buttonThrower else base.buttonThrowers[0].node() self.BT = base.buttonThrowers[0].node() # get our aspect ratio, and pixels per mm self.pixels_per_mm = render.getPythonTag('system_data')['max_ppmm'] self.getWindowData() self.accept('window-event', self.getWindowData) #set the text height using the above data self.setTextHeight() # get the root for all frames in the scene self.frameRoot = aspect2d.find('frameRoot') if not self.frameRoot: self.frameRoot = aspect2d.attachNewNode('frameRoot') # create the parent node for this frame #parent = self.frameRoot.find('frame-*') #if not parent: #parent = self.frameRoot self.frame = self.frameRoot.attachNewNode('frame-%s-%s' % (title, id(self))) self.frame.setBin(*self.DRAW_ORDER['frame']) # background l, r, b, t = 0, self.width, 0, self.height self.frame_bg = DirectFrame( parent=self.frame, frameColor=self.bg_color, pos=LVecBase3f(self.x, 0, self.y), frameSize=(l, r, b, t), state=DGG.NORMAL, # FIXME framesize is >_< suppressMouse=1) self.frame_bg.setBin(*self.DRAW_ORDER['frame_bg']) # border self.__make_border__(self.frame_bg, self.bdr_thickness, self.bdr_color, l, r, b, t) # setup for items self.itemsParent = self.frame_bg.attachNewNode('items parent') # title self.title_button = self.__create_item__(title, self.title_toggle_vis) # add any items that we got for item in items: self.__create_item__( *item ) # FIXME when we call frame adjust we will loose the record of any data items # dragging self.title_button.bind(DGG.B1PRESS, self.__startDrag) self.title_button.bind(DGG.B1RELEASE, self.__stopDrag) # raise if we click the frame background self.frame_bg.bind(DGG.B1PRESS, self.raise_) #self.frame_bg.bind(DGG.B1RELEASE, self.__stopDrag) # this can cause problems w/ was dragging # toggle vis if shortcut: self.accept(shortcut, self.toggle_vis) # adjust the frame self.frame_adjust() @property def text_s(self): return self.text_h * self.TEXT_MAGIC_NUMBER def setTextHeight(self): h_units = 2 * base.a2dTop units_per_pixel = h_units / self.__winy__ text_h = self.text_height_mm * self.pixels_per_mm * units_per_pixel self.text_h = text_h def do_xywh(self, x, y, w, h): """ makes negative wneg xidths and heights work as well as negative x and y (bottom right is 0) """ if x < 0: x = 1 + x if y < 0: y = 1 + y if w < 0: x, w = x + w, -w if h < 0: y, h = y + h, -h self.x = self.fix_x(x) # for top left self.y = self.fix_y(y) # for top left self.width = self.fix_w(w) self.height = self.fix_h(h) def getWindowData(self, window=None): x = base.win.getXSize() y = base.win.getYSize() if x != self.__winx__ or y != self.__winy__: self.__ar__ = base.camLens.getAspectRatio() # w/h self.__winx__ = x self.__winy__ = y self.frame_adjust() def raise_(self, *args): """ function that raises windows call FIRST inside any function that should raise """ self.frame.reparentTo( self.frameRoot) # self.frame doesn't move so no wrt def frame_adjust( self ): # FIXME sometimes this fails to call, also calls too often at startup self.setTextHeight() MI = self.getMaxItems() # does not count title >_< LI = len(self.items) DI = MI - LI if DI >= 0: for i in range(DI + 1): self.__create_item__(' blank') else: for i in range(-(DI + 1)): k, v = self.items.popitem() # remove the last nodes in order v.removeNode() # FIXME consider keeping these around? for k, b in self.items.items(): if k == 'title': if self.frame_bg.isHidden(): x, y, z = self.frame_bg.getPos() self.title_button.setPos(LVecBase3f(x, y, z - self.text_h)) else: self.title_button.setPos(LVecBase3f(0, 0, -self.text_h)) elif k == self.__first_item__: b.setPos(LVecBase3f(0, 0, -(self.text_h * 2))) else: b.setPos(LVecBase3f(0, 0, -self.text_h)) b['frameSize'] = 0, self.width, 0, self.text_h b['text_scale'] = self.text_s, self.text_s b['text_pos'] = 0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s def getWindowSize(self, event=None): # TODO see if we really need this self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() m = max(self.__winx__, self.__winy__) self.__xscale__ = self.__winx__ / m self.__yscale__ = self.__winy__ / m # put origin in top left and positive down and right @staticmethod def fix_x(x): return (x - .5) * 2 # TODO * base.a2dLeft? @staticmethod def fix_y(y): return (y - .5) * -2 # TODO * base.a2dTop? @staticmethod def fix_w(n): return n * 2 @staticmethod def fix_h(n): return -n * 2 def add_item(self, text, command=None, args=tuple()): args = list(args) if text[0] != ' ': text = ' ' + text items = list(self.items) last_slot = len(self.items) if self.__add_head__ == last_slot: print('all slots are full, cannot add item to %s' % self) return None button = self.items[items[self.__add_head__]] button['text'] = text button['command'] = command button['extraArgs'] = args + button[ 'extraArgs'] # blank buttons always have [self,id] self.__add_head__ += 1 def __create_item__(self, text, command=None, args=tuple()): args = list(args) #if not len(self.items): #parent = self.frame if len(self.items) <= 1: parent = self.itemsParent #everyone else parents off 2nd text else: parent = list(self.items.values())[-1] if command != None: def cmd(*args): """ any item should raise """ self.raise_() command(*args) else: cmd = self.raise_ b = DirectButton( parent=parent, frameColor=(1, 1, 1, .0), # a = 0 => no border overlap frameSize=(0, self.width, 0, self.text_h), text=' ' + text, # hack to keep spacing from border text_font=self.text_font, text_fg=self.text_color, text_scale=self.text_s, text_pos=(0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s), command=cmd, relief=DGG.FLAT, text_align=TextNode.ALeft, ) b.setPos(LVecBase3f(0, 0, -self.text_h)) b.setName('DirectButton-' + text) if not len(self.items): self.items['title'] = b b.setBin(*self.DRAW_ORDER['title']) else: b['extraArgs'] = args + [self, id(b)] b.node().setPythonTag('id', id(b)) b.setBin(*self.DRAW_ORDER['items']) if len(self.items) is 1: # the first item that is not the title b.setPos(LVecBase3f(0, 0, -(self.text_h * 2))) self.__first_item__ = id(b) self.items[id(b)] = b if text == ' blank': if self.__add_head__ is None: self.__add_head__ = 1 return b def del_all(self): if self.__first_item__ != None: for id_, button in self.items.items(): if id_ != 'title': button['text'] = ' blank' button['command'] = None button['extraArgs'] = [self, id_] self.__add_head__ = 1 def del_item(self, text): # FIXME uniqueness problems #d = self.itemsParent.find('*%s*'%text) if text[0] != ' ': text = ' ' + text d = [i for i in self.items.values() if i.getName().count(text)] try: self.__del_item__(d[0].getPythonTag('id')) except IndexError: print('that item does not seem to exist') # if we have a name then there shouldn't be key errors def __del_item__(self, index): """ I have no idea how this is going to work """ out = self.items[index] p = out.getParent() if out.getNumChildren(): # avoid the printing of the AssertionError :/ c = out.getChild(0) c.reparentTo(p) if index == self.__first_item__: # XXX is fails, ints from id != c.setPos(LVecBase3f(out.getPos())) id_ = c.getPythonTag('id') self.__first_item__ = id_ out.setPos(LVecBase3f(0, 0, -self.text_h)) self.items.pop(index) parent = list(self.items.values())[-1] out['text'] = ' del blank' #out['command'] = None out['extraArgs'] = [self, index] out.reparentTo(parent) self.items[index] = out if self.__add_head__ > 1: # title is always at 0 self.__add_head__ -= 1 @classmethod def __make_border__(cls, parent, thickness, color, l, r, b, t): moveto_drawto = ( ((l, 0, t), (l, 0, b)), ((r, 0, t), (r, 0, b)), ((l, 0, b), (r, 0, b)), ((l, 0, t), (r, 0, t)), ) for moveto, drawto in moveto_drawto: Border = LineSegs() Border.setThickness(thickness) Border.setColor(*color) Border.moveTo(*moveto) Border.drawTo(*drawto) b = parent.attachNewNode(Border.create()) b.setBin(*cls.DRAW_ORDER['border']) def getMaxItems(self): return int(abs(self.height / self.text_h) - 1) @event_callback def toggle_vis(self): if self.frame_bg.isHidden(): self.frame_bg.show() self.raise_() else: self.frame_bg.hide() def title_toggle_vis(self): if not self.__was_dragging__: self.toggle_vis() if self.frame_bg.isHidden(): self.title_button.wrtReparentTo(self.frame) self.title_button['frameColor'] = (1, 1, 1, .5) # TODO else: self.title_button.wrtReparentTo(self.frame_bg) self.title_button['frameColor'] = (1, 1, 1, 0) # TODO else: self.__was_dragging__ = False def __startDrag(self, crap): self.raise_() self._ox, self._oy = base.mouseWatcherNode.getMouse() taskMgr.add(self.__drag, 'dragging %s' % self.title) self.origBTprefix = self.BT.getPrefix() self.BT.setPrefix('dragging frame') def __drag(self, task): if base.mouseWatcherNode.hasMouse(): x, y = base.mouseWatcherNode.getMouse() if x != self._ox or y != self._oy: m_old = aspect2d.getRelativePoint( render2d, Point3(self._ox, self._oy, 0)) m_new = aspect2d.getRelativePoint(render2d, Point3(x, y, 0)) dx, dy, _ = m_new - m_old self.setPos(self.x + dx, self.y + dy) self._ox = x self._oy = y self.__was_dragging__ = True return task.cont def __stopDrag(self, crap): taskMgr.remove('dragging %s' % self.title) self.BT.setPrefix(self.origBTprefix) def setPos(self, x, y): """ actually sets the title button position since it is really the parent node """ self.x = x self.y = y #- self.text_h # FIXME is hard :/ self.frame_bg.setPos(LVecBase3f(x, 0, y)) if self.frame_bg.isHidden(): self.title_button.setPos(LVecBase3f(x, 0, y - self.text_h)) def __enter__(self): #load the position #load other saved state pass def __exit__(self): #save the position! #save other state pass
class RaceGUI: GagPie = 0 gagRoot = "phase_3.5/maps/inventory_" class RacerInfo: def __init__(self, face, mapSpot): self.curvetime = 0 self.maxlaphit = 0 self.face = face self.mapspot = mapSpot self.place = 1 self.enabled = True self.finished = False self.gag = None def update(self, curvetime=None, maxlaphit=None, faceX=None, mapspotPt=None, place=None, finished=None): if (self.enabled): if (not curvetime == None): self.curvetime = curvetime if (not maxlaphit == None): self.maxlaphit = maxlaphit if (not faceX == None): self.face.setX(faceX) if (not mapspotPt == None): self.mapspot.setPos(mapspotPt) if (not place == None): self.place = place if (not finished == None): self.finished = finished def disable(self): self.enabled = False if (not self.finished): self.face.hide() self.mapspot.hide() def enable(self): self.enabled = True self.face.show() self.mapspot.show() def __init__(self, distRace): self.race = distRace self.timerEnabled = False self.maxLapHit = 0 self.photoFinish = False toonInteriorTextures = loader.loadModel( 'phase_3.5/models/modules/toon_interior_textures') invTextures = loader.loadModel('phase_3.5/models/gui/inventory_icons') racingTextures = loader.loadModel( 'phase_6/models/karting/racing_textures') self.gagTextures = [ toonInteriorTextures.find('**/couch'), invTextures.find('**/inventory_bannana_peel'), racingTextures.find('**/boost_arrow'), invTextures.find('**/inventory_anvil'), invTextures.find('**/inventory_creampie'), ] self.gagTextures[1].setScale(7.5) self.gagTextures[3].setScale(7.5) self.gagTextures[4].setScale(7.5) self.cardMaker = CardMaker('card') #racer info self.racerDict = {} #setup render2d self.render2dRoot = render2d.attachNewNode('RaceGuiRender2dRoot') self.render2dRoot.setDepthWrite(1) #setup a list of directobjects self.directObjList = [] #setup aspect2d self.aspect2dRoot = aspect2d.attachNewNode('RaceGuiAspect2dRoot') self.aspect2dRoot.setDepthWrite(1) #setup raceModeRoot self.raceModeRoot = self.aspect2dRoot.attachNewNode('RaceModeRoot') #setup the 'leave race' button gui = loader.loadModel("phase_3.5/models/gui/avatar_panel_gui") self.closeButton = DirectButton( image=( gui.find("**/CloseBtn_UP"), gui.find("**/CloseBtn_DN"), gui.find("**/CloseBtn_Rllvr"), gui.find("**/CloseBtn_UP"), ), relief=None, scale=1.05, text=TTLocalizer.KartRace_Leave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(-0.99, 0, 0.925), command=self.race.leaveRace, ) self.closeButton.reparentTo(self.aspect2dRoot) self.directObjList.append(self.closeButton) #setup the race gui self.raceTimeDelta = 0 self.raceModeReady = False # self.initRaceMode() #setup the end result mode gui self.resultModeReady = False # self.initResultMode() # Load the sounds for cycling through and picking a gag. # Since the methods for gag cycling are all here, it makes sense # for the sounds to be here as well. self.gagCycleSound = base.loadSfx( "phase_3.5/audio/sfx/tick_counter.mp3") if hasattr(self.gagCycleSound, "setPlayRate"): self.gagCycleSound.setPlayRate(0.2) self.gagCycleSound.setLoop(1) self.gagAcquireSound = base.loadSfx( "phase_6/audio/sfx/SZ_MM_gliss.mp3") self.disable() def initRaceMode(self): ## #setup the 'map' display region ## self.mapScene = NodePath('MapScene') ## self.mapScene.setTransparency(1) ## self.mapSize = 0.15 ## self.mapX = 0.84 ## self.mapY = 0.84 ## self.mapCam = None ## if (base.win.getNumDisplayRegions()>4): ## for x in range(base.win.getNumDisplayRegions()-4): ## dr = base.win.getDisplayRegion(x+4) ## if (dr.getCamera().getName() == 'MapCam'): ## self.mapCam = dr.getCamera() ## break ## if(self.mapCam == None): ## self.mapCam = base.makeCamera(base.win,sort=30,displayRegion = (self.mapX,self.mapX+self.mapSize,self.mapY,self.mapY+self.mapSize),camName = 'MapCam') ## self.mapCam.setY(-10) ## self.mapCam.node().setLens(OrthographicLens()) ## self.mapCam.node().getLens().setFilmSize(2) ## self.mapCam.node().getLens().setAspectRatio(4.0/3.0) ## self.mapCam.reparentTo(self.mapScene) ## self.cardMaker.reset() ## self.cardMaker.setName('MapBackground') ## self.cardMaker.setFrame(-1,1,-1,1) ## self.cardMaker.setColor(1,1,1,0.25) ## card = self.mapScene.attachNewNode(self.cardMaker.generate()) #setup the 'map' display region self.mapScene = self.raceModeRoot.attachNewNode('MapScene') self.mapScene.setPos(1.1, 0, 0.75) self.mapScene.setScale(0.25, 0.001, 0.25) maxT = self.race.curve.getMaxT() pt = Vec3(0, 0, 0) ls = LineSegs('MapLines') ls.setColor(1, 1, 1, 1) ls.setThickness(2) for x in range(101): self.race.curve.getPoint(x / 100.0 * maxT, pt) if (x == 0): ls.moveTo(pt[0], pt[1], pt[2]) else: ls.drawTo(pt[0], pt[1], pt[2]) self.mapLines = self.mapScene.attachNewNode(ls.create()) self.mapLines.setScale(0.00025 * RaceGlobals.TrackDict[self.race.trackId][6]) self.mapLines.setP(90) #setup face info self.faceStartPos = Vec3(-0.80, 0, 0.93) self.faceEndPos = Vec3(0.80, 0, 0.93) #setup place(1st,2nd,...) reporting self.placeLabelNum = DirectLabel( relief=None, pos=TTLocalizer.RGUIplaceLabelNumPos, text='1', text_scale=0.35, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), ) self.placeLabelNum.reparentTo(self.raceModeRoot) self.directObjList.append(self.placeLabelNum) self.placeLabelStr = DirectLabel( relief=None, pos=TTLocalizer.RGUIplaceLabelStrPos, text=TTLocalizer.KartRace_FirstSuffix, text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), ) self.placeLabelStr.reparentTo(self.raceModeRoot) self.directObjList.append(self.placeLabelStr) #setup lap reporting self.lapLabel = DirectLabel( relief=None, pos=(1.1, 0, 0.45), text='1/' + str(self.race.lapCount), text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), ) self.lapLabel.reparentTo(self.raceModeRoot) self.directObjList.append(self.lapLabel) #setup photo finish label self.photoFinishLabel = DirectLabel( relief=None, pos=(0, 0, -0.1), text=TTLocalizer.KartRace_PhotoFinish, text_scale=TTLocalizer.RGUIphotoFinish, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), ) self.photoFinishLabel.hide() self.directObjList.append(self.photoFinishLabel) #setup wrong way reporting self.wrongWayLabel = DirectLabel( relief=None, pos=(1.1, 0, 0.85), text=TTLocalizer.KartRace_WrongWay, text_scale=0.1, text_fg=(0.95, 0, 0, 1), text_font=ToontownGlobals.getSignFont(), ) self.wrongWayLabel.reparentTo(self.raceModeRoot) self.directObjList.append(self.wrongWayLabel) self.wrongWayLabel.setColorScale(Vec4(1, 1, 1, 0)) self.wrongWaySeq = Sequence( self.wrongWayLabel.colorScaleInterval(0.25, colorScale=Vec4(1, 1, 1, 1), startColorScale=Vec4( 1, 1, 1, 0)), self.wrongWayLabel.colorScaleInterval(0.25, colorScale=Vec4(1, 1, 1, 0), startColorScale=Vec4( 1, 1, 1, 1)), ) #setup time reporting interpolateFacePos = lambda x: self.faceStartPos * ( 1.0 - x) + self.faceEndPos * (x) self.timeLabels = [] for x in range(self.race.lapCount): minLabel = DirectLabel( relief=None, pos=(interpolateFacePos( (2.0 * x + 1) / (self.race.lapCount * 2))[0] - 0.06, 0, 0.84), text='0\'', text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight, ) minLabel.reparentTo(self.raceModeRoot) self.directObjList.append(minLabel) secLabel = DirectLabel( relief=None, pos=(interpolateFacePos( (2.0 * x + 1) / (self.race.lapCount * 2))[0] + 0.06, 0, 0.84), text='00\'\'', text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight, ) secLabel.reparentTo(self.raceModeRoot) self.directObjList.append(secLabel) fractionLabel = DirectLabel( relief=None, pos=(interpolateFacePos( (2.0 * x + 1) / (self.race.lapCount * 2))[0] + 0.14, 0, 0.84), text='00', text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight, ) fractionLabel.reparentTo(self.raceModeRoot) self.directObjList.append(fractionLabel) self.timeLabels.append((minLabel, secLabel, fractionLabel)) #setup gag indicator self.cardMaker.reset() self.cardMaker.setName('GagIndicator') self.cardMaker.setFrame(-0.5, 0.5, -0.5, 0.5) self.cardMaker.setColor(1, 1, 1, 1) self.gagPanel = DirectFrame( parent=self.raceModeRoot, relief=None, image=loader.loadModel('phase_6/models/karting/gag_panel'), image_scale=0.25, pos=(-1.13, 0, -0.5), ) self.directObjList.append(self.gagPanel) self.gag = self.gagPanel.attachNewNode('gag') self.gag.setScale(0.2) for gag in self.gagTextures: gag.reparentTo(self.gag) gag.hide() #setup face line self.cardMaker.reset() self.cardMaker.setName('RaceProgressLine') self.cardMaker.setFrame(-0.5, 0.5, -0.5, 0.5) line = self.raceModeRoot.attachNewNode(self.cardMaker.generate()) line.setScale(self.faceEndPos[0] - self.faceStartPos[0], 1, 0.01) line.setPos(0, 0, self.faceStartPos[2]) self.cardMaker.setName('RaceProgressLineHash') for n in range(self.race.lapCount + 1): hash = self.raceModeRoot.attachNewNode(self.cardMaker.generate()) hash.setScale(line.getScale()[2], 1, line.getScale()[2] * 5) t = float(n) / self.race.lapCount hash.setPos( self.faceStartPos[0] * (1 - t) + self.faceEndPos[0] * t, self.faceStartPos[1], self.faceStartPos[2]) self.raceModeReady = True self.disable() def initResultMode(self): self.endPanel = RaceEndPanel(len(self.race.avIds), self.race) self.endPanel.reparentTo(self.aspect2dRoot) self.directObjList.append(self.endPanel) self.resultModeReady = True self.disable() def showGag(self, gagIndex): if gagIndex < len(self.gagTextures): for gag in self.gagTextures: gag.hide() self.gagTextures[gagIndex].show() def updateGag(self, gagIndex): if (self.gag): # Make sure the gag cycle interval is cleaned up. # Do this before setting the final gag texture. if hasattr(self, "gagCycleInterval"): self.gagCycleInterval.finish() del self.gagCycleInterval #self.gagCycleSound.stop() self.gag.setHpr(0, 0, 0) # Set the actual gag texture. self.showGag(gagIndex) if gagIndex == 0: self.gag.hide() else: self.gag.show() self.gagAcquireSound.play() self.gagAcquireInterval = LerpHprInterval(self.gag, duration=0.5, blendType="easeOut", startHpr=Point3( 0, -90, 0), hpr=Point3(0, 0, 0)) self.gagAcquireInterval.start() def waitingOnGag(self, cycleTime): if (self.gag): numTextures = len(self.gagTextures) startOffset = random.choice(range(0, numTextures)) self.gag.show() self.gagCycleInterval = Parallel( LerpFunc(self.showNextGag, fromData=startOffset, toData=numTextures * 2 * cycleTime + startOffset, blendType="easeOut", duration=cycleTime), LerpHprInterval(self.gag, duration=cycleTime, hpr=Point3( 0, 180 * numTextures * 2 * cycleTime - 90, 0), blendType="easeOut", startHpr=Point3(0, 0, 0)), SoundInterval(self.gagCycleSound, loop=1, duration=cycleTime, startTime=0), name="gagCycleInterval") self.gagCycleInterval.start() def showNextGag(self, t): if (self.gag): # We don't want to show the texture at index 0. currGagIndex = int(t % (len(self.gagTextures) - 1)) + 1 self.showGag(currGagIndex) def enableSpeedometer(self): self.race.localKart.showSpeedometer() def disableSpeedometer(self): self.race.localKart.hideSpeedometer() def disableRaceMode(self): self.disableSpeedometer() ## self.mapCam.node().getDisplayRegion(0).setActive(False) self.render2dRoot.hide() self.raceModeRoot.hide() for x in self.timeLabels: for y in x: y.hide() self.setTimerEnabled(False) def disableResultMode(self): self.endPanel.disable() def disable(self): self.closeButton.hide() taskMgr.removeTasksMatching("clearRaceEndPanel") if self.raceModeReady: self.disableRaceMode() if self.resultModeReady: self.disableResultMode() def enableRaceMode(self): self.enableSpeedometer() ## self.closeButton.show() ## self.mapCam.node().getDisplayRegion(0).setActive(True) self.render2dRoot.show() self.raceModeRoot.show() self.maxLapHit = min(self.maxLapHit, self.race.lapCount - 1) for x in range(self.maxLapHit + 1): for y in self.timeLabels[x]: y.configure(text_font=ToontownGlobals.getSignFont()) y.show() for y in self.timeLabels[self.maxLapHit]: y.configure(text_font=ToontownGlobals.getSignFont()) def enableResultMode(self): self.endPanel.enable() # make this panel eventually go away eventually if this is the last race if not self.race.circuitLoop: taskMgr.doMethodLater(180, self.endPanel.closeButtonPressed, "clearRaceEndPanel", extraArgs=[]) def destroy(self): self.disable() if hasattr(self, "wrongWaySeq"): self.wrongWaySeq.finish() self.wrongWaySeq = None taskMgr.removeTasksMatching('removeIt') taskMgr.removeTasksMatching('removeCam*') taskMgr.removeTasksMatching("clearRaceEndPanel") for obj in self.directObjList: obj.destroy() if hasattr(self, "mapScene"): self.mapScene.removeNode() self.mapScene = None self.aspect2dRoot.removeNode() self.aspect2dRoot = None self.raceModeRoot.removeNode() self.raceModeRoot = None self.render2dRoot.removeNode() self.render2dRoot = None self.closeButton = None self.gag = None self.lapLabel = None self.timeLabels = None self.placeLabelStr = None self.placeLabelNum = None self.photoFinishLabel = None self.mapScene = None self.race = None def setSpotAsymptotic(self, diffT, spot): p = (-1, 1)[diffT > 0] * (1 - 1 / pow(abs(diffT) / self.cutoff + 1, 2)) spot.setX(p) def setSpotRaceLinear(self, t, spot): spot.setX(-1.0 + 2.0 * (t / self.lapCount)) def setSpotLapLinear(self, t, spot): spot.setX(-1.0 + 2.0 * (t - int(t))) def update(self, time): placeSorter = [] placeCount = 0 # begin updates for all racers for key in self.racerDict.keys(): racer = self.racerDict[key] curvetime = racer.curvetime face = racer.face mapspot = racer.mapspot maxlaphit = racer.maxlaphit if (not racer.finished and racer.enabled): placeSorter.append((curvetime, key)) if (racer.finished or racer.enabled): placeCount += 1 pt = Vec3(0, 0, 0) mapT = ( (curvetime % 1 + self.race.startT / self.race.curve.getMaxT()) % 1) * self.race.curve.getMaxT() self.race.curve.getPoint(mapT, pt) self.race.curve.getPoint((mapT % self.race.curve.getMaxT()), pt) lapT = clampScalar(curvetime / self.race.lapCount, 0.0, 1.0) faceX = self.faceStartPos[0] * (1 - lapT) + self.faceEndPos[0] * lapT racer.update(faceX=faceX, mapspotPt=pt) # subtract out previous lap times t = time - self.race.baseTime - self.raceTimeDelta # begin updates for self only if (key == localAvatar.doId): if (self.race.laps > maxlaphit): racer.update(maxlaphit=self.race.laps) self.maxLapHit = racer.maxlaphit if (self.maxLapHit < self.race.lapCount): for y in self.timeLabels[self.maxLapHit - 1]: y.configure( text_font=ToontownGlobals.getSignFont()) for y in self.timeLabels[self.maxLapHit]: y.show() for y in self.timeLabels[self.maxLapHit]: y.configure( text_font=ToontownGlobals.getSignFont()) self.raceTimeDelta = globalClock.getFrameTime( ) - self.race.baseTime lapNotice = DirectLabel() lapNotice.setScale(.1) if (self.maxLapHit == self.race.lapCount - 1): lapNotice[ 'text'] = TTLocalizer.KartRace_FinalLapText else: lapNotice[ 'text'] = TTLocalizer.KartRace_LapText % str( self.maxLapHit + 1) taskMgr.doMethodLater(2, lapNotice.remove, "removeIt", extraArgs=[]) self.lapLabel['text'] = str( clampScalar(self.maxLapHit + 1, 1, self.race.lapCount)) + '/' + str( self.race.lapCount) suffix = { 1: TTLocalizer.KartRace_FirstSuffix, 2: TTLocalizer.KartRace_SecondSuffix, 3: TTLocalizer.KartRace_ThirdSuffix, 4: TTLocalizer.KartRace_FourthSuffix, } placeSorter.sort() for x, p in zip(placeSorter, xrange(len(placeSorter), 0, -1)): self.racerDict[x[1]].update(place=(p + placeCount - len(placeSorter))) # if we are close to the finish line, and so is someone else, # declare a 'photo finish' localRacer = self.racerDict[localAvatar.doId] (nearDiff, farDiff) = RaceGlobals.TrackDict[self.race.trackId][8] if (not localRacer.finished) and ( self.faceEndPos[0] - localRacer.face.getX() < nearDiff): for racerId in self.racerDict.keys(): racer = self.racerDict[racerId] if (not racer.enabled or (racerId == localAvatar.doId) or (racer.face.getX() >= self.faceEndPos[0])): continue if (self.faceEndPos[0] - racer.face.getX()) < farDiff: self.photoFinish = True if self.photoFinish: self.photoFinishLabel.show() self.placeLabelNum['text'] = "" self.placeLabelStr['text'] = "" else: self.photoFinishLabel.hide() self.placeLabelNum['text'] = str( self.racerDict[localAvatar.doId].place) self.placeLabelStr['text'] = suffix[self.racerDict[ localAvatar.doId].place] # convert the time into a label displayable string minutes = int(t / 60) t -= minutes * 60 seconds = int(t) # quick python ternary operator padding = (seconds < 10 and ['0'] or [''])[0] t -= seconds fraction = str(t)[2:4] fraction = fraction + '0' * (2 - len(fraction)) if (self.timerEnabled and self.maxLapHit < self.race.lapCount): self.timeLabels[self.maxLapHit][0]['text'] = '%d\'' % (minutes) self.timeLabels[self.maxLapHit][1]['text'] = '%s%d\'\'' % (padding, seconds) self.timeLabels[self.maxLapHit][2]['text'] = '%s' % (fraction) if (self.race.wrongWay and not self.wrongWaySeq.isPlaying()): self.wrongWaySeq.loop() elif (not self.race.wrongWay and self.wrongWaySeq.isPlaying()): self.wrongWaySeq.finish() def updateRacerInfo(self, avId, curvetime=None, maxlaphit=None): if (avId in self.racerDict.keys()): self.racerDict[avId].update(curvetime=curvetime, maxlaphit=maxlaphit) ##################################################### # Begin populating the gui elements with racer data # ##################################################### def racerEntered(self, avId): toon = base.cr.doId2do.get(avId, None) kart = base.cr.doId2do.get(self.race.kartMap.get(avId, None), None) if (not toon or not kart): return if (kart.getBodyColor() == InvalidEntry): bodyColor = getDefaultColor() else: bodyColor = getAccessory(kart.getBodyColor()) ######################################################### # When offscreen buffers are supported, this works... # ######################################################### ## # setup temporary portrait scene graph ## buf = base.graphicsEngine.makeBuffer(base.win.getGsg(),'test',0,128,128) ## par = buf.makeTextureBuffer('par',128,128) ## parcam = base.makeCamera(par,0,'parCam') ## parcam.node().setLens(OrthographicLens()) ## parcam.node().getLens().setFilmSize(0.5,0.5) ## portraitSceneGraph = NodePath('Portrait:%d'%avId) ## parcam.reparentTo(portraitSceneGraph) ## tex = par.getTexture() ## headframe = RaceHeadFrame(toon,bodyColor) ## headframe.configure(geom_scale=(0.5,0.5,0.5)) ## headframe.setY(10) ## headframe.reparentTo(portraitSceneGraph) ## # take picture and initialize cleanup ## buf.setOneShot(True) ## def cleanUpPortrait(task,s = portraitSceneGraph,f = headframe): ## f.destroy() ## s.removeNode() ## # if using this doMethodLater, be sure to remove it from the taskMgr ## # ## taskMgr.doMethodLater(1,cleanUpPortrait,'removeCam:%d'%avId) ## #setup face ## self.cardMaker.reset() ## self.cardMaker.setName('Face:%d'%avId) ## self.cardMaker.setFrame(-0.5,0.5,-0.5,0.5) ## face = NodePath(self.cardMaker.generate()) ## face.setTexture(tex,1) ## face.setZ(self.faceStartPos[2]) ## face.reparentTo(self.raceModeRoot) headframe = RaceHeadFrame(av=toon, color=bodyColor) eyes = headframe.head.find('**/eyes*') eyes.setDepthTest(1) eyes.setDepthWrite(1) headframe.configure(geom_scale=(0.5, 0.5, 0.5)) headframe.setZ(self.faceStartPos[2]) headframe.setDepthWrite(True) headframe.setDepthTest(True) headframe.reparentTo(self.raceModeRoot) self.directObjList.append(headframe) #setup map place mapspot = loader.loadModel('phase_6/models/karting/race_mapspot') mapspot.setColor(bodyColor) mapspot.reparentTo(self.mapLines) mapspot.setHpr(self.mapScene, 0, 0, 0) self.racerDict[avId] = self.RacerInfo(headframe, mapspot) for key, i in zip(self.racerDict.keys(), range(len(self.racerDict.keys()))): face = self.racerDict[key].face mapspot = self.racerDict[key].mapspot face.setX(self.faceStartPos[0]) face.setY(-1 - 5 * (i + 1)) face.setScale(0.15) mapspot.getChild(0).setY((-5 - 5 * (i + 1)) * 1000) mapspot.setScale(self.mapScene, 0.15) mapspot.setPos(self.race.startingPos[0][0]) if (key == localAvatar.doId): face.setY(-1) face.setScale(face.getScale() * 1.25) mapspot.getChild(0).setY((-5) * 1000) mapspot.setScale(mapspot.getScale() * 1.25) self.face = face self.mapspot = mapspot def racerLeft(self, avId, unexpected=False): racer = self.racerDict.get(avId, None) if (racer): racer.disable() def racerFinished(self, avId, trackId, place, totalTime, entryFee, qualify, winnings, bonus, trophies, circuitPoints, circuitTime): racer = self.racerDict.get(avId, None) if (racer): racer.update(finished=True) racer.disable() self.endPanel.displayRacer(place, entryFee, qualify, winnings, trackId, bonus, trophies, racer.face, base.cr.doId2do[avId].getName(), totalTime, circuitPoints, circuitTime) self.directObjList.remove(racer.face) if (avId == localAvatar.doId): self.disableRaceMode() self.enableResultMode() self.endPanel.startWinningsPanel(entryFee, winnings, trackId, bonus, trophies) def racerFinishedCircuit(self, avId, place, entryFee, winnings, bonus, trophies): #print("racerFinishedCircuit") racer = self.racerDict.get(avId, None) if (racer): newTotalTickets = winnings + entryFee + bonus self.endPanel.updateWinnings(place, newTotalTickets) if (avId == localAvatar.doId): self.endPanel.updateWinningsFromCircuit( place, entryFee, winnings, bonus, trophies) pass # self.disableRaceMode() # self.enableResultMode() # self.endPanel.startWinningsPanel(entryFee,winnings,trackId,bonus,trophies) def circuitFinished(self, placeFixup): #print "circuit finished" self.endPanel.circuitFinished(placeFixup) def setTimerEnabled(self, enabled): self.timerEnabled = enabled
class MainGUI(DirectObject.DirectObject): def __init__(self): self.scaling = Scaling() self.layer = 0 self.regen = False self.showMenu = True self.showPause = False self.showMap = False self.pauseBar = DirectFrame( frameColor=(0.22/2, 0.24/2, 0.32/2, 1), frameSize=(0, base.win.getXSize(), 0, self.scaling.getVerticalDisplayRatio(25)), pos=(0, -1, -self.scaling.getVerticalDisplayRatio(25)), parent=pixel2d ) header = TextNode('paused') header.setText('Paused') header.setTextColor(1, 1, 1, 1) header.setAlign(TextNode.ACenter) header.setTextScale(30) self.pauseTextNodePath = self.pauseBar.attachNewNode(header) self.pauseTextNodePath.setPos(base.win.getXSize()/2, 0, -5) self.footer = DirectFrame( frameSize=(0, base.win.getXSize(), 0, 24), pos=(0, -1, -base.win.getYSize()), parent=pixel2d ) #findMethods(self.footer, 'set') self.pauseBar.hide() self.coords = TextNode('coords') self.coords.setText('coords: _x _y _z') self.coords.setTextColor(0, 0, 0, 1) self.coords.setAlign(TextNode.ARight) self.coords.setTextScale(15) self.coordsTextNodePath = self.footer.attachNewNode(self.coords) self.coordsTextNodePath.setPos(base.win.getXSize() - 10, 0, 5) self.time = TextNode('time') self.time.setText('time: _x _y _z') self.time.setTextColor(0, 0, 0, 1) self.time.setAlign(TextNode.ALeft) self.time.setTextScale(15) self.timeTextNodePath = self.footer.attachNewNode(self.time) self.timeTextNodePath.setPos(10, 0, 5) pixel2d.setAntialias(AntialiasAttrib.MMultisample) self.menubar = MenuBar() self.mapView = MapView() self.registerEvents() self.registerMouseClickEvents() def registerEvents(self): self.accept('window-event', self.onWindowEvent) self.accept('escape', self.exitProgram) self.accept('q', self.toggleMenu) self.accept('m', self.toggleMap) self.accept('l', self.cycleLayers) self.accept('space', self.togglePause) self.accept('w', self.shiftMapUp) self.accept('s', self.shiftMapDown) self.accept('a', self.shiftMapLeft) self.accept('d', self.shiftMapRight) def registerMouseClickEvents(self): findMethods(self.menubar.btnQuit, 'func') self.menubar.btnQuit['command'] = self.exitProgram self.mapView.btnLayers['command'] = self.cycleLayers self.menubar.btnMaps['command'] = self.setRegen def shiftMapUp(self): if self.mapView.origin[1] > 0: self.mapView.origin[1] -= 1 print(self.mapView.origin) def shiftMapDown(self): if self.mapView.origin[1] >= 0: self.mapView.origin[1] += 1 print(self.mapView.origin) def shiftMapLeft(self): if self.mapView.origin[0] > 0: self.mapView.origin[0] -= 1 print(self.mapView.origin) def shiftMapRight(self): if self.mapView.origin[0] >= 0: self.mapView.origin[0] += 1 print(self.mapView.origin) def setRegen(self): self.regen = True def toggleMenu(self): self.showMenu = not self.showMenu if self.showMenu: self.menubar.menubar.show() else: self.menubar.menubar.hide() def togglePause(self): self.showPause = not self.showPause if self.showPause: self.pauseBar.show() else: self.pauseBar.hide() def toggleMap(self): self.showMap = not self.showMap if self.showMap: self.mapView.mapView.show() else: self.mapView.mapView.hide() def onWindowEvent(self, window): self.pauseBar['frameSize'] = (0, window.size[0], 0, self.scaling.getVerticalDisplayRatio(25)) self.footer['frameSize'] = (0, window.size[0], 0, self.scaling.getVerticalDisplayRatio(25)) self.footer.setZ(-window.size[1]) self.pauseTextNodePath.setPos(base.win.getXSize()/2, 0, -5) self.coordsTextNodePath.setPos(base.win.getXSize() - 10, 0, 5) self.mapView.mapView.setPos( base.win.getXSize() - self.mapView.xDim - 1, -1, -base.win.getYSize() + self.mapView.vOffset ) def exitProgram(self): sys.exit() def cycleLayers(self): self.layer += 1 if self.layer >= 4: self.layer = 0 def prepare_font(self): pass
class RaceGUI: GagPie = 0 gagRoot = 'phase_3.5/maps/inventory_' class RacerInfo: def __init__(self, face, mapSpot): self.curvetime = 0 self.maxlaphit = 0 self.face = face self.mapspot = mapSpot self.place = 1 self.enabled = True self.finished = False self.gag = None return def update(self, curvetime = None, maxlaphit = None, faceX = None, mapspotPt = None, place = None, finished = None): if self.enabled: if not curvetime == None: self.curvetime = curvetime if not maxlaphit == None: self.maxlaphit = maxlaphit if not faceX == None: self.face.setX(faceX) if not mapspotPt == None: self.mapspot.setPos(mapspotPt) if not place == None: self.place = place if not finished == None: self.finished = finished return def disable(self): self.enabled = False if not self.finished: self.face.hide() self.mapspot.hide() def enable(self): self.enabled = True self.face.show() self.mapspot.show() def __init__(self, distRace): self.race = distRace self.timerEnabled = False self.maxLapHit = 0 self.photoFinish = False toonInteriorTextures = loader.loadModel('phase_3.5/models/modules/toon_interior_textures') invTextures = loader.loadModel('phase_3.5/models/gui/inventory_icons') racingTextures = loader.loadModel('phase_6/models/karting/racing_textures') self.gagTextures = [toonInteriorTextures.find('**/couch'), invTextures.find('**/inventory_bannana_peel'), racingTextures.find('**/boost_arrow'), invTextures.find('**/inventory_anvil'), invTextures.find('**/inventory_creampie')] self.gagTextures[1].setScale(7.5) self.gagTextures[3].setScale(7.5) self.gagTextures[4].setScale(7.5) self.cardMaker = CardMaker('card') self.racerDict = {} self.render2dRoot = render2d.attachNewNode('RaceGuiRender2dRoot') self.render2dRoot.setDepthWrite(1) self.directObjList = [] self.aspect2dRoot = aspect2d.attachNewNode('RaceGuiAspect2dRoot') self.aspect2dRoot.setDepthWrite(1) self.raceModeRoot = self.aspect2dRoot.attachNewNode('RaceModeRoot') gui = loader.loadModel('phase_3.5/models/gui/avatar_panel_gui') self.closeButton = DirectButton(image=(gui.find('**/CloseBtn_UP'), gui.find('**/CloseBtn_DN'), gui.find('**/CloseBtn_Rllvr'), gui.find('**/CloseBtn_UP')), relief=None, scale=1.05, text=TTLocalizer.KartRace_Leave, text_scale=0.04, text_pos=(0, -0.07), text_fg=VBase4(1, 1, 1, 1), pos=(-0.99, 0, 0.925), command=self.race.leaveRace) self.closeButton.reparentTo(self.aspect2dRoot) self.directObjList.append(self.closeButton) self.raceTimeDelta = 0 self.raceModeReady = False self.resultModeReady = False self.gagCycleSound = base.loadSfx('phase_3.5/audio/sfx/tick_counter.ogg') if hasattr(self.gagCycleSound, 'setPlayRate'): self.gagCycleSound.setPlayRate(0.2) self.gagCycleSound.setLoop(1) self.gagAcquireSound = base.loadSfx('phase_6/audio/sfx/SZ_MM_gliss.ogg') self.disable() return def initRaceMode(self): self.mapScene = base.a2dTopRight.attachNewNode('MapScene') self.mapScene.setPos(-0.2, 0, -0.2) self.mapScene.setScale(0.25, 0.001, 0.25) maxT = self.race.curve.getMaxT() pt = Vec3(0, 0, 0) ls = LineSegs('MapLines') ls.setColor(1, 1, 1, 1) ls.setThickness(2) for x in xrange(101): self.race.curve.getPoint(x / 100.0 * maxT, pt) if x == 0: ls.moveTo(pt[0], pt[1], pt[2]) else: ls.drawTo(pt[0], pt[1], pt[2]) self.mapLines = self.mapScene.attachNewNode(ls.create()) self.mapLines.setScale(0.00025 * RaceGlobals.TrackDict[self.race.trackId][6]) self.mapLines.setP(90) self.faceStartPos = Vec3(-0.8, 0, 0.93) self.faceEndPos = Vec3(0.8, 0, 0.93) self.placeLabelNum = DirectLabel(relief=None, pos=TTLocalizer.RGUIplaceLabelNumPos, text='1', text_scale=0.35, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.placeLabelNum.reparentTo(base.a2dBottomLeft) self.directObjList.append(self.placeLabelNum) self.placeLabelStr = DirectLabel(relief=None, pos=TTLocalizer.RGUIplaceLabelStrPos, text=TTLocalizer.KartRace_FirstSuffix, text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.placeLabelStr.reparentTo(base.a2dBottomLeft) self.directObjList.append(self.placeLabelStr) self.lapLabel = DirectLabel(relief=None, pos=(-0.22, 0, -0.5), text='1/' + str(self.race.lapCount), text_scale=0.1, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.lapLabel.reparentTo(base.a2dTopRight) self.directObjList.append(self.lapLabel) self.photoFinishLabel = DirectLabel(relief=None, pos=(0, 0, -0.1), text=TTLocalizer.KartRace_PhotoFinish, text_scale=TTLocalizer.RGUIphotoFinish, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont()) self.photoFinishLabel.hide() self.directObjList.append(self.photoFinishLabel) self.wrongWayLabel = DirectLabel(relief=None, pos=(-0.22, 0, -0.2), text=TTLocalizer.KartRace_WrongWay, text_scale=0.1, text_fg=(0.95, 0, 0, 1), text_font=ToontownGlobals.getSignFont()) self.wrongWayLabel.reparentTo(base.a2dTopRight) self.directObjList.append(self.wrongWayLabel) self.wrongWayLabel.setColorScale(Vec4(1, 1, 1, 0)) self.wrongWaySeq = Sequence(self.wrongWayLabel.colorScaleInterval(0.25, colorScale=Vec4(1, 1, 1, 1), startColorScale=Vec4(1, 1, 1, 0)), self.wrongWayLabel.colorScaleInterval(0.25, colorScale=Vec4(1, 1, 1, 0), startColorScale=Vec4(1, 1, 1, 1))) interpolateFacePos = lambda x: self.faceStartPos * (1.0 - x) + self.faceEndPos * x self.timeLabels = [] for x in xrange(self.race.lapCount): minLabel = DirectLabel(relief=None, pos=(interpolateFacePos((2.0 * x + 1) / (self.race.lapCount * 2))[0] - 0.06, 0, 0.84), text="0'", text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight) minLabel.reparentTo(self.raceModeRoot) self.directObjList.append(minLabel) secLabel = DirectLabel(relief=None, pos=(interpolateFacePos((2.0 * x + 1) / (self.race.lapCount * 2))[0] + 0.06, 0, 0.84), text="00''", text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight) secLabel.reparentTo(self.raceModeRoot) self.directObjList.append(secLabel) fractionLabel = DirectLabel(relief=None, pos=(interpolateFacePos((2.0 * x + 1) / (self.race.lapCount * 2))[0] + 0.14, 0, 0.84), text='00', text_scale=0.06, text_fg=(0.95, 0.95, 0, 1), text_font=ToontownGlobals.getSignFont(), text_align=TextNode.ARight) fractionLabel.reparentTo(self.raceModeRoot) self.directObjList.append(fractionLabel) self.timeLabels.append((minLabel, secLabel, fractionLabel)) self.cardMaker.reset() self.cardMaker.setName('GagIndicator') self.cardMaker.setFrame(-0.5, 0.5, -0.5, 0.5) self.cardMaker.setColor(1, 1, 1, 1) self.gagPanel = DirectFrame(parent=base.a2dBottomLeft, relief=None, image=loader.loadModel('phase_6/models/karting/gag_panel'), image_scale=0.25, pos=(0.2, 0, 0.55)) self.directObjList.append(self.gagPanel) self.gag = self.gagPanel.attachNewNode('gag') self.gag.setScale(0.2) for gag in self.gagTextures: gag.reparentTo(self.gag) gag.hide() self.cardMaker.reset() self.cardMaker.setName('RaceProgressLine') self.cardMaker.setFrame(-0.5, 0.5, -0.5, 0.5) line = self.raceModeRoot.attachNewNode(self.cardMaker.generate()) line.setScale(self.faceEndPos[0] - self.faceStartPos[0], 1, 0.01) line.setPos(0, 0, self.faceStartPos[2]) self.cardMaker.setName('RaceProgressLineHash') for n in xrange(self.race.lapCount + 1): hash = self.raceModeRoot.attachNewNode(self.cardMaker.generate()) hash.setScale(line.getScale()[2], 1, line.getScale()[2] * 5) t = float(n) / self.race.lapCount hash.setPos(self.faceStartPos[0] * (1 - t) + self.faceEndPos[0] * t, self.faceStartPos[1], self.faceStartPos[2]) self.raceModeReady = True self.disable() return def initResultMode(self): self.endPanel = RaceEndPanel(len(self.race.avIds), self.race) self.endPanel.reparentTo(self.aspect2dRoot) self.directObjList.append(self.endPanel) self.resultModeReady = True self.disable() def showGag(self, gagIndex): if gagIndex < len(self.gagTextures): for gag in self.gagTextures: gag.hide() self.gagTextures[gagIndex].show() def updateGag(self, gagIndex): if self.gag: if hasattr(self, 'gagCycleInterval'): self.gagCycleInterval.finish() del self.gagCycleInterval self.gag.setHpr(0, 0, 0) self.showGag(gagIndex) if gagIndex == 0: self.gag.hide() else: self.gag.show() self.gagAcquireSound.play() self.gagAcquireInterval = LerpHprInterval(self.gag, duration=0.5, blendType='easeOut', startHpr=Point3(0, -90, 0), hpr=Point3(0, 0, 0)) self.gagAcquireInterval.start() def waitingOnGag(self, cycleTime): if self.gag: numTextures = len(self.gagTextures) startOffset = random.choice(range(0, numTextures)) self.gag.show() self.gagCycleInterval = Parallel(LerpFunc(self.showNextGag, fromData=startOffset, toData=numTextures * 2 * cycleTime + startOffset, blendType='easeOut', duration=cycleTime), LerpHprInterval(self.gag, duration=cycleTime, hpr=Point3(0, 180 * numTextures * 2 * cycleTime - 90, 0), blendType='easeOut', startHpr=Point3(0, 0, 0)), SoundInterval(self.gagCycleSound, loop=1, duration=cycleTime, startTime=0), name='gagCycleInterval') self.gagCycleInterval.start() def showNextGag(self, t): if self.gag: currGagIndex = int(t % (len(self.gagTextures) - 1)) + 1 self.showGag(currGagIndex) def enableSpeedometer(self): self.race.localKart.showSpeedometer() def disableSpeedometer(self): self.race.localKart.hideSpeedometer() def disableRaceMode(self): self.disableSpeedometer() self.render2dRoot.hide() self.raceModeRoot.hide() for x in self.timeLabels: for y in x: y.hide() self.setTimerEnabled(False) def disableResultMode(self): self.endPanel.disable() def disable(self): self.closeButton.hide() taskMgr.removeTasksMatching('clearRaceEndPanel') if self.raceModeReady: self.disableRaceMode() if self.resultModeReady: self.disableResultMode() def enableRaceMode(self): self.enableSpeedometer() self.render2dRoot.show() self.raceModeRoot.show() self.maxLapHit = min(self.maxLapHit, self.race.lapCount - 1) for x in xrange(self.maxLapHit + 1): for y in self.timeLabels[x]: y.configure(text_font=ToontownGlobals.getSignFont()) y.show() for y in self.timeLabels[self.maxLapHit]: y.configure(text_font=ToontownGlobals.getSignFont()) def enableResultMode(self): self.endPanel.enable() if len(self.race.circuitLoop) > 1: taskMgr.doMethodLater(180, self.endPanel.closeButtonPressed, 'clearRaceEndPanel', extraArgs=[]) def destroy(self): self.disable() if hasattr(self, 'wrongWaySeq'): self.wrongWaySeq.finish() self.wrongWaySeq = None taskMgr.removeTasksMatching('removeIt') taskMgr.removeTasksMatching('removeCam*') taskMgr.removeTasksMatching('clearRaceEndPanel') for obj in self.directObjList: obj.destroy() if hasattr(self, 'mapScene'): self.mapScene.removeNode() self.mapScene = None self.aspect2dRoot.removeNode() self.aspect2dRoot = None self.raceModeRoot.removeNode() self.raceModeRoot = None self.render2dRoot.removeNode() self.render2dRoot = None self.closeButton = None self.gag = None self.lapLabel = None self.timeLabels = None self.placeLabelStr = None self.placeLabelNum = None self.photoFinishLabel = None self.mapScene = None self.race = None return def setSpotAsymptotic(self, diffT, spot): p = (-1, 1)[diffT > 0] * (1 - 1 / pow(abs(diffT) / self.cutoff + 1, 2)) spot.setX(p) def setSpotRaceLinear(self, t, spot): spot.setX(-1.0 + 2.0 * (t / self.lapCount)) def setSpotLapLinear(self, t, spot): spot.setX(-1.0 + 2.0 * (t - int(t))) def update(self, time): placeSorter = [] placeCount = 0 for key in self.racerDict.keys(): racer = self.racerDict[key] curvetime = racer.curvetime face = racer.face mapspot = racer.mapspot maxlaphit = racer.maxlaphit if not racer.finished and racer.enabled: placeSorter.append((curvetime, key)) if racer.finished or racer.enabled: placeCount += 1 pt = Vec3(0, 0, 0) mapT = (curvetime % 1 + self.race.startT / self.race.curve.getMaxT()) % 1 * self.race.curve.getMaxT() self.race.curve.getPoint(mapT, pt) self.race.curve.getPoint(mapT % self.race.curve.getMaxT(), pt) lapT = clampScalar(curvetime / self.race.lapCount, 0.0, 1.0) faceX = self.faceStartPos[0] * (1 - lapT) + self.faceEndPos[0] * lapT racer.update(faceX=faceX, mapspotPt=pt) t = time - self.race.baseTime - self.raceTimeDelta if key == localAvatar.doId: if self.race.laps > maxlaphit: racer.update(maxlaphit=self.race.laps) self.maxLapHit = racer.maxlaphit if self.maxLapHit < self.race.lapCount: for y in self.timeLabels[self.maxLapHit - 1]: y.configure(text_font=ToontownGlobals.getSignFont()) for y in self.timeLabels[self.maxLapHit]: y.show() for y in self.timeLabels[self.maxLapHit]: y.configure(text_font=ToontownGlobals.getSignFont()) self.raceTimeDelta = globalClock.getFrameTime() - self.race.baseTime lapNotice = DirectLabel() lapNotice.setScale(0.1) if self.maxLapHit == self.race.lapCount - 1: lapNotice['text'] = TTLocalizer.KartRace_FinalLapText else: lapNotice['text'] = TTLocalizer.KartRace_LapText % str(self.maxLapHit + 1) taskMgr.doMethodLater(2, lapNotice.remove, 'removeIt', extraArgs=[]) self.lapLabel['text'] = str(clampScalar(self.maxLapHit + 1, 1, self.race.lapCount)) + '/' + str(self.race.lapCount) suffix = {1: TTLocalizer.KartRace_FirstSuffix, 2: TTLocalizer.KartRace_SecondSuffix, 3: TTLocalizer.KartRace_ThirdSuffix, 4: TTLocalizer.KartRace_FourthSuffix} placeSorter.sort() for x, p in zip(placeSorter, xrange(len(placeSorter), 0, -1)): self.racerDict[x[1]].update(place=p + placeCount - len(placeSorter)) localRacer = self.racerDict[localAvatar.doId] nearDiff, farDiff = RaceGlobals.TrackDict[self.race.trackId][8] if not localRacer.finished and self.faceEndPos[0] - localRacer.face.getX() < nearDiff: for racerId in self.racerDict.keys(): racer = self.racerDict[racerId] if not racer.enabled or racerId == localAvatar.doId or racer.face.getX() >= self.faceEndPos[0]: continue if self.faceEndPos[0] - racer.face.getX() < farDiff: self.photoFinish = True if self.photoFinish: self.photoFinishLabel.show() self.placeLabelNum['text'] = '' self.placeLabelStr['text'] = '' else: self.photoFinishLabel.hide() self.placeLabelNum['text'] = str(self.racerDict[localAvatar.doId].place) self.placeLabelStr['text'] = suffix[self.racerDict[localAvatar.doId].place] minutes = int(t / 60) t -= minutes * 60 seconds = int(t) padding = (seconds < 10 and ['0'] or [''])[0] t -= seconds fraction = str(t)[2:4] fraction = fraction + '0' * (2 - len(fraction)) if self.timerEnabled and self.maxLapHit < self.race.lapCount: self.timeLabels[self.maxLapHit][0]['text'] = "%d'" % minutes self.timeLabels[self.maxLapHit][1]['text'] = "%s%d''" % (padding, seconds) self.timeLabels[self.maxLapHit][2]['text'] = '%s' % fraction if self.race.wrongWay and not self.wrongWaySeq.isPlaying(): self.wrongWaySeq.loop() elif not self.race.wrongWay and self.wrongWaySeq.isPlaying(): self.wrongWaySeq.finish() def updateRacerInfo(self, avId, curvetime = None, maxlaphit = None): if avId in self.racerDict.keys(): self.racerDict[avId].update(curvetime=curvetime, maxlaphit=maxlaphit) def racerEntered(self, avId): toon = base.cr.doId2do.get(avId, None) kart = base.cr.doId2do.get(self.race.kartMap.get(avId, None), None) if not toon or not kart: return if kart.getBodyColor() == InvalidEntry: bodyColor = getDefaultColor() else: bodyColor = getAccessory(kart.getBodyColor()) headframe = RaceHeadFrame(av=toon, color=bodyColor) eyes = headframe.head.find('**/eyes*') eyes.setDepthTest(1) eyes.setDepthWrite(1) headframe.configure(geom_scale=(0.5, 0.5, 0.5)) headframe.setZ(self.faceStartPos[2]) headframe.setDepthWrite(True) headframe.setDepthTest(True) headframe.reparentTo(self.raceModeRoot) self.directObjList.append(headframe) mapspot = loader.loadModel('phase_6/models/karting/race_mapspot') mapspot.setColor(bodyColor) mapspot.reparentTo(self.mapLines) mapspot.setHpr(self.mapScene, 0, 0, 0) self.racerDict[avId] = self.RacerInfo(headframe, mapspot) for key, i in zip(self.racerDict.keys(), range(len(self.racerDict.keys()))): face = self.racerDict[key].face mapspot = self.racerDict[key].mapspot face.setX(self.faceStartPos[0]) face.setY(-1 - 5 * (i + 1)) face.setScale(0.15) mapspot.getChild(0).setY((-5 - 5 * (i + 1)) * 1000) mapspot.setScale(self.mapScene, 0.15) mapspot.setPos(self.race.startingPos[0][0]) if key == localAvatar.doId: face.setY(-1) face.setScale(face.getScale() * 1.25) mapspot.getChild(0).setY(-5 * 1000) mapspot.setScale(mapspot.getScale() * 1.25) self.face = face self.mapspot = mapspot return def racerLeft(self, avId, unexpected = False): racer = self.racerDict.get(avId, None) if racer: racer.disable() return def racerFinished(self, avId, trackId, place, totalTime, entryFee, qualify, winnings, bonus, trophies, circuitPoints, circuitTime): racer = self.racerDict.get(avId, None) if racer: racer.update(finished=True) racer.disable() self.endPanel.displayRacer(place, entryFee, qualify, winnings, trackId, bonus, trophies, racer.face, base.cr.doId2do[avId].getName(), totalTime, circuitPoints, circuitTime) if racer.face in self.directObjList: self.directObjList.remove(racer.face) if avId == localAvatar.doId: self.disableRaceMode() self.enableResultMode() self.endPanel.startWinningsPanel(entryFee, winnings, trackId, bonus, trophies) return def racerFinishedCircuit(self, avId, place, entryFee, winnings, bonus, trophies): racer = self.racerDict.get(avId, None) if racer: newTotalTickets = winnings + entryFee + bonus self.endPanel.updateWinnings(place, newTotalTickets) if avId == localAvatar.doId: self.endPanel.updateWinningsFromCircuit(place, entryFee, winnings, bonus, trophies) return def circuitFinished(self, placeFixup): self.endPanel.circuitFinished(placeFixup) def setTimerEnabled(self, enabled): self.timerEnabled = enabled
class DirectWindow( DirectFrame ): def __init__( self , pos = ( -.5, .5) , title = 'Title' , bgColor = (.5,.5,.5,1) , buttonColor = (1,1,1,1) #( .6, .6, .6, 1 ) #, minSize = ( .5, .5 ) #, maxSize = ( 1, 1 ) , minWindowSize = (0,0) , maxWindowSize = (10000,10000) , virtualSize = (1,1) , windowBorderTextureFiles = [ DEFAULT_TITLE_TEXTURE_LEFT , DEFAULT_TITLE_TEXTURE_CENTER , DEFAULT_TITLE_TEXTURE_RIGHT , DEFAULT_RESIZE_GEOM ] , windowBorderGeomFiles = [ DEFAULT_TITLE_GEOM_RIGHT ] , windowColors = [ ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) ] , borderSize = 0.01 , dragbarSize = 0.05 , parent=None): self.windowPos = pos self.minWindowSize = minWindowSize self.maxWindowSize = maxWindowSize self.virtualSize = virtualSize self.borderSize = borderSize self.dragbarSize = dragbarSize if parent is None: parent=aspect2d self.parent=parent self.previousSize = (10,10) self.collapsed = False # maybe we should check if aspect2d doesnt already contain the aspect2dMouseNode self.mouseNode = self.parent.attachNewNode( 'aspect2dMouseNode', sort = 999999 ) taskMgr.add( self.mouseNodeTask, 'mouseNodeTask' ) windowBorderTextures = list() for windowBorder in windowBorderTextureFiles: if windowBorder is not None: mdlFile = loader.loadTexture(windowBorder) windowBorderTextures.append(mdlFile) else: windowBorderTextures.append(None) windowBorderGeoms = list() for windowGeom in windowBorderGeomFiles: if windowGeom is not None: mdlFile = loader.loadModel(windowGeom) mdls = ( mdlFile.find('**/**-default'), mdlFile.find('**/**-click'), mdlFile.find('**/**-rollover'), mdlFile.find('**/**-disabled') ) windowBorderGeoms.append(mdls) else: windowBorderGeoms.append((None,None,None,None,),) # the main window we want to move around self.parentWindow = DirectFrame( parent=self.parent, pos=(self.windowPos[0], 0, self.windowPos[1]), #frameSize=# is defined in resize scale=(1, 1, -1), frameColor=bgColor, borderWidth=(0, 0), relief=DGG.FLAT, sortOrder=1, ) # header of the window (drag&drop with it) # the title part of the window, drag around to move the window self.headerParent = DirectButton( parent=self.parentWindow, pos=(0, 0, 0), #frameSize=# is defined in resize scale=(1, 1, self.dragbarSize), frameColor=(1, 1, 1, 1), borderWidth=(0, 0), relief=DGG.FLAT, ) self.headerParent.bind(DGG.B1PRESS,self.startWindowDrag) # images in the headerParent self.headerCenter = DirectFrame( parent=self.headerParent, pos=(0, 0, 1), #frameSize=# is defined in resize scale=(1,1,-1), frameColor=windowColors[1], frameTexture=windowBorderTextures[1], borderWidth=(0, 0), relief=DGG.FLAT, ) self.headerLeft = DirectFrame( parent=self.headerParent, pos=(0, 0, 1), frameSize=(0, self.dragbarSize, 0, 1), scale=(1,1,-1), frameColor=windowColors[0], frameTexture=windowBorderTextures[0], borderWidth=(0, 0), relief=DGG.FLAT, ) # collapse button self.headerRight = DirectButton( parent=self.headerParent, #pos=# is defined in resize frameSize=(0, self.dragbarSize, 0, 1), scale=(1,1,-1), frameColor=windowColors[2], #frameTexture=windowBorderTextures[2], borderWidth=(0, 0), relief=DGG.FLAT, command=self.toggleCollapsed, geom=windowBorderGeoms[0], geom_scale=(self.dragbarSize,1,1) ) # the resize button of the window self.resizeButton = DirectButton( parent=self.parentWindow, pos=(1-self.dragbarSize, 0, 1), frameSize=(0, 1, 0, 1), scale=(self.dragbarSize,1,-self.dragbarSize), frameColor=windowColors[3], frameTexture=windowBorderTextures[3], borderWidth=(0, 0), relief=DGG.FLAT, sortOrder=1, ) self.resizeButton.bind(DGG.B1PRESS,self.startResizeDrag) # text in the center of the window text = TextNode('WindowTitleTextNode') text.setText(title) text.setAlign(TextNode.ACenter) text.setTextColor( 0, 0, 0, 1 ) text.setShadow(0.05, 0.05) text.setShadowColor( 1, 1, 1, 1 ) self.textNodePath = self.headerCenter.attachNewNode(text) self.textNodePath.setPos(.5,0,.3) self.textNodePath.setScale(0.8*self.dragbarSize,1,0.8) if Y_INVERTED: scale = (1,1,-1) else: scale = (1,1,1) # the content part of the window, put stuff beneath # contentWindow.getCanvas() to put it into it self.contentWindow = DirectScrolledFrame( parent = self.parentWindow, #pos = # is defined in resize scale = scale, canvasSize = (0,self.virtualSize[0],0,self.virtualSize[1]), frameColor = buttonColor, relief = DGG.RAISED, borderWidth = (0,0), verticalScroll_frameSize = [0,self.dragbarSize,0,1], verticalScroll_frameTexture = loader.loadTexture( 'rightBorder.png' ), verticalScroll_incButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), verticalScroll_decButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), verticalScroll_thumb_frameTexture = loader.loadTexture( 'scrollBar.png' ), horizontalScroll_frameSize = [0,1,0,self.dragbarSize], horizontalScroll_frameTexture = loader.loadTexture( 'bottomBorder.png' ), horizontalScroll_incButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), horizontalScroll_decButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), horizontalScroll_thumb_frameTexture = loader.loadTexture( 'scrollBar.png' ), ) # child we attach should be inside the window DirectFrame.__init__( self, parent = self.contentWindow.getCanvas(), pos = (0,0,self.virtualSize[1]), scale = (1,1,1), frameSize = ( 0, self.virtualSize[0]+2*self.borderSize, 0, self.virtualSize[1] ), #frameColor = (0,0,0,1), relief = DGG.RIDGE, borderWidth = (0,0), ) self.initialiseoptions(DirectWindow) # offset then clicking on the resize button from the mouse to the resizebutton # position, required to calculate the position / scaling self.offset = None self.resizeButtonTaskName = "resizeTask-%s" % str(hash(self)) # do sizing of the window to virtualSize #self.resize( self.virtualSize[0]+2*self.borderSize # , self.virtualSize[1]+self.dragbarSize+2*self.borderSize ) self.resize(10,10) # a task that keeps a node at the position of the mouse-cursor def mouseNodeTask(self, task): if WindowManager.hasMouse(): x=WindowManager.getMouseX() y=WindowManager.getMouseY() # the mouse position is read relative to render2d, so set it accordingly self.mouseNode.setPos( render2d, x, 0, y ) return task.cont # dragging functions def startWindowDrag( self, param ): self.parentWindow.wrtReparentTo( self.mouseNode ) self.ignoreAll() self.accept( 'mouse1-up', self.stopWindowDrag ) def stopWindowDrag( self, param=None ): # this could be called even after the window has been destroyed #if self: # this is called 2 times (bug), so make sure it's not already parented to aspect2d if self.parentWindow.getParent() != self.parent: self.parentWindow.wrtReparentTo(self.parent) self.ignoreAll() # resize functions def startResizeDrag(self, param): self.offset = self.resizeButton.getPos(aspect2d) - self.mouseNode.getPos(aspect2d) taskMgr.remove( self.resizeButtonTaskName ) taskMgr.add( self.resizeButtonTask, self.resizeButtonTaskName ) self.accept( 'mouse1-up', self.stopResizeDrag,['x'] ) def resize(self,windowX,windowY): # limit max/min size of the window maxX = min(self.maxWindowSize[0], self.virtualSize[0]+2*self.borderSize) minX = max( self.dragbarSize*3, self.minWindowSize[0]) windowWidth = min( maxX, max( minX, windowX ) ) maxY = min( self.maxWindowSize[1], self.virtualSize[1]+self.dragbarSize+2*self.borderSize ) minY = max( self.dragbarSize*4, self.minWindowSize[1]) windowHeight = min( maxY, max( minY, windowY ) ) if self.collapsed: windowHeight = 2*self.dragbarSize+2*self.borderSize windowWidth = windowWidth self.contentWindow.hide() # store changed window width only self.previousSize = windowWidth, self.previousSize[1] else: self.contentWindow.show() self.previousSize = windowWidth, windowHeight # set the window size self.headerParent['frameSize'] = (0, windowWidth, 0, 1) self.headerCenter['frameSize'] = (0, windowWidth, 0, 1) self.parentWindow['frameSize'] = (0, windowWidth, 0, windowHeight) self.contentWindow['frameSize'] = (0, windowWidth-self.borderSize*2, 0, windowHeight-self.dragbarSize-2*self.borderSize) self.contentWindow.setPos(self.borderSize,0,windowHeight-self.borderSize) self.headerRight.setPos(windowWidth-self.dragbarSize, 0, 1) self.textNodePath.setPos(windowWidth/2.,0,.3) self.resizeButton.setPos(windowWidth-self.dragbarSize, 0, windowHeight) def resizeButtonTask(self, task=None): mPos = self.mouseNode.getPos(self.parentWindow) # max height, the smaller of (given maxWindowSize and real size of content and borders windowX = mPos.getX() + self.offset.getX() + self.dragbarSize windowY = mPos.getZ() - self.offset.getZ() self.resize(windowX,windowY) return task.cont def stopResizeDrag(self, param): taskMgr.remove( self.resizeButtonTaskName ) self.ignoreAll() # a bugfix for a wrong implementation def detachNode( self ): self.parentWindow.detachNode() #self. = None #DirectFrame.detachNode( self ) def removeNode( self ): self.parentWindow.removeNode() #DirectFrame.removeNode( self ) def toggleCollapsed(self,state=None): if state is None: state=not self.collapsed if state: self.collapse() else: self.uncollapse() def collapse(self): self.collapsed = True self.resize(*self.previousSize) def uncollapse(self): self.collapsed = False self.resize(*self.previousSize)