def setScale(self, *args, **kwargs): DirectFrame.setScale(self, *args, **args) self.resetArcBall()
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 QuestPoster(DirectFrame): notify = directNotify.newCategory('QuestPoster') # We need to declare and initialize these variables here # because some methods use them as default arguments. auxIcon = None # Requires one parameter, quest, this must be a Quest instance. # The next argument, parent, is where to reparent the DirectFrame to. # The next arguments are simply additional options when setting up the DirectFrame. def __init__(self, quest, parent=aspect2d, **kw): # The quest this poster is representing. self.quest = quest self.accessibleObjectives = quest.accessibleObjectives if quest else [] self.viewObjective = quest.accessibleObjectives.seek( ) if quest else None isObjComplete = False if not quest else ( self.accessibleObjectives.isComplete() or quest.isComplete()) # Let's define our options for the DirectFrame. bookModel = loader.loadModel( 'phase_3.5/models/gui/stickerbook_gui.bam') optiondefs = (('relief', None, None), ('image', bookModel.find('**/questCard'), None), ('image_scale', (0.8, 1.0, 0.58), None), ('image_color', (1.0, 1.0, 1.0, 1.0) if not isObjComplete else Vec4( *QuestGlobals.LIGHT_GREEN), None), ('state', DGG.NORMAL, None)) self.defineoptions(kw, optiondefs) # Finally, initialize the DirectFrame. DirectFrame.__init__(self, parent, relief=None) self.initialiseoptions(QuestPoster) # Let's declare and initialize our barebone GUI element variables. questTitle = '' if not self.quest else self.quest.name self.titleLabel = DirectLabel(parent=self, relief=None, text=questTitle, text_font=CIGlobals.getMinnieFont(), text_fg=QuestGlobals.TEXT_COLOR, text_scale=0.05, text_align=TextNode.ACenter, text_wordwrap=25.0, textMayChange=1, pos=(0, 0, 0.23)) ########################################################################## # THE FOLLOWING ELEMENTS BELOW ARE GROUPED TOGETHER # ########################################################################## # The background frame where the objective image is displayed. # This is the colored background frame. circleGui = loader.loadModel( 'phase_4/models/gui/CircleIconBackgroundGui.bam') self.auxFrame = DirectFrame( parent=self, relief=None, image=circleGui.find('**/circle_display_interior'), image_scale=0.18, text='', text_pos=(0, -0.11), text_fg=QuestGlobals.TEXT_COLOR, text_scale=QuestGlobals.QPtextScale, text_align=TextNode.ACenter, text_wordwrap=11.0, pos=QuestGlobals.DEFAULT_LEFT_PICTURE_POS) if self.quest and len( self.quest.accessibleObjectives) > 1 and not isObjComplete: # We can only use arrows when we have more than one objective available. arrowGui = loader.loadModel('phase_4/models/gui/QuestArrowGui.bam') self.prevObjArrow = DirectButton( parent=self.auxFrame, relief=None, geom=((arrowGui.find('**/quest_arrow_enabled'), arrowGui.find('**/quest_arrow_click'), arrowGui.find('**/quest_arrow_mouseover'), arrowGui.find('**/quest_arrow_disabled'))), scale=0.08, command=self.switchObjective, extraArgs=[0], hpr=(180, 0, 0), pos=QuestGlobals.DEFAULT_LEFT_ARROW_POS) self.nextObjArrow = DirectButton( parent=self.auxFrame, relief=None, geom=((arrowGui.find('**/quest_arrow_enabled'), arrowGui.find('**/quest_arrow_click'), arrowGui.find('**/quest_arrow_mouseover'), arrowGui.find('**/quest_arrow_disabled'))), scale=0.08, command=self.switchObjective, pos=QuestGlobals.DEFAULT_RIGHT_ARROW_POS) # The icon that goes on top of the aux frame. self.auxIcon = DirectFrame(parent=self.auxFrame, relief=None, text=' ', text_font=CIGlobals.getSuitFont(), text_pos=(0, -0.03), text_fg=QuestGlobals.TEXT_COLOR, text_scale=0.13, text_align=TextNode.ACenter, text_wordwrap=13.0, textMayChange=1) self.auxIcon.setColorOff(-1) self.auxOutline = DirectLabel( parent=self.auxFrame, relief=None, image=circleGui.find('**/circle_display_outline'), image_scale=0.18) # The aux text saying: DEFEAT, RECOVER, etc. self.auxText = DirectLabel(parent=self, relief=None, text=QuestGlobals.RECOVER, text_font=CIGlobals.getToonFont(), text_scale=QuestGlobals.QPauxText, text_fg=QuestGlobals.TEXT_COLOR, text_align=TextNode.ACenter, textMayChange=1, pos=QuestGlobals.DEFAULT_AUX_POS) self.auxText.hide() ########################################################################## # Information displayed about the objective. self.objectiveInfo = DirectLabel( parent=self, relief=None, text='', text_font=CIGlobals.getToonFont(), text_fg=QuestGlobals.TEXT_COLOR, text_scale=0.04, text_align=TextNode.ACenter, text_wordwrap=QuestGlobals.QPtextWordwrap, textMayChange=1, pos=(QuestGlobals.DEFAULT_INFO_POS)) self.objectiveInfo.hide() # Information displayed showing the location. self.locationInfo = DirectLabel( parent=self, relief=None, text='N/A', text_font=CIGlobals.getToonFont(), text_fg=QuestGlobals.TEXT_COLOR, text_scale=QuestGlobals.QPtextScale, text_align=TextNode.ACenter, text_wordwrap=QuestGlobals.QPtextWordwrap, textMayChange=1, pos=(0, 0, -0.115)) self.locationInfo.hide() # The progress bar showing the objective's progress self.progressBar = DirectWaitBar(parent=self, relief=DGG.SUNKEN, frameSize=(-0.95, 0.95, -0.1, 0.12), borderWidth=(0.025, 0.025), scale=0.2, frameColor=(0.945, 0.875, 0.706, 1.0), barColor=(0.5, 0.7, 0.5, 1), text='0/0', text_font=CIGlobals.getToonFont(), text_scale=0.19, text_fg=(0.05, 0.14, 0.4, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05), pos=(0, 0, -0.2425)) self.progressBar.hide() # The wood panel at the bottom where rewards are displayed. rewardFrameGeom = loader.loadModel( 'phase_4/models/gui/gag_shop_purchase_gui.bam') self.rewardFrame = DirectFrame( parent=self, relief=None, geom=rewardFrameGeom.find('**/Goofys_Sign'), geom_scale=(0.62, 0, 0.4), pos=(-0.015, 0, -0.25)) # Let's setup our reward frames. reward = None if self.quest and len(self.quest.rewards) > 0: reward = self.quest.rewards[0] self.lReward = QuestRewardFrame(self, reward) # The text displayed on the right side of the frame with additional information, if necessary. self.sideInfo = DirectLabel(parent=self, relief=None, text=QuestGlobals.JUST_FOR_FUN, text_fg=(0.0, 0.439, 1.0, 1.0), text_shadow=(0, 0, 0, 1), pos=(-0.2825, 0, 0.2), scale=0.03) self.sideInfo.setR(-30) # This side information is usually not needed, let's hide it. self.sideInfo.hide() # Remove the nodes of the loaded models we no longer need. circleGui.removeNode() bookModel.removeNode() rewardFrameGeom.removeNode() # We are only removing this node if we generated arrows. if hasattr(self, 'arrowGui'): arrowGui.removeNode() # Let's hide this until it is needed. self.hide() return def switchObjective(self, forward=1): if forward: self.accessibleObjectives.nextObjective() else: self.accessibleObjectives.lastObjective() self.viewObjective = self.accessibleObjectives.seek() self.setup() def setup(self): if self.quest: objective = self.viewObjective complete = self.accessibleObjectives.isComplete() # Let's reset our positioning of elements. self.auxFrame.setPos(QuestGlobals.DEFAULT_LEFT_PICTURE_POS) self.auxText.setPos(QuestGlobals.DEFAULT_AUX_POS) self.objectiveInfo.setPos(QuestGlobals.DEFAULT_INFO_POS) # Let's reset our icon. self.auxIcon.setScale(1, 1, 1) self.auxIcon.setPos(0, 0, 0) self.auxIcon.setHpr(0, 0, 0) self.objectiveInfo.show() self.auxFrame.show() # Let's setup the quest progress bar progress = objective.progress if hasattr(objective, 'progress') else None if objective.goal > 1: self.progressBar['range'] = objective.goal self.progressBar['value'] = progress & pow(2, 16) - 1 if objective.HasProgress and objective.goal > 1 and not complete: self.progressBar.show() self.auxText.show() # Let's handle the objectives. if not complete: if objective.__class__ == CogObjective: self.handleCogObjective() elif objective.__class__ == CogBuildingObjective: self.handleCogBuildingObjective() elif objective.__class__ == MinigameObjective: self.handleMinigameObjective() elif objective.__class__ == VisitNPCObjective: self.handleNPCObjective() else: bgColor = QuestGlobals.RED if objective.type in DefeatObjectives: bgColor = QuestGlobals.BLUE self.handleNPCObjective(auxText=QuestGlobals.RETURN + ' to', frameColor=bgColor) self.lReward.setup() newLineInObjInfo = '\n' in self.objectiveInfo['text'] isShopLoc = QuestGlobals.isShopLocation( objective.area) if not complete else True if complete: locationText = QuestGlobals.getLocationText(None, objective) else: locationText = QuestGlobals.getLocationText(objective.area) self.locationInfo['text'] = locationText self.locationInfo['text_pos'] = (0.0, (0.025 if isShopLoc else ( -0.025 if newLineInObjInfo else 0.0))) self.locationInfo.show() else: # We want to be able to show empty quest posters. self.titleLabel.hide() self.auxFrame.hide() self.auxIcon.hide() self.titleLabel.initialiseoptions(DirectLabel) self.auxIcon.initialiseoptions(DirectFrame) self.auxText.initialiseoptions(DirectLabel) self.objectiveInfo.initialiseoptions(DirectLabel) self.locationInfo.initialiseoptions(DirectLabel) self.rewardFrame.initialiseoptions(DirectFrame) self.sideInfo.initialiseoptions(DirectLabel) self.lReward.initialiseoptions(DirectFrame) # Handle arrow stuff if necessary. if hasattr(self, 'prevObjArrow'): index = self.accessibleObjectives.seeker self.prevObjArrow['state'] = DGG.NORMAL self.nextObjArrow['state'] = DGG.NORMAL self.prevObjArrow.setPos(QuestGlobals.DEFAULT_LEFT_ARROW_POS) self.nextObjArrow.setPos(QuestGlobals.DEFAULT_RIGHT_ARROW_POS) if index == 0: self.prevObjArrow['state'] = DGG.DISABLED elif index == len(self.accessibleObjectives) - 1: self.nextObjArrow['state'] = DGG.DISABLED self.prevObjArrow.initialiseoptions(DirectButton) self.nextObjArrow.initialiseoptions(DirectButton) # Changes geometry and scale of an icon. def handleSimpleIcon(self, geom, scale, icon): icon['geom'] = geom icon['geom_scale'] = scale def handleComplexIcon(self, geom, icon, scale=QuestGlobals.IMAGE_SCALE_SMALL): geom.setDepthWrite(1) geom.setDepthTest(1) self.fitGeometry(geom, fFlip=1) self.handleSimpleIcon(geom, scale, icon) # We have to rotate the head and set the scale of the icon. if CIGlobals.Suit in geom.getName(): cogName = geom.getPythonTag('Settings') data = QuestGlobals.Suit2PosterZNDScale.get(cogName) zOffset = data[0] headScale = data[1] icon.setScale(headScale) icon.setZ(icon.getZ() + zOffset) icon.setH(180) else: icon.setZ(icon.getZ() - 0.01) def handleCogObjective(self, iconElement=auxIcon, auxText=QuestGlobals.DEFEAT, frameColor=QuestGlobals.BLUE): objective = self.viewObjective infoText = objective.getTaskInfo() if objective.__class__ == RecoverItemObjective: infoText = CIGlobals.makePlural(objective.cog) if not iconElement: iconElement = self.auxIcon # Let's make sure we have a current objective that is # an instance of the CogObjective class and this poster isn't destroyed. if not objective or not hasattr(self, 'titleLabel') or not isinstance( objective, CogObjective): return if objective.dept: icons = loader.loadModel('phase_3/models/gui/cog_icons.bam') deptIcon = None if objective.dept == Dept.BOSS: deptIcon = icons.find('**/CorpIcon') else: deptIcon = icons.find('**/%sIcon' % objective.dept.getTie().title()) # Correct the medallion color. deptIcon.setColor(SuitGlobals.medallionColors[objective.dept]) # Setup the icon and remove the icons node. self.handleSimpleIcon(deptIcon, 0.13, iconElement) icons.removeNode() elif objective.cog == QuestGlobals.Any: # We aren't fighting a Cog in particular. cogIcon = QuestGlobals.getCogIcon() self.handleSimpleIcon(cogIcon, 0.13, iconElement) # We're fighting a Cog in particular. if not objective.cog == QuestGlobals.Any: cogHeadInstance = SuitBank.getSuitByName(objective.cog).getHead() cogHead = cogHeadInstance.generate() cogHead.setName('%sHead' % CIGlobals.Suit) cogHead.setPythonTag('Settings', cogHeadInstance.head) cogHead.setScale(2) cogHead.setLightOff() self.handleComplexIcon(cogHead, iconElement) # HACK FIX: Corrects the buggy Flunky glasses. glasses = cogHead.find('**/glasses') if glasses and not glasses.isEmpty(): glasses.setScale(1) glasses.reparentTo(cogHead) if not iconElement is self.auxIcon: if hasattr(self, 'goalInfo'): # We're working with the second frame, on the right. # Let's update the information pertaining to this side. self.goalInfo['text'] = infoText self.goalInfo.setPos(QuestGlobals.RECOVER_INFO2_POS) self.auxText.setPos(QuestGlobals.RECOVER_AUX_POS) else: raise AttributeError( 'Attempted to setup DoubleFrame information for poster using default style.' ) else: self.objectiveInfo['text'] = infoText # Let's set the progress bar text pgBarText = '%d of %d %s' % (objective.progress, objective.goal, CIGlobals.makePastTense(auxText)) self.progressBar['text'] = pgBarText self.auxText['text'] = auxText # Let's set the color of the poster. frame = self.auxFrame if iconElement is self.auxIcon else self.goalFrame frame['image_color'] = Vec4(*frameColor) def handleCogBuildingObjective(self, iconElement=auxIcon, auxText=QuestGlobals.DEFEAT, frameColor=QuestGlobals.BLUE): objective = self.viewObjective infoText = objective.getTaskInfo() if not iconElement: iconElement = self.auxIcon # Let's make sure we have a current objective that is # an instance of the CogBuildingObjective class and this poster isn't destroyed. if not objective or not hasattr(self, 'titleLabel') or not isinstance( objective, CogBuildingObjective): return # If we aren't looking for any specific department of building. if objective.dept == QuestGlobals.Any: # Let's just use the good ol' generic building icon. self.handleSimpleIcon(QuestGlobals.getCogBuildingIcon(), QuestGlobals.SIMPLE_IMAGE_SCALE, iconElement) else: # Ah geez, we're looking for a specific department. # Bossbot tie names are messed up, so we need this if statement. dept = objective.dept.getTie( ) if not objective.dept == Dept.BOSS else 'corp' bldgMdl = loader.loadModel( 'phase_4/models/modules/suit_landmark_%s.bam' % dept) # Next, we need to load the building elevator. elevator = loader.loadModel('phase_4/models/modules/elevator.bam') elevator.reparentTo(bldgMdl.find('**/*_door_origin')) self.handleComplexIcon(bldgMdl, iconElement) # Let's set the progress bar text pgBarText = '%d of %d %s' % (objective.progress, objective.goal, CIGlobals.makePastTense(auxText)) self.progressBar['text'] = pgBarText self.objectiveInfo['text'] = infoText self.auxText['text'] = auxText self.auxFrame['image_color'] = Vec4(*frameColor) def handleMinigameObjective(self, iconElement=auxIcon, auxText=QuestGlobals.PLAY, frameColor=QuestGlobals.RED): objective = self.viewObjective infoText = objective.getTaskInfo() if not iconElement: iconElement = self.auxIcon # Let's make sure we have a current objective that is # an instance of the MinigameObjective class and this poster isn't destroyed. if not objective or not hasattr(self, 'titleLabel') or not isinstance( objective, MinigameObjective): return # Let's set the icon to the minigame icon. self.handleSimpleIcon(QuestGlobals.getTrolleyIcon(), QuestGlobals.SIMPLE_IMAGE_SCALE, iconElement) # Let's set the progress bar text pgBarText = '%d of %d %s' % (objective.progress, objective.goal, CIGlobals.makePastTense(auxText)) self.progressBar['text'] = pgBarText self.objectiveInfo['text'] = infoText self.auxText['text'] = auxText self.auxFrame['image_color'] = Vec4(*frameColor) def handleNPCObjective(self, iconElement=auxIcon, auxText=QuestGlobals.VISIT, frameColor=QuestGlobals.BROWN): objective = self.viewObjective npcId = 0 if self.accessibleObjectives.isComplete() and not hasattr( objective, 'npcId'): npcId = objective.assigner elif hasattr(objective, 'npcId'): npcId = objective.npcId if npcId == 0: infoText = 'A %s' % NPCGlobals.lHQOfficerF else: infoText = NPCGlobals.NPCToonNames[npcId] if not iconElement: iconElement = self.auxIcon # Let's generate the head. if not npcId == 0: dna = ToonDNA() dna.setDNAStrand(NPCGlobals.NPCToonDict.get(npcId)[2]) head = ToonGlobals.generateGuiHead(dna) self.handleComplexIcon(head, iconElement, scale=QuestGlobals.IMAGE_SCALE_SMALL - 0.01) else: self.handleSimpleIcon(QuestGlobals.getHQIcon(), QuestGlobals.SIMPLE_IMAGE_SCALE, iconElement) self.auxText['text'] = auxText if not iconElement is self.auxIcon: if hasattr(self, 'goalInfo'): # We're working with the second frame, on the right. # Let's update the information pertaining to this side. self.goalInfo['text'] = infoText self.goalInfo.setPos(QuestGlobals.RECOVER_INFO2_POS) self.auxText.setPos(QuestGlobals.RECOVER_AUX_POS) self.goalFrame['image_color'] = frameColor else: raise AttributeError( 'Attempted to setup DoubleFrame information for poster using default style.' ) else: self.objectiveInfo['text'] = infoText self.auxFrame['image_color'] = frameColor def fitGeometry(self, geom, fFlip=0, dimension=0.8): p1 = Point3() p2 = Point3() geom.calcTightBounds(p1, p2) if fFlip: t = p1[0] p1.setX(-p2[0]) p2.setX(-t) d = p2 - p1 biggest = max(d[0], d[2]) s = dimension / biggest mid = (p1 + d / 2.0) * s geomXform = hidden.attachNewNode('geomXform') for child in geom.getChildren(): child.reparentTo(geomXform) geomXform.setPosHprScale(-mid[0], -mid[1] + 1, -mid[2], 180, 0, 0, s, s, s) geomXform.reparentTo(geom) def destroy(self): if hasattr(self, 'titleLabel'): self.titleLabel.destroy() self.auxFrame.destroy() self.auxIcon.destroy() self.auxOutline.destroy() self.auxText.destroy() self.objectiveInfo.destroy() self.locationInfo.destroy() self.progressBar.destroy() self.rewardFrame.destroy() self.sideInfo.destroy() self.lReward.destroy() # We need to cleanup our arrows if they were created. if hasattr(self, 'prevObjArrow'): self.prevObjArrow.destroy() self.nextObjArrow.destroy() del self.prevObjArrow del self.nextObjArrow del self.titleLabel del self.auxFrame del self.auxIcon del self.auxOutline del self.auxText del self.objectiveInfo del self.locationInfo del self.progressBar del self.rewardFrame del self.sideInfo del self.lReward del self.accessibleObjectives del self.viewObjective DirectFrame.destroy(self) self.notify.debug('Destroyed all elements.')
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 Transitions: # These may be reassigned before the fade or iris transitions are # actually invoked to change the models that will be used. IrisModelName = "models/misc/iris" FadeModelName = "models/misc/fade" def __init__(self, loader, model=None, scale=3.0, pos=Vec3(0, 0, 0)): self.transitionIval = None self.__transitionFuture = None self.letterboxIval = None self.__letterboxFuture = None self.iris = None self.fade = None self.letterbox = None self.fadeModel = model self.imagePos = pos if model: self.alphaOff = Vec4(1, 1, 1, 0) self.alphaOn = Vec4(1, 1, 1, 1) model.setTransparency(1) self.lerpFunc = LerpColorScaleInterval else: self.alphaOff = Vec4(0, 0, 0, 0) self.alphaOn = Vec4(0, 0, 0, 1) self.lerpFunc = LerpColorInterval self.irisTaskName = "irisTask" self.fadeTaskName = "fadeTask" self.letterboxTaskName = "letterboxTask" def __del__(self): if self.fadeModel: self.fadeModel.removeNode() self.fadeModel = None ################################################## # Fade ################################################## # We can set a custom model for the fade before using it for the first time def setFadeModel(self, model, scale=1.0): self.fadeModel = model # We have to change some default parameters for a custom fadeModel self.alphaOn = Vec4(1, 1, 1, 1) # Reload fade if its already been created if self.fade: self.fade.destroy() self.fade = None self.loadFade() def loadFade(self): if self.fade is None: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects # positioned behind it. self.fade = DirectFrame( parent = ShowBaseGlobal.hidden, guiId = 'fade', relief = None, image = self.fadeModel, image_scale = (4, 2, 2), state = DGG.NORMAL, ) if not self.fadeModel: # No fade model was given, so we make this the fade model. self.fade["relief"] = DGG.FLAT self.fade["frameSize"] = (-2, 2, -1, 1) self.fade["frameColor"] = (0, 0, 0, 1) self.fade.setTransparency(TransparencyAttrib.MAlpha) self.fade.setBin('unsorted', 0) self.fade.setColor(0,0,0,0) self.fade.setScale(max(base.a2dRight, base.a2dTop)) def getFadeInIval(self, t=0.5, finishIval=None, blendType='noBlend'): """ Returns an interval without starting it. This is particularly useful in cutscenes, so when the cutsceneIval is escaped out of we can finish the fade immediately """ #self.noTransitions() masad: this creates a one frame pop, is it necessary? self.loadFade() transitionIval = Sequence(Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough), # in case aspect2d is hidden for some reason self.lerpFunc(self.fade, t, self.alphaOff, # self.alphaOn, blendType=blendType ), Func(self.fade.detachNode), name = self.fadeTaskName, ) if finishIval: transitionIval.append(finishIval) return transitionIval def getFadeOutIval(self, t=0.5, finishIval=None, blendType='noBlend'): """ Create a sequence that lerps the color out, then parents the fade to hidden """ self.noTransitions() self.loadFade() transitionIval = Sequence(Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough), # in case aspect2d is hidden for some reason self.lerpFunc(self.fade, t, self.alphaOn, # self.alphaOff, blendType=blendType ), name = self.fadeTaskName, ) if finishIval: transitionIval.append(finishIval) return transitionIval def fadeIn(self, t=0.5, finishIval=None, blendType='noBlend'): """ Play a fade in transition over t seconds. Places a polygon on the aspect2d plane then lerps the color from black to transparent. When the color lerp is finished, it parents the fade polygon to hidden. """ gsg = base.win.getGsg() if gsg: # If we're about to fade in from black, go ahead and # preload all the textures etc. base.graphicsEngine.renderFrame() render.prepareScene(gsg) render2d.prepareScene(gsg) if (t == 0): # Fade in immediately with no lerp #print "transitiosn: fadeIn 0.0" self.noTransitions() self.loadFade() self.fade.detachNode() fut = AsyncFuture() fut.setResult(None) return fut else: # Create a sequence that lerps the color out, then # parents the fade to hidden self.transitionIval = self.getFadeInIval(t, finishIval, blendType) self.transitionIval.append(Func(self.__finishTransition)) self.__transitionFuture = AsyncFuture() self.transitionIval.start() return self.__transitionFuture def fadeOut(self, t=0.5, finishIval=None, blendType='noBlend'): """ Play a fade out transition over t seconds. Places a polygon on the aspect2d plane then lerps the color from transparent to full black. When the color lerp is finished, it leaves the fade polygon covering the aspect2d plane until you fadeIn or call noFade. lerp """ if (t == 0): # Fade out immediately with no lerp self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn) elif ConfigVariableBool('no-loading-screen', False): if finishIval: self.transitionIval = finishIval self.transitionIval.start() else: # Create a sequence that lerps the color out, then # parents the fade to hidden self.transitionIval = self.getFadeOutIval(t, finishIval, blendType) self.transitionIval.append(Func(self.__finishTransition)) self.__transitionFuture = AsyncFuture() self.transitionIval.start() return self.__transitionFuture # Immediately done, so return a dummy future. fut = AsyncFuture() fut.setResult(None) return fut def fadeOutActive(self): return self.fade and self.fade.getColor()[3] > 0 def fadeScreen(self, alpha=0.5): """ Put a semitransparent screen over the camera plane to darken out the world. Useful for drawing attention to a dialog box for instance """ #print "transitiosn: fadeScreen" self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn[0], self.alphaOn[1], self.alphaOn[2], alpha) def fadeScreenColor(self, color): """ Put a semitransparent screen over the camera plane to darken out the world. Useful for drawing attention to a dialog box for instance """ #print "transitiosn: fadeScreenColor" self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(color) def noFade(self): """ Removes any current fade tasks and parents the fade polygon away """ #print "transitiosn: noFade" if self.transitionIval: self.transitionIval.pause() self.transitionIval = None if self.__transitionFuture: self.__transitionFuture.cancel() self.__transitionFuture = None if self.fade: # Make sure to reset the color, since fadeOutActive() is looking at it self.fade.setColor(self.alphaOff) self.fade.detachNode() def setFadeColor(self, r, g, b): self.alphaOn.set(r, g, b, 1) self.alphaOff.set(r, g, b, 0) ################################################## # Iris ################################################## def loadIris(self): if self.iris == None: self.iris = loader.loadModel(self.IrisModelName) self.iris.setPos(0, 0, 0) def irisIn(self, t=0.5, finishIval=None, blendType = 'noBlend'): """ Play an iris in transition over t seconds. Places a polygon on the aspect2d plane then lerps the scale of the iris polygon up so it looks like we iris in. When the scale lerp is finished, it parents the iris polygon to hidden. """ self.noTransitions() self.loadIris() if (t == 0): self.iris.detachNode() fut = AsyncFuture() fut.setResult(None) return fut else: self.iris.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) scale = 0.18 * max(base.a2dRight, base.a2dTop) self.transitionIval = Sequence(LerpScaleInterval(self.iris, t, scale = scale, startScale = 0.01, blendType=blendType), Func(self.iris.detachNode), Func(self.__finishTransition), name = self.irisTaskName, ) self.__transitionFuture = AsyncFuture() if finishIval: self.transitionIval.append(finishIval) self.transitionIval.start() return self.__transitionFuture def irisOut(self, t=0.5, finishIval=None, blendType='noBlend'): """ Play an iris out transition over t seconds. Places a polygon on the aspect2d plane then lerps the scale of the iris down so it looks like we iris out. When the scale lerp is finished, it leaves the iris polygon covering the aspect2d plane until you irisIn or call noIris. """ self.noTransitions() self.loadIris() self.loadFade() # we need this to cover up the hole. if (t == 0): self.iris.detachNode() self.fadeOut(0) fut = AsyncFuture() fut.setResult(None) return fut else: self.iris.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) scale = 0.18 * max(base.a2dRight, base.a2dTop) self.transitionIval = Sequence(LerpScaleInterval(self.iris, t, scale = 0.01, startScale = scale, blendType=blendType), Func(self.iris.detachNode), # Use the fade to cover up the hole that the iris would leave Func(self.fadeOut, 0), Func(self.__finishTransition), name = self.irisTaskName, ) self.__transitionFuture = AsyncFuture() if finishIval: self.transitionIval.append(finishIval) self.transitionIval.start() return self.__transitionFuture def noIris(self): """ Removes any current iris tasks and parents the iris polygon away """ if self.transitionIval: self.transitionIval.pause() self.transitionIval = None if self.iris != None: self.iris.detachNode() # Actually we need to remove the fade too, # because the iris effect uses it. self.noFade() def noTransitions(self): """ This call should immediately remove any and all transitions running """ self.noFade() self.noIris() # Letterbox is not really a transition, it is a screen overlay # self.noLetterbox() def __finishTransition(self): if self.__transitionFuture: self.__transitionFuture.setResult(None) self.__transitionFuture = None ################################################## # Letterbox ################################################## def loadLetterbox(self): if not self.letterbox: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects # positioned behind it. self.letterbox = NodePath("letterbox") # Allow fade in and out of the bars self.letterbox.setTransparency(1) # Allow DirectLabels to be parented to the letterbox sensibly self.letterbox.setBin('unsorted', 0) # Allow a custom look to the letterbox graphic. # TODO: This model isn't available everywhere. We should # pass it in as a parameter. button = loader.loadModel('models/gui/toplevel_gui', okMissing = True) barImage = None if button: barImage = button.find('**/generic_button') self.letterboxTop = DirectFrame( parent = self.letterbox, guiId = 'letterboxTop', relief = DGG.FLAT, state = DGG.NORMAL, frameColor = (0, 0, 0, 1), borderWidth = (0, 0), frameSize = (-1, 1, 0, 0.2), pos = (0, 0, 1.0), image = barImage, image_scale = (2.25,1,.5), image_pos = (0,0,.1), image_color = (0.3,0.3,0.3,1), sortOrder = 0, ) self.letterboxBottom = DirectFrame( parent = self.letterbox, guiId = 'letterboxBottom', relief = DGG.FLAT, state = DGG.NORMAL, frameColor = (0, 0, 0, 1), borderWidth = (0, 0), frameSize = (-1, 1, 0, 0.2), pos = (0, 0, -1.2), image = barImage, image_scale = (2.25,1,.5), image_pos = (0,0,.1), image_color = (0.3,0.3,0.3,1), sortOrder = 0, ) # masad: always place these at the bottom of render self.letterboxTop.setBin('sorted',0) self.letterboxBottom.setBin('sorted',0) self.letterbox.reparentTo(render2d, -1) self.letterboxOff(0) def noLetterbox(self): """ Removes any current letterbox tasks and parents the letterbox polygon away """ if self.letterboxIval: self.letterboxIval.pause() self.letterboxIval = None if self.__letterboxFuture: self.__letterboxFuture.cancel() self.__letterboxFuture = None if self.letterbox: self.letterbox.stash() def __finishLetterbox(self): if self.__letterboxFuture: self.__letterboxFuture.setResult(None) self.__letterboxFuture = None def letterboxOn(self, t=0.25, finishIval=None, blendType='noBlend'): """ Move black bars in over t seconds. """ self.noLetterbox() self.loadLetterbox() self.letterbox.unstash() if (t == 0): self.letterboxBottom.setPos(0, 0, -1) self.letterboxTop.setPos(0, 0, 0.8) fut = AsyncFuture() fut.setResult(None) return fut else: self.__letterboxFuture = AsyncFuture() self.letterboxIval = Sequence(Parallel( LerpPosInterval(self.letterboxBottom, t, pos = Vec3(0, 0, -1), #startPos = Vec3(0, 0, -1.2), blendType=blendType ), LerpPosInterval(self.letterboxTop, t, pos = Vec3(0, 0, 0.8), # startPos = Vec3(0, 0, 1), blendType=blendType ), ), Func(self.__finishLetterbox), name = self.letterboxTaskName, ) if finishIval: self.letterboxIval.append(finishIval) self.letterboxIval.start() return self.__letterboxFuture def letterboxOff(self, t=0.25, finishIval=None, blendType='noBlend'): """ Move black bars away over t seconds. """ self.noLetterbox() self.loadLetterbox() self.letterbox.unstash() if (t == 0): self.letterbox.stash() fut = AsyncFuture() fut.setResult(None) return fut else: self.__letterboxFuture = AsyncFuture() self.letterboxIval = Sequence(Parallel( LerpPosInterval(self.letterboxBottom, t, pos = Vec3(0, 0, -1.2), # startPos = Vec3(0, 0, -1), blendType=blendType ), LerpPosInterval(self.letterboxTop, t, pos = Vec3(0, 0, 1), # startPos = Vec3(0, 0, 0.8), blendType=blendType ), ), Func(self.letterbox.stash), Func(self.__finishLetterbox), Func(messenger.send,'letterboxOff'), name = self.letterboxTaskName, ) if finishIval: self.letterboxIval.append(finishIval) self.letterboxIval.start() return self.__letterboxFuture
class OptionsPage(BookPage): notify = directNotify.newCategory("OptionsPage") # Keys are categories and values are x-positions for the text. Categories = OrderedDict() Categories[AboutCategory] = 0.09 Categories[GeneralCategory] = 0.07 Categories[ControlsCategory] = 0.05 Categories[SoundCategory] = 0.0825 Categories[DisplayCategory] = 0.07 Categories[AdvancedDisplayCategory] = 0.05 def __init__(self, book): BookPage.__init__(self, book, "Options") self.currentCategory = None self.tabs = [] def load(self): BookPage.load(self) icons = loader.loadModel('phase_3.5/models/gui/sos_textures.bam') self.icon = icons.find('**/switch') icons.detachNode() def enter(self): BookPage.enter(self) self.tabScaleFrame = DirectFrame(parent=self.book) self.tabScaleFrame.setZ(0.7683) self.tabsFrame = DirectFrame(parent=self.tabScaleFrame) tabWidth = 0.379136800766 spacing = 0.075 totalWidth = 0.0 bookWidth = 2.0 for i in xrange(len(self.Categories.keys())): if i > 0: totalWidth += spacing totalWidth += tabWidth cl = self.Categories.keys()[i] tab = CategoryTab(self, cl.Name, [cl], ((tabWidth + spacing) * i, 0, 0), self.Categories.values()[i]) self.tabs.append(tab) self.tabsFrame.setX(totalWidth / -2.0) self.tabScaleFrame.setScale(min(1.0, 1.0 / (totalWidth / bookWidth))) self.pickCategory(AboutCategory) def closeWindow(self): if self.currentCategory: self.currentCategory.cleanup() self.currentCategory = None def pickCategory(self, cat): if self.currentCategory: self.currentCategory.cleanup() self.currentCategory = None self.currentCategory = cat(self) for tab in self.tabs: if tab['extraArgs'][0] is cat: tab['state'] = DGG.DISABLED else: tab['state'] = DGG.NORMAL #self.currentCategory.show() def exit(self): if self.currentCategory: self.currentCategory.cleanup() self.currentCategory = None for tab in self.tabs: tab.destroy() self.tabsFrame.destroy() del self.tabsFrame self.tabScaleFrame.destroy() del self.tabScaleFrame self.tabs = [] BookPage.exit(self)
class Transitions: # These may be reassigned before the fade or iris transitions are # actually invoked to change the models that will be used. IrisModelName = "models/misc/iris" FadeModelName = "models/misc/fade" def __init__(self, loader, model=None, scale=3.0, pos=Vec3(0, 0, 0)): self.transitionIval = None self.__transitionFuture = None self.letterboxIval = None self.__letterboxFuture = None self.iris = None self.fade = None self.letterbox = None self.fadeModel = model self.imagePos = pos if model: self.alphaOff = Vec4(1, 1, 1, 0) self.alphaOn = Vec4(1, 1, 1, 1) model.setTransparency(1) self.lerpFunc = LerpColorScaleInterval else: self.alphaOff = Vec4(0, 0, 0, 0) self.alphaOn = Vec4(0, 0, 0, 1) self.lerpFunc = LerpColorInterval self.irisTaskName = "irisTask" self.fadeTaskName = "fadeTask" self.letterboxTaskName = "letterboxTask" def __del__(self): if self.fadeModel: self.fadeModel.removeNode() self.fadeModel = None ################################################## # Fade ################################################## # We can set a custom model for the fade before using it for the first time def setFadeModel(self, model, scale=1.0): self.fadeModel = model # We have to change some default parameters for a custom fadeModel self.alphaOn = Vec4(1, 1, 1, 1) # Reload fade if its already been created if self.fade: self.fade.destroy() self.fade = None self.loadFade() def loadFade(self): if self.fade is None: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects # positioned behind it. self.fade = DirectFrame( parent = hidden, guiId = 'fade', relief = None, image = self.fadeModel, image_scale = (4, 2, 2), state = DGG.NORMAL, ) if not self.fadeModel: # No fade model was given, so we make this the fade model. self.fade["relief"] = DGG.FLAT self.fade["frameSize"] = (-2, 2, -1, 1) self.fade["frameColor"] = (0, 0, 0, 1) self.fade.setTransparency(TransparencyAttrib.MAlpha) self.fade.setBin('unsorted', 0) self.fade.setColor(0,0,0,0) self.fade.setScale(max(base.a2dRight, base.a2dTop)) def getFadeInIval(self, t=0.5, finishIval=None, blendType='noBlend'): """ Returns an interval without starting it. This is particularly useful in cutscenes, so when the cutsceneIval is escaped out of we can finish the fade immediately """ #self.noTransitions() masad: this creates a one frame pop, is it necessary? self.loadFade() transitionIval = Sequence(Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough), # in case aspect2d is hidden for some reason self.lerpFunc(self.fade, t, self.alphaOff, # self.alphaOn, blendType=blendType ), Func(self.fade.detachNode), name = self.fadeTaskName, ) if finishIval: transitionIval.append(finishIval) return transitionIval def getFadeOutIval(self, t=0.5, finishIval=None, blendType='noBlend'): """ Create a sequence that lerps the color out, then parents the fade to hidden """ self.noTransitions() self.loadFade() transitionIval = Sequence(Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough), # in case aspect2d is hidden for some reason self.lerpFunc(self.fade, t, self.alphaOn, # self.alphaOff, blendType=blendType ), name = self.fadeTaskName, ) if finishIval: transitionIval.append(finishIval) return transitionIval def fadeIn(self, t=0.5, finishIval=None, blendType='noBlend'): """ Play a fade in transition over t seconds. Places a polygon on the aspect2d plane then lerps the color from black to transparent. When the color lerp is finished, it parents the fade polygon to hidden. """ gsg = base.win.getGsg() if gsg: # If we're about to fade in from black, go ahead and # preload all the textures etc. base.graphicsEngine.renderFrame() render.prepareScene(gsg) render2d.prepareScene(gsg) if (t == 0): # Fade in immediately with no lerp #print "transitiosn: fadeIn 0.0" self.noTransitions() self.loadFade() self.fade.detachNode() fut = AsyncFuture() fut.setResult(None) return fut else: # Create a sequence that lerps the color out, then # parents the fade to hidden self.transitionIval = self.getFadeInIval(t, finishIval, blendType) self.transitionIval.append(Func(self.__finishTransition)) self.__transitionFuture = AsyncFuture() self.transitionIval.start() return self.__transitionFuture def fadeOut(self, t=0.5, finishIval=None, blendType='noBlend'): """ Play a fade out transition over t seconds. Places a polygon on the aspect2d plane then lerps the color from transparent to full black. When the color lerp is finished, it leaves the fade polygon covering the aspect2d plane until you fadeIn or call noFade. lerp """ if (t == 0): # Fade out immediately with no lerp self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn) elif ConfigVariableBool('no-loading-screen', False): if finishIval: self.transitionIval = finishIval self.transitionIval.start() else: # Create a sequence that lerps the color out, then # parents the fade to hidden self.transitionIval = self.getFadeOutIval(t, finishIval, blendType) self.transitionIval.append(Func(self.__finishTransition)) self.__transitionFuture = AsyncFuture() self.transitionIval.start() return self.__transitionFuture # Immediately done, so return a dummy future. fut = AsyncFuture() fut.setResult(None) return fut def fadeOutActive(self): return self.fade and self.fade.getColor()[3] > 0 def fadeScreen(self, alpha=0.5): """ Put a semitransparent screen over the camera plane to darken out the world. Useful for drawing attention to a dialog box for instance """ #print "transitiosn: fadeScreen" self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn[0], self.alphaOn[1], self.alphaOn[2], alpha) def fadeScreenColor(self, color): """ Put a semitransparent screen over the camera plane to darken out the world. Useful for drawing attention to a dialog box for instance """ #print "transitiosn: fadeScreenColor" self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(color) def noFade(self): """ Removes any current fade tasks and parents the fade polygon away """ #print "transitiosn: noFade" if self.transitionIval: self.transitionIval.pause() self.transitionIval = None if self.__transitionFuture: self.__transitionFuture.cancel() self.__transitionFuture = None if self.fade: # Make sure to reset the color, since fadeOutActive() is looking at it self.fade.setColor(self.alphaOff) self.fade.detachNode() def setFadeColor(self, r, g, b): self.alphaOn.set(r, g, b, 1) self.alphaOff.set(r, g, b, 0) ################################################## # Iris ################################################## def loadIris(self): if self.iris == None: self.iris = loader.loadModel(self.IrisModelName) self.iris.setPos(0, 0, 0) def irisIn(self, t=0.5, finishIval=None, blendType = 'noBlend'): """ Play an iris in transition over t seconds. Places a polygon on the aspect2d plane then lerps the scale of the iris polygon up so it looks like we iris in. When the scale lerp is finished, it parents the iris polygon to hidden. """ self.noTransitions() self.loadIris() if (t == 0): self.iris.detachNode() fut = AsyncFuture() fut.setResult(None) return fut else: self.iris.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) scale = 0.18 * max(base.a2dRight, base.a2dTop) self.transitionIval = Sequence(LerpScaleInterval(self.iris, t, scale = scale, startScale = 0.01, blendType=blendType), Func(self.iris.detachNode), Func(self.__finishTransition), name = self.irisTaskName, ) self.__transitionFuture = AsyncFuture() if finishIval: self.transitionIval.append(finishIval) self.transitionIval.start() return self.__transitionFuture def irisOut(self, t=0.5, finishIval=None, blendType='noBlend'): """ Play an iris out transition over t seconds. Places a polygon on the aspect2d plane then lerps the scale of the iris down so it looks like we iris out. When the scale lerp is finished, it leaves the iris polygon covering the aspect2d plane until you irisIn or call noIris. """ self.noTransitions() self.loadIris() self.loadFade() # we need this to cover up the hole. if (t == 0): self.iris.detachNode() self.fadeOut(0) fut = AsyncFuture() fut.setResult(None) return fut else: self.iris.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) scale = 0.18 * max(base.a2dRight, base.a2dTop) self.transitionIval = Sequence(LerpScaleInterval(self.iris, t, scale = 0.01, startScale = scale, blendType=blendType), Func(self.iris.detachNode), # Use the fade to cover up the hole that the iris would leave Func(self.fadeOut, 0), Func(self.__finishTransition), name = self.irisTaskName, ) self.__transitionFuture = AsyncFuture() if finishIval: self.transitionIval.append(finishIval) self.transitionIval.start() return self.__transitionFuture def noIris(self): """ Removes any current iris tasks and parents the iris polygon away """ if self.transitionIval: self.transitionIval.pause() self.transitionIval = None if self.iris != None: self.iris.detachNode() # Actually we need to remove the fade too, # because the iris effect uses it. self.noFade() def noTransitions(self): """ This call should immediately remove any and all transitions running """ self.noFade() self.noIris() # Letterbox is not really a transition, it is a screen overlay # self.noLetterbox() def __finishTransition(self): if self.__transitionFuture: self.__transitionFuture.setResult(None) self.__transitionFuture = None ################################################## # Letterbox ################################################## def loadLetterbox(self): if not self.letterbox: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects # positioned behind it. self.letterbox = NodePath("letterbox") # Allow fade in and out of the bars self.letterbox.setTransparency(1) # Allow DirectLabels to be parented to the letterbox sensibly self.letterbox.setBin('unsorted', 0) # Allow a custom look to the letterbox graphic. # TODO: This model isn't available everywhere. We should # pass it in as a parameter. button = loader.loadModel('models/gui/toplevel_gui', okMissing = True) barImage = None if button: barImage = button.find('**/generic_button') self.letterboxTop = DirectFrame( parent = self.letterbox, guiId = 'letterboxTop', relief = DGG.FLAT, state = DGG.NORMAL, frameColor = (0, 0, 0, 1), borderWidth = (0, 0), frameSize = (-1, 1, 0, 0.2), pos = (0, 0, 1.0), image = barImage, image_scale = (2.25,1,.5), image_pos = (0,0,.1), image_color = (0.3,0.3,0.3,1), sortOrder = 0, ) self.letterboxBottom = DirectFrame( parent = self.letterbox, guiId = 'letterboxBottom', relief = DGG.FLAT, state = DGG.NORMAL, frameColor = (0, 0, 0, 1), borderWidth = (0, 0), frameSize = (-1, 1, 0, 0.2), pos = (0, 0, -1.2), image = barImage, image_scale = (2.25,1,.5), image_pos = (0,0,.1), image_color = (0.3,0.3,0.3,1), sortOrder = 0, ) # masad: always place these at the bottom of render self.letterboxTop.setBin('sorted',0) self.letterboxBottom.setBin('sorted',0) self.letterbox.reparentTo(render2d, -1) self.letterboxOff(0) def noLetterbox(self): """ Removes any current letterbox tasks and parents the letterbox polygon away """ if self.letterboxIval: self.letterboxIval.pause() self.letterboxIval = None if self.__letterboxFuture: self.__letterboxFuture.cancel() self.__letterboxFuture = None if self.letterbox: self.letterbox.stash() def __finishLetterbox(self): if self.__letterboxFuture: self.__letterboxFuture.setResult(None) self.__letterboxFuture = None def letterboxOn(self, t=0.25, finishIval=None, blendType='noBlend'): """ Move black bars in over t seconds. """ self.noLetterbox() self.loadLetterbox() self.letterbox.unstash() if (t == 0): self.letterboxBottom.setPos(0, 0, -1) self.letterboxTop.setPos(0, 0, 0.8) fut = AsyncFuture() fut.setResult(None) return fut else: self.__letterboxFuture = AsyncFuture() self.letterboxIval = Sequence(Parallel( LerpPosInterval(self.letterboxBottom, t, pos = Vec3(0, 0, -1), #startPos = Vec3(0, 0, -1.2), blendType=blendType ), LerpPosInterval(self.letterboxTop, t, pos = Vec3(0, 0, 0.8), # startPos = Vec3(0, 0, 1), blendType=blendType ), ), Func(self.__finishLetterbox), name = self.letterboxTaskName, ) if finishIval: self.letterboxIval.append(finishIval) self.letterboxIval.start() return self.__letterboxFuture def letterboxOff(self, t=0.25, finishIval=None, blendType='noBlend'): """ Move black bars away over t seconds. """ self.noLetterbox() self.loadLetterbox() self.letterbox.unstash() if (t == 0): self.letterbox.stash() fut = AsyncFuture() fut.setResult(None) return fut else: self.__letterboxFuture = AsyncFuture() self.letterboxIval = Sequence(Parallel( LerpPosInterval(self.letterboxBottom, t, pos = Vec3(0, 0, -1.2), # startPos = Vec3(0, 0, -1), blendType=blendType ), LerpPosInterval(self.letterboxTop, t, pos = Vec3(0, 0, 1), # startPos = Vec3(0, 0, 0.8), blendType=blendType ), ), Func(self.letterbox.stash), Func(self.__finishLetterbox), Func(messenger.send,'letterboxOff'), name = self.letterboxTaskName, ) if finishIval: self.letterboxIval.append(finishIval) self.letterboxIval.start() return self.__letterboxFuture
class GuiButton2: def __init__(self, hugpos, offset, aspect, plane, name): self.enabled = True self.name = name self.frame = DirectFrame( relief = DGG.FLAT , frameColor = (0, 0, 0, 0) , scale = 1 , frameSize = (-0.3, 0.3, -0.3, 0.3) ) #32/600=0.05333 self.frame.setScale(0.0533) self.imageObject = OnscreenImage(image = name+".png", pos = (0, 0, 0)) self.imageObject.setTransparency(TransparencyAttrib.MAlpha) self.imageObject.setAlphaScale(1) self.imageObject.reparentTo(self.frame) self.hugpos = hugpos self.offset = offset self.redraw(aspect) def redraw(self, aspect, flag="wide"): if self.hugpos == "top": p = base.a2dTopLeft.getPos()#@UndefinedVariable p.setX(p.getX() + self.offset.getX() + 0.05) p.setZ(p.getZ() + self.offset.getZ() - GUI_TOP_OFFSET - 0.05) elif self.hugpos == "bottom": p = base.a2dBottomLeft.getPos()#@UndefinedVariable p.setX(p.getX() + self.offset.getX() + 0.05) p.setZ(p.getZ() + self.offset.getZ() + GUI_BOTTOM_OFFSET - 0.05) elif self.hugpos == "right": p = base.a2dBottomRight.getPos()#@UndefinedVariable p.setX(p.getX() + self.offset.getX() + 0.05) p.setZ(p.getZ() + self.offset.getZ() + GUI_BOTTOM_OFFSET - 0.05) self.frame.setPos(p) if flag == "wide": posx, posy = self.frame.getTightBounds() self.pos_min_x = posx.getX() / aspect self.pos_min_y = posx.getZ() self.pos_max_x = posy.getX() / aspect self.pos_max_y = posy.getZ() elif flag == "tall": posx, posy = self.frame.getTightBounds() self.pos_min_x = posx.getX() self.pos_min_y = posx.getZ() / aspect self.pos_max_x = posy.getX() self.pos_max_y = posy.getZ() / aspect def turnOn(self): self.imageObject.setImage(self.name+"_on.png")#@UndefinedVariable self.imageObject.setTransparency(TransparencyAttrib.MAlpha) def turnOff(self): self.imageObject.setImage(self.name+".png")#@UndefinedVariable self.imageObject.setTransparency(TransparencyAttrib.MAlpha) def enable(self): self.imageObject.setImage(self.name+".png")#@UndefinedVariable self.imageObject.setTransparency(TransparencyAttrib.MAlpha) self.enabled = True def disable(self): self.imageObject.setImage("empty.png")#@UndefinedVariable self.imageObject.setTransparency(TransparencyAttrib.MAlpha) self.enabled = False def removeNode(self): self.frame.removeNode() def setAbility(self, ability): self.name = ability self.imageObject.setImage(self.name+".png") self.imageObject.setTransparency(TransparencyAttrib.MAlpha) self.imageObject.setAlphaScale(1)
class RewardPanel(DirectFrame): notify = directNotify.newCategory('RewardPanel') def __init__(self, panelData): dialogBox = loader.loadModel('phase_3/models/gui/dialog_box_gui.bam') DirectFrame.__init__(self, relief=None, geom=dialogBox, geom_color=CIGlobals.DialogColor, geom_scale=(1.75, 1, 0.75 * 1.1), geom_pos=Point3(0, 0, -0.05), pos=(0, 0, 0.661)) self.initialiseoptions(RewardPanel) self.setScale(0.8) # The data for the reward panel inside of a RPToonData object. self.panelData = panelData # Top wood panel saying Reward Panel gagShopNodes = loader.loadModel( 'phase_4/models/gui/gag_shop_purchase_gui.bam') # Original pos: (-0.02, 0, 0.3) scale = (1.55, 1, 1) self.titlePanel = OnscreenImage( parent=self, image=gagShopNodes.find('**/Goofys_Sign'), pos=(0, 0, 0.3), hpr=(1, 0, 0), scale=(1.3, 1, 0.9)) self.avatarNamePanel = DirectFrame(parent=self.titlePanel, pos=(0, 0.005, 0)) self.avatarText = OnscreenText(parent=self.avatarNamePanel, text='', font=CIGlobals.getMickeyFont(), fg=(0.698, 0.13, 0.13, 1), mayChange=1, scale=(0.1, 0.13, 0.1)) self.panelContentsTitle = OnscreenText(parent=self, text=GagPanelName, font=CIGlobals.getMickeyFont(), pos=(0, 0.24, 0), fg=(0.3725, 0.619, 0.627, 1), mayChange=1) self.playerInfo = DirectFrame(parent=self, relief=None, pos=(-0.5, 0, 0)) self.playerInfo.setBin('gui-popup', 0) self.bonusText = OnscreenText(parent=self.playerInfo, text='2X Cog Office Bonus!', font=CIGlobals.getToonFont(), pos=(0, 0.15, 0), scale=(0.055, 0.055, 0.055), align=TextNode.ACenter) self.bonusText.hide() ################################################################################## # GUI Elements relating to the Favorite Gag/Gag Popup Used for showing Gag Unlock# ################################################################################## self.favoriteGagText = OnscreenText(parent=self.playerInfo, text=FavoriteGag, font=CIGlobals.getMickeyFont(), pos=FavoriteGagTitlePos, fg=(1, 0.2, 0.2, 1), sort=0) glow = loader.loadModel('phase_4/models/minigames/particleGlow.bam') self.favoriteGagGlow = OnscreenImage(parent=self.playerInfo, image=glow, pos=FavoriteGagPos, color=GagGlowColor, scale=(0.8, 0.8, 0.8)) self.favoriteGagGlow.setBin('gui-popup', 10) # particleGlow.bam uses a material since it's normally part of render, not render2d. # Since render2d is still fixed-function, we have to explicitly enable shader generation # to correctly display the glow in render2d. self.favoriteGagGlow.setShaderAuto() invIcons = loader.loadModel('phase_3.5/models/gui/inventory_icons.bam') gag = invIcons.find( GagGlobals.InventoryIconByName.get(GagGlobals.Foghorn)) self.favoriteGag = OnscreenImage(parent=self.playerInfo, image=gag, pos=FavoriteGagPos, scale=(1.65, 1.65, 1.65)) self.favoriteGag.setBin('gui-popup', 20) self.favoriteGagName = OnscreenText(parent=self.playerInfo, text=GagGlobals.Foghorn, font=CIGlobals.getToonFont(), pos=FavoriteGagNamePos, mayChange=1) ################################################################################ # GUI elements showing gag experience on the right-side of the gag exp panel # ################################################################################ self.gagExpFrame = DirectFrame(parent=self, relief=None, pos=(0.085, 0, 0.15)) self.trackLabels = [] self.trackIncLabels = [] self.trackBars = [] self.trackBarsOffset = 0 for i in range(len(GagGlobals.TrackNameById.values())): track = GagGlobals.TrackNameById.values()[i] color = GagGlobals.TrackColorByName.get(track) label = DirectLabel(parent=self.gagExpFrame, relief=None, text=track.upper(), text_scale=0.05, text_align=TextNode.ARight, pos=(0.13, 0, -0.09 * i), text_pos=(0, -0.02)) incrementLabel = DirectLabel(parent=self.gagExpFrame, relief=None, text='', text_scale=0.05, text_align=TextNode.ALeft, pos=(0.65, 0, -0.09 * i), text_pos=(0, -0.02)) progressBar = DirectWaitBar( parent=self.gagExpFrame, relief=DGG.SUNKEN, frameSize=(-1, 1, -0.15, 0.15), borderWidth=(0.02, 0.02), scale=0.25, frameColor=(color[0] * 0.7, color[1] * 0.7, color[2] * 0.7, 1), barColor=(color[0], color[1], color[2], 1), text='0/0', text_scale=0.18, text_fg=(0, 0, 0, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05), pos=(0.4, 0, -0.09 * i)) self.trackLabels.append(label) self.trackIncLabels.append(incrementLabel) self.trackBars.append(progressBar) ################################################################################ # GUI elements showing progress updates on quests # ################################################################################ self.questFrame = DirectFrame(parent=self, relief=None) self.questPosters = [] self.congratsLeft = OnscreenText(parent=self.playerInfo, pos=(-0.1, 0.125, -0.1), text='', scale=0.06, align=TextNode.ARight) self.congratsLeft.setR(-30) self.congratsRight = OnscreenText(parent=self.playerInfo, pos=(0.1, 0.125, 0.1), text='', scale=0.06, align=TextNode.ALeft) self.congratsRight.setR(30) glow.removeNode() invIcons.removeNode() gagShopNodes.removeNode() dialogBox.removeNode() def __getAvatarTextScale(self): totalWidth = self.avatarText.node().getWidth() panelWidth = 9.2 defaultTextScale = 1.0 scale = min(defaultTextScale, defaultTextScale / (totalWidth / panelWidth)) return (scale, scale, scale) def enterOff(self): pass def exitOff(self): pass def setPanelData(self, panelData): self.panelData = panelData self.avatarText['text'] = self.panelData.avatarName self.avatarNamePanel.setScale(self.__getAvatarTextScale()) # Let's set the data for our gag experience here. for i in range(len(self.trackLabels)): track = self.panelData.getTrackByName( GagGlobals.TrackNameById.values()[i]) bar = self.trackBars[i] bar['text'] = '%d/%d' % (track.exp, track.maxExp) # When the maximum experience of a track isn't 0, we know it isn't unlocked. if track.maxExp == -1: bar.hide() self.trackIncLabels[i]['text'] = '' self.trackIncLabels[i].show() def __chooseRewardShot(self, av): shotChoices = [(0, 8, av.getHeight() * 0.66, 179, 15, 0), (5.2, 5.45, av.getHeight() * 0.66, 131.5, 3.6, 0)] shot = random.choice(shotChoices) return shot def getQuestsProgressInterval(self): avatar = self.panelData.avatar intervals = [] def toggleFavoriteGagItems(visible): for item in [ self.favoriteGag, self.favoriteGagGlow, self.favoriteGagText, self.favoriteGagName ]: if not visible: item.hide() else: item.show() def setupQuestPosters(): questManager = avatar.questManager numQuests = len(questManager.quests.values()) yPos = 0.47 displayData = { 1: [[Point3(0.0, 0.0, yPos)], 0.88], 2: [[Point3(-0.42, 0.0, yPos), Point3(0.45, 0.0, yPos)], 0.88], 3: [[ Point3(-0.57, 0.0, yPos), Point3(0.0, 0.0, yPos), Point3(0.57, 0.0, yPos) ], 0.70], 4: [[ Point3(-0.32, 0.0, 0.62), Point3(-0.32, 0.0, 0.30), Point3(0.32, 0.0, 0.62), Point3(0.32, 0.0, 0.30) ], 0.52] } # A full frame is a frame showing two quests at once. howManyFullFrames = math.ceil(numQuests / 2.0) howManyRemainderFrames = (numQuests - howManyFullFrames) for i, quest in enumerate(questManager.quests.values()): poster = QuestGlobals.generatePoster(quest, parent=self.questFrame) poster.setScale(displayData.get(numQuests)[1]) poster.setPos(displayData.get(numQuests)[0][i]) poster.show() self.questPosters.append(poster) intervals.append(Func(self.gagExpFrame.hide)) intervals.append(Func(self.playerInfo.show)) intervals.append(Func(self.panelContentsTitle.setText, QuestsPanelName)) intervals.append(Func(toggleFavoriteGagItems, False)) intervals.append(Func(setupQuestPosters)) #intervals.append(Func(self.playerInfo.initialiseoptions, DirectFrame)) return intervals def getGagExperienceInterval(self): avatar = self.panelData.avatar intervals = [] shot = self.__chooseRewardShot(avatar) intervals.append(Func(base.camera.reparentTo, avatar)) intervals.append(Func(base.camera.setPosHpr, *shot)) intervals.append(Func(self.congratsLeft.hide)) intervals.append(Func(self.congratsRight.hide)) intervals.append(Func(self.panelContentsTitle.setText, GagPanelName)) intervals.append(Func(self.setFavoriteGag, self.panelData.favoriteGag)) intervals.append(Func(self.gagExpFrame.show)) intervals.append(Func(self.playerInfo.show)) intervals.append(Wait(1.0)) for i in range(len(self.trackLabels)): track = self.panelData.getTrackByName( GagGlobals.TrackNameById.values()[i]) intervals.extend(self.getTrackIntervalList(track, i)) return intervals def getNextExpValue(self, newValue, track): if newValue < track.maxExp or track.maxExp == 0: return track.maxExp else: levels = GagGlobals.TrackExperienceAmounts[track.name] index = levels.index(track.maxExp) if index + 1 < len(levels): return levels[index + 1] return -1 def incrementExp(self, trackIndex, track, newValue): bar = self.trackBars[trackIndex] nextExp = GagGlobals.getMaxExperienceValue(newValue, track.name) oldValue = bar['value'] color = GagGlobals.TrackColorByName.get(track.name) bar['text'] = '%d/%d' % (newValue, nextExp) bar['range'] = nextExp if not nextExp == -1 else newValue bar['value'] = newValue bar['barColor'] = (color[0], color[1], color[2], 1) def resetBarColor(self, trackIndex): color = GagGlobals.TrackColorByName.get( GagGlobals.TrackNameById.values()[trackIndex]) self.trackBars[trackIndex]['barColor'] = (color[0] * 0.8, color[1] * 0.8, color[2] * 0.8, 1) def showTrackIncLabel(self, trackIndex, track, increment): label = self.trackIncLabels[trackIndex] # Only show increments when that track is unlocked. if track.exp != -1: label['text'] = '+%d' % increment label.show() def getTrackIntervalList(self, track, trackIndex): tickDelay = 1.0 / 60 intervalList = [] intervalList.append( Func(self.showTrackIncLabel, trackIndex, track, track.increment)) barTime = 2.0 if track.exp > 0 else 0.25 numTicks = int(math.ceil(barTime / tickDelay)) for i in range(numTicks): t = (i + 1) / float(numTicks) newValue = int(track.exp + t * track.increment + 0.5) intervalList.append( Func(self.incrementExp, trackIndex, track, newValue)) intervalList.append(Wait(tickDelay)) intervalList.append(Func(self.resetBarColor, trackIndex)) intervalList.append(Wait(0.2)) if track.maxExp > 0 and (track.maxExp != GagGlobals.MaxedTrackExperiences.get(track.name) \ and (track.exp + track.increment) >= track.maxExp): gagIndex = GagGlobals.TrackExperienceAmounts.get(track.name).index( track.maxExp) + 1 newGag = GagGlobals.TrackGagNamesByTrackName.get( track.name)[gagIndex] intervalList.append( self.getShowGagUnlockedInterval(track.name, newGag)) return intervalList def getShowGagUnlockedInterval(self, track, gagName): seq = Sequence( Func(self.gagExpFrame.hide), Func(self.panelContentsTitle.setText, 'Gag Unlocked!'), Func(self.playerInfo.show), Func(self.setFavoriteGag, gagName), Func(self.favoriteGagName.setY, -0.35), Func(self.favoriteGagText.setY, 0.105), Func(self.favoriteGagText.setText, 'New %s Gag' % track), Func(self.bonusText.hide), Func(self.playerInfo.setPos, 0, 0, 0), Func(self.playerInfo.initialiseoptions, DirectFrame)) seq.append(self.getCongratsInterval()) seq.append(Wait(1.0)) seq.append(self.getHideGagUnlockedInterval()) seq.append(Func(self.gagExpFrame.show)) seq.append(Wait(0.5)) return seq def getHideGagUnlockedInterval(self): def correctPositioning(guiElement, pos): guiElement['pos'] = pos seq = Sequence( Func(self.panelContentsTitle.setText, GagPanelName), Func(self.setFavoriteGag, self.panelData.favoriteGag), Func(self.playerInfo.setX, -0.5), Func(correctPositioning, self.favoriteGagName, FavoriteGagNamePos), Func(self.favoriteGagText.setText, FavoriteGag), Func(correctPositioning, self.favoriteGagText, FavoriteGagTitlePos), Func(self.congratsLeft.hide), Func(self.congratsRight.hide)) return seq def __getRandomCongratsPair(self): msgs = list(NewGagCongratsMessages) msg = msgs[random.randint(0, len(msgs) - 1)] msgs.remove(msg) return (msg, msgs[random.randint(0, len(msgs) - 1)]) def getCongratsInterval(self): msgs = self.__getRandomCongratsPair() self.congratsLeft['text'] = msgs[0] self.congratsRight['text'] = msgs[1] sfx = loader.loadSfx('phase_3/audio/sfx/GUI_balloon_popup.ogg') sfx.setLoop(False) sfx.setVolume(1.0) def makeSequence(text): seq = Sequence(Wait(1.0), Func(text.show)) seq.append(Func(sfx.play)) seq.append( CIGlobals.makePulseEffectInterval(text, 1.0, 0.01, 1.05, 0.5, 0.25)) seq.append(Func(sfx.stop)) return seq return Sequence(makeSequence(self.congratsLeft), makeSequence(self.congratsRight)) def setFavoriteGag(self, gagName): invIcons = loader.loadModel('phase_3.5/models/gui/inventory_icons.bam') gag = invIcons.find(GagGlobals.InventoryIconByName.get(gagName)) self.favoriteGagName.setText(gagName) self.favoriteGag['image'] = gag invIcons.removeNode() def destroy(self): if self.titlePanel: self.titlePanel.destroy() if self.avatarText: self.avatarText.destroy() if self.avatarNamePanel: self.avatarNamePanel.destroy() if self.panelContentsTitle: self.panelContentsTitle.destroy() if self.favoriteGag: self.favoriteGag.destroy() if self.favoriteGagGlow: self.favoriteGagGlow.destroy() if self.favoriteGagName: self.favoriteGagName.destroy() if self.playerInfo: self.playerInfo.destroy() if self.trackLabels: for label in self.trackLabels: label.destroy() if self.trackIncLabels: for label in self.trackIncLabels: label.destroy() if self.trackBars: for bar in self.trackBars: bar.destroy() if self.congratsLeft: self.congratsLeft.destroy() if self.congratsRight: self.congratsRight.destroy() if self.gagExpFrame: self.gagExpFrame.destroy() if self.panelData: self.panelData = None del self.titlePanel del self.avatarText del self.avatarNamePanel del self.panelContentsTitle del self.favoriteGag del self.favoriteGagGlow del self.favoriteGagName del self.playerInfo del self.trackLabels del self.trackIncLabels del self.trackBars del self.gagExpFrame del self.congratsLeft del self.congratsRight del self.panelData DirectFrame.destroy(self)
def setScale(self, *args, **kwargs): DirectFrame.setScale(self, *args, **kwargs) self.resetArcBall()
class DoubleFrameQuestPoster(QuestPoster): notify = directNotify.newCategory('DoubleFrameQuestPoster') def __init__(self, quest, parent=aspect2d, **kw): QuestPoster.__init__(self, quest, parent, **kw) # This text is in between the two frames and it usually says # either "from:" or "to:" self.fromToMiddleText = DirectLabel( parent=self, relief=None, text=QuestGlobals.FROM, text_font=CIGlobals.getToonFont(), text_scale=QuestGlobals.QPauxText, text_fg=QuestGlobals.TEXT_COLOR, text_align=TextNode.ACenter, textMayChange=1, pos=QuestGlobals.DEFAULT_MIDDLE_POS) self.fromToMiddleText.hide() ########################################################################## # THE FOLLOWING ELEMENTS BELOW ARE GROUPED TOGETHER # ########################################################################## # We need this again for certain geometry. circleGui = loader.loadModel( 'phase_4/models/gui/CircleIconBackgroundGui.bam') # The background frame where the objective image is displayed. # This is the colored background frame. self.goalFrame = DirectFrame( parent=self, relief=None, image=circleGui.find('**/circle_display_interior'), image_scale=0.18, text='', text_pos=(0, -0.11), text_fg=QuestGlobals.TEXT_COLOR, text_scale=QuestGlobals.QPtextScale, text_align=TextNode.ACenter, text_wordwrap=11.0, pos=QuestGlobals.DEFAULT_RIGHT_PICTURE_POS) self.goalFrame.hide() # The icon that goes on top of the goal frame. self.goalIcon = DirectFrame(parent=self.goalFrame, relief=None, text=' ', text_font=CIGlobals.getSuitFont(), text_pos=(0, -0.03), text_fg=QuestGlobals.TEXT_COLOR, text_scale=0.13, text_align=TextNode.ACenter, text_wordwrap=13.0, textMayChange=1) self.goalIcon.setColorOff(-1) self.goalIcon.hide() self.goalOutline = DirectLabel( parent=self.goalFrame, relief=None, image=circleGui.find('**/circle_display_outline'), image_scale=0.18) self.goalOutline.hide() # Information displayed about the additional goal. self.goalInfo = DirectLabel(parent=self, relief=None, text='', text_font=CIGlobals.getToonFont(), text_fg=QuestGlobals.TEXT_COLOR, text_scale=0.04, text_align=TextNode.ACenter, text_wordwrap=QuestGlobals.QPtextWordwrap, textMayChange=1, pos=(QuestGlobals.DEFAULT_INFO2_POS)) self.goalInfo.hide() circleGui.removeNode() return ########################################################################## def setup(self): QuestPoster.setup(self) objective = self.viewObjective # Let's reset our icon. self.goalIcon.setScale(1, 1, 1) self.goalIcon.setPos(0, 0, 0) self.goalIcon.setHpr(0, 0, 0) if objective.__class__ in DoubleFrameObjectives: if objective.__class__ == DeliverItemObjective: # It's kind of hard to return delivered stuff to somebody. # We're not handling complete objectives from here. self.handleDeliverItemObjective() elif objective.__class__ == RecoverItemObjective: self.handleRecoverItemObjective() if len(self.quest.accessibleObjectives) > 1: self.prevObjArrow.setPos(QuestGlobals.SECONDARY_LEFT_ARROW_POS) self.nextObjArrow.setPos( QuestGlobals.SECONDARY_RIGHT_ARROW_POS) self.goalFrame.show() self.goalIcon.show() self.goalOutline.show() self.goalInfo.show() self.fromToMiddleText.show() else: self.goalFrame.hide() self.goalIcon.hide() self.goalOutline.hide() self.goalInfo.hide() self.fromToMiddleText.hide() self.goalIcon.initialiseoptions(DirectFrame) self.initialiseoptions(DoubleFrameQuestPoster) def handleRecoverItemObjective(self): objective = self.viewObjective # Let's make sure we have a current objective that is # an instance of the RecoverItemObjective class and this poster isn't destroyed. if not objective or not hasattr(self, 'titleLabel') or not isinstance( objective, RecoverItemObjective): return # Let's make the left icon use the item icon we chose. self.handleSimpleIcon(objective.itemIcon, 0.12, self.auxIcon) # Handle the objective information. infoText = '%d %s' % (objective.goal, CIGlobals.makePlural(objective.itemName)) if objective.goal == 1: infoText = objective.itemName # Update the positions and information regarding the left side. self.auxFrame.setPos(QuestGlobals.RECOVER_LEFT_PICTURE_POS) self.auxFrame['image_color'] = QuestGlobals.GREEN self.objectiveInfo.setPos(QuestGlobals.RECOVER_INFO_POS) self.objectiveInfo['text'] = infoText self.fromToMiddleText[ 'text'] = QuestGlobals.FROM if not objective.isComplete( ) else QuestGlobals.TO if not objective.isComplete(): self.handleCogObjective(self.goalIcon, auxText=QuestGlobals.RECOVER, frameColor=QuestGlobals.GREEN) # Let's set the progress bar text pgBarText = '%d of %d %s' % (objective.progress, objective.goal, CIGlobals.makePastTense( QuestGlobals.RECOVER)) self.progressBar['text'] = pgBarText self.progressBar['value'] = objective.progress & pow(2, 16) - 1 else: self.handleNPCObjective(self.goalIcon, auxText=QuestGlobals.RETURN, frameColor=QuestGlobals.BLUE) def handleDeliverItemObjective(self): objective = self.viewObjective # Let's make sure we have a current objective that is # an instance of the DeliverItemObjective class and this poster isn't destroyed. if not objective or not hasattr(self, 'titleLabel') or not isinstance( objective, DeliverItemObjective): return # Correct the scaling if we need to and set the icon. scale = 0.12 if objective.itemIcon.getName() == 'package' else 0.85 self.handleSimpleIcon(objective.itemIcon, scale, self.auxIcon) self.auxFrame.setPos(QuestGlobals.RECOVER_LEFT_PICTURE_POS) self.auxFrame['image_color'] = QuestGlobals.RED infoText = '%d %s' % (objective.goal, CIGlobals.makePlural(objective.itemName)) if objective.goal == 1: infoText = objective.itemName self.objectiveInfo.setPos(QuestGlobals.RECOVER_INFO_POS) self.objectiveInfo['text'] = infoText self.fromToMiddleText['text'] = QuestGlobals.TO # Let's set the progress bar text pgBarText = '%d of %d %s' % (objective.progress, objective.goal, CIGlobals.makePastTense( QuestGlobals.DELIVER)) self.progressBar['text'] = pgBarText self.progressBar['value'] = objective.progress & pow(2, 16) - 1 self.handleNPCObjective(self.goalIcon, auxText=QuestGlobals.DELIVER, frameColor=QuestGlobals.RED) def destroy(self): self.fromToMiddleText.destroy() self.goalFrame.destroy() self.goalIcon.destroy() self.goalOutline.destroy() self.goalInfo.destroy() del self.fromToMiddleText del self.goalFrame del self.goalIcon del self.goalOutline del self.goalInfo QuestPoster.destroy(self)