class PartyPlanner(DirectFrame, FSM): notify = DirectNotifyGlobal.directNotify.newCategory('PartyPlanner') def __init__(self, doneEvent = None): FSM.__init__(self, 'PartyPlannerFSM') DirectFrame.__init__(self) self.doneEvent = doneEvent self.stateArray = ['Off', 'Welcome', 'PartyEditor', 'Guests', 'Date', 'Time', 'Invitation', 'Farewell'] self.partyTime = base.cr.toontownTimeManager.getCurServerDateTime() self.partyNowTime = base.cr.toontownTimeManager.getCurServerDateTime() minutesToNextFifteen = 15 - self.partyTime.minute % 15 self.cleanPartyTime = self.partyTime + timedelta(minutes=minutesToNextFifteen, seconds=-self.partyTime.second) self.partyTime = self.cleanPartyTime self.guests = [] self.isPrivate = False self.selectedCalendarGuiDay = None self.gui = loader.loadModel('phase_4/models/parties/partyPlannerGUI') self.partyDuration = timedelta(hours=PartyGlobals.DefaultPartyDuration) self.timeTypeToMaxValue = {'hour': 23, 'minute': 59} self.timeTypeToChangeAmount = {'hour': (1, -1), 'minute': (15, -15), 'ampm': (1, -1)} self.partyInfo = None self.asapMinuteRounding = base.config.GetInt('party-asap-minute-rounding', PartyGlobals.PartyPlannerAsapMinuteRounding) self.load() self.request('Welcome') return def enterWelcome(self, *args): self.prevButton['state'] = DirectGuiGlobals.DISABLED self.prevButton.hide() self.nextButton['state'] = DirectGuiGlobals.NORMAL self.welcomePage.show() self.partyPlannerHead.reparentTo(self.welcomePage) self.partyPlannerHead.startBlink() self.partyPlannerHead.startLookAround() self.nametagNP.reparentTo(self.welcomePage) self.chatNP.reparentTo(self.welcomePage) def exitWelcome(self): self.welcomePage.hide() self.prevButton.show() self.partyPlannerHead.stopBlink() self.partyPlannerHead.stopLookAround() def enterPartyEditor(self, *args): self.prevButton['state'] = DirectGuiGlobals.NORMAL self.nextButton['state'] = DirectGuiGlobals.DISABLED self.nextButton.hide() self.partyEditorPage.show() self.okWithGroundsGui.doneStatus = '' self.partyEditor.request('Idle') def exitPartyEditor(self): self.partyEditor.request('Hidden') self.partyEditorPage.hide() def enterGuests(self, *args): self.prevButton['state'] = DirectGuiGlobals.NORMAL self.nextButton['state'] = DirectGuiGlobals.NORMAL self.nextButton.show() self.guestPage.show() def exitGuests(self): self.guests = [] for friendCheckBox in self.friendList['items']: if friendCheckBox['indicatorValue']: self.guests.append(friendCheckBox.getPythonTag('id')) self.guestPage.hide() def enterDate(self, *args): self.prevButton.show() self.prevButton['state'] = DirectGuiGlobals.NORMAL if self.selectedCalendarGuiDay is None: self.nextButton['state'] = DirectGuiGlobals.DISABLED self.nextButton.hide() self.makePartyNowButton.show() self.datePage.show() return def exitDate(self): self.datePage.hide() self.nextButton.show() if self.selectedCalendarGuiDay is not None: self.partyTime = self.cleanPartyTime self.alterPartyTime(year=self.selectedCalendarGuiDay.myDate.year, month=self.selectedCalendarGuiDay.myDate.month, day=self.selectedCalendarGuiDay.myDate.day) else: self.partyNowTime = self.calcAsapTime() self.partyTime = self.partyNowTime return def calcAsapTime(self): curServerTime = base.cr.toontownTimeManager.getCurServerDateTime() baseTime = curServerTime baseTime = baseTime.replace(baseTime.year, baseTime.month, baseTime.day, baseTime.hour, baseTime.minute, second=0, microsecond=0) minute = curServerTime.minute remainder = minute % self.asapMinuteRounding if remainder: baseTime += timedelta(minutes=self.asapMinuteRounding - remainder) else: baseTime += timedelta(minutes=self.asapMinuteRounding) return baseTime def enterTime(self, *args): self.prevButton.show() self.prevButton['state'] = DirectGuiGlobals.NORMAL self.nextButton.show() self.timePage.show() self.timePageRecapToontownTimeLabel2['text'] = '%s' % PartyUtils.formatDateTime(self.partyTime) self.timePageRecapLocalTimeLabel['text'] = '%s%s' % (TTLocalizer.PartyPlannerTimeLocalTime, PartyUtils.formatDateTime(self.partyTime, inLocalTime=True)) def exitTime(self): self.timePage.hide() self.nextButton.show() def enterInvitation(self, *args): self.prevButton['state'] = DirectGuiGlobals.NORMAL self.nextButton.hide() defaultInviteTheme = PartyGlobals.InviteTheme.GenericMale if hasattr(base.cr, 'newsManager') and base.cr.newsManager: if ToontownGlobals.VICTORY_PARTY_HOLIDAY in base.cr.newsManager.getHolidayIdList(): defaultInviteTheme = PartyGlobals.InviteTheme.VictoryParty elif ToontownGlobals.KARTING_TICKETS_HOLIDAY in base.cr.newsManager.getHolidayIdList() or ToontownGlobals.CIRCUIT_RACING_EVENT in base.cr.newsManager.getHolidayIdList(): defaultInviteTheme = PartyGlobals.InviteTheme.Racing elif ToontownGlobals.VALENTINES_DAY in base.cr.newsManager.getHolidayIdList(): defaultInviteTheme = PartyGlobals.InviteTheme.Valentoons if self.partyInfo is not None: del self.partyInfo activityList = self.partyEditor.partyEditorGrid.getActivitiesOnGrid() decorationList = self.partyEditor.partyEditorGrid.getDecorationsOnGrid() endTime = self.partyTime + self.partyDuration self.partyInfo = PartyInfo(0, 0, self.partyTime.year, self.partyTime.month, self.partyTime.day, self.partyTime.hour, self.partyTime.minute, endTime.year, endTime.month, endTime.day, endTime.hour, endTime.minute, self.isPrivate, defaultInviteTheme, activityList, decorationList, 0) if self.noFriends or len(self.getInvitees()) == 0: self.inviteVisual.setNoFriends(True) self.invitationTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmTitleNoFriends self.inviteButton['text'] = TTLocalizer.PartyPlannerInviteButtonNoFriends self.selectedInviteThemeLabel.stash() self.nextThemeButton.stash() self.prevThemeButton.stash() self.setInviteTheme(defaultInviteTheme) else: self.inviteVisual.setNoFriends(False) self.invitationTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmTitle self.inviteButton['text'] = TTLocalizer.PartyPlannerInviteButton self.selectedInviteThemeLabel.unstash() self.nextThemeButton.unstash() self.prevThemeButton.unstash() self.setInviteTheme(defaultInviteTheme) self.inviteVisual.updateInvitation(base.localAvatar.getName(), self.partyInfo) self.invitationPage.show() return def __prevTheme(self): self.nextThemeButton.show() prevTheme = self.currentInvitationTheme - 1 while prevTheme not in self.inviteThemes: prevTheme -= 1 if prevTheme == self.currentInvitationTheme: self.notify.warning('No previous invite theme found.') break elif prevTheme < 0: prevTheme = len(self.inviteVisual.inviteThemesIdToInfo) - 1 self.setInviteTheme(prevTheme) def __nextTheme(self): self.prevThemeButton.show() nextTheme = self.currentInvitationTheme + 1 while nextTheme not in self.inviteThemes: nextTheme += 1 if nextTheme == self.currentInvitationTheme: self.notify.warning('No next invite theme found.') break elif nextTheme >= len(self.inviteVisual.inviteThemesIdToInfo): nextTheme = 0 self.setInviteTheme(nextTheme) def setInviteTheme(self, themeNumber): self.currentInvitationTheme = themeNumber self.selectedInviteThemeLabel['text'] = '%s %s (%d/%d)' % (self.inviteVisual.inviteThemesIdToInfo[self.currentInvitationTheme][1], TTLocalizer.PartyPlannerInvitationTheme, self.inviteThemes.index(self.currentInvitationTheme) + 1, len(self.inviteThemes)) self.partyInfo.inviteTheme = self.currentInvitationTheme self.inviteVisual.updateInvitation(base.localAvatar.getName(), self.partyInfo) def exitInvitation(self): self.invitationPage.hide() self.nextButton.show() def enterFarewell(self, goingBackAllowed): self.farewellPage.show() if goingBackAllowed: self.prevButton.show() else: self.prevButton.hide() self.nextButton.hide() self.partyPlannerHead.reparentTo(self.farewellPage) self.partyPlannerHead.startBlink() self.partyPlannerHead.startLookAround() self.nametagNP.reparentTo(self.farewellPage) self.chatNP.reparentTo(self.farewellPage) def exitFarewell(self): self.farewellPage.hide() self.nextButton.show() self.prevButton.show() self.partyPlannerHead.stopBlink() self.partyPlannerHead.stopLookAround() def load(self): self.frame = DirectFrame(parent=aspect2d, geom=self.gui.find('**/background'), relief=None, scale=0.85, pos=(0.05, 0.0, 0.1)) self.titleScale = TTLocalizer.PPtitleScale self._createNavButtons() self.welcomePage = self._createWelcomePage() self.welcomePage.hide() self.datePage = self._createDatePage() self.datePage.hide() self.timePage = self._createTimePage() self.timePage.hide() self.guestPage = self._createGuestPage() self.guestPage.hide() self.partyEditorPage = self._createPartyEditorPage() self.partyEditorPage.hide() self.invitationPage = self._createInvitationPage() self.invitationPage.hide() self.farewellPage = self._createFarewellPage() self.farewellPage.hide() return def _createNavButtons(self): self.quitButton = DirectButton(parent=self.frame, relief=None, geom=(self.gui.find('**/cancelButton_up'), self.gui.find('**/cancelButton_down'), self.gui.find('**/cancelButton_rollover')), command=self.__acceptExit) self.nextButton = DirectButton(parent=self.frame, relief=None, geom=(self.gui.find('**/bottomNext_button/nextButton_up'), self.gui.find('**/bottomNext_button/nextButton_down'), self.gui.find('**/bottomNext_button/nextButton_rollover')), command=self.__nextItem, state=DirectGuiGlobals.DISABLED) self.prevButton = DirectButton(parent=self.frame, relief=None, geom=(self.gui.find('**/bottomPrevious_button/previousButton_up'), self.gui.find('**/bottomPrevious_button/previousButton_down'), self.gui.find('**/bottomPrevious_button/previousButton_rollover')), command=self.__prevItem, state=DirectGuiGlobals.DISABLED) self.currentItem = None return def __createNametag(self, parent): if self.nametagGroup == None: self.nametagGroup = NametagGroup() self.nametagGroup.setFont(OTPGlobals.getInterfaceFont()) self.nametagGroup.setActive(0) self.nametagGroup.setAvatar(self.partyPlannerHead) self.nametagGroup.manage(base.marginManager) self.nametagGroup.setColorCode(self.nametagGroup.CCNonPlayer) self.nametagGroup.getNametag2d().setContents(0) self.nametagNode = NametagFloat2d() self.nametagNode.setContents(Nametag.CName) self.nametagGroup.addNametag(self.nametagNode) self.nametagGroup.setName(base.cr.partyManager.getPartyPlannerName()) self.nametagNP = parent.attachNewNode(self.nametagNode.upcastToPandaNode()) nametagPos = self.gui.find('**/step_01_partymanPeteNametag_locator').getPos() self.nametagNP.setPosHprScale(nametagPos[0], 0, nametagPos[2], 0, 0, 0, 0.1, 1, 0.1) self.chatNode = NametagFloat2d() self.chatNode.setContents(Nametag.CSpeech | Nametag.CThought) self.nametagGroup.addNametag(self.chatNode) self.nametagGroup.setChat(TTLocalizer.PartyPlannerInstructions, CFSpeech) self.chatNP = parent.attachNewNode(self.chatNode.upcastToPandaNode()) chatPos = self.gui.find('**/step_01_partymanPeteText_locator').getPos() self.chatNP.setPosHprScale(chatPos[0], 0, chatPos[2], 0, 0, 0, 0.08, 1, 0.08) return def clearNametag(self): if self.nametagGroup != None: self.nametagGroup.unmanage(base.marginManager) self.nametagGroup.removeNametag(self.nametagNode) self.nametagGroup.removeNametag(self.chatNode) self.nametagNP.removeNode() self.chatNP.removeNode() del self.nametagNP del self.chatNP del self.nametagNode del self.chatNode self.nametagGroup.setAvatar(NodePath()) self.nametagGroup = None return def _createWelcomePage(self): self.nametagGroup = None page = DirectFrame(self.frame) page.setName('PartyPlannerWelcomePage') self.welcomeTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerWelcomeTitle, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) self.partyPlannerHead = ToonHead.ToonHead() partyPlannerStyle = base.cr.partyManager.getPartyPlannerStyle() self.partyPlannerHead.setupHead(partyPlannerStyle, forGui=True) self.partyPlannerHead.setPos(self.gui.find('**/step_01_partymanPete_locator').getPos()) animal = partyPlannerStyle.getAnimal() if animal == 'cat' or animal == 'pig': headScale = 0.4 elif animal == 'dog' or animal == 'bear': headScale = 0.45 elif animal == 'rabbit': headScale = 0.35 else: headScale = 0.3 self.partyPlannerHead.setScale(headScale) self.partyPlannerHead.setH(180.0) self.partyPlannerHead.reparentTo(page) self.__createNametag(page) return page def _createDatePage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerDatePage') self.createDateTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerDateTitle, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) pos = self.gui.find('**/step_06_sendInvitation_locator').getPos() self.makePartyNowButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/send_up'), self.gui.find('**/send_down'), self.gui.find('**/send_rollover')), text=TTLocalizer.PartyPlannerPartyNow, text_pos=(pos[0], pos[2]), text_scale=0.05, command=self.__doMakePartyNow) curServerDate = base.cr.toontownTimeManager.getCurServerDateTime() self.calendarGuiMonth = CalendarGuiMonth(page, curServerDate, scale=0.95, pos=(-0.05, 0.0, -0.33), dayClickCallback=self._dayClickCallback, onlyFutureDaysClickable=True) return page def __doMakePartyNow(self): self.request('Invitation') def _dayClickCallback(self, calendarGuiDay): self.selectedCalendarGuiDay = calendarGuiDay self.nextButton['state'] = DirectGuiGlobals.NORMAL self.makePartyNowButton.hide() self.nextButton.show() def alterPartyTime(self, year = None, month = None, day = None, hour = None, minute = None): self.partyTime = datetime(year=self.positiveTime('year', year), month=self.positiveTime('month', month), day=self.positiveTime('day', day), hour=self.positiveTime('hour', hour), minute=self.positiveTime('minute', minute), tzinfo=self.partyTime.tzinfo) def positiveTime(self, type, amount): if amount is None: return getattr(self.partyTime, type) if type == 'hour' or type == 'minute': if amount < 0: return self.timeTypeToMaxValue[type] + 1 + self.timeTypeToChangeAmount[type][1] elif amount > self.timeTypeToMaxValue[type]: return 0 return amount def _createTimePage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerTimePage') self.createTimeTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeTitle, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) self.clockImage = DirectFrame(parent=page, relief=None, geom=self.gui.find('**/toontownTime_background')) self.timePageToontownLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeToontown, pos=self.gui.find('**/step_03_toontown_locator').getPos(), scale=0.15, text_fg=(1.0, 0.0, 0.0, 1.0), text_font=ToontownGlobals.getSignFont()) self.timePageTimeLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeTime, pos=self.gui.find('**/step_03_time_locator').getPos(), scale=0.15, text_fg=(1.0, 0.0, 0.0, 1.0), text_font=ToontownGlobals.getSignFont()) self.timePageRecapLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeRecap, pos=self.gui.find('**/step_03_partyDateAndTime_locator').getPos(), scale=0.09) self.timePageRecapToontownTimeLabel1 = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeToontownTime, pos=self.gui.find('**/step_03_toontownTime_locator').getPos(), scale=0.06) self.timePageRecapToontownTimeLabel2 = DirectLabel(parent=page, relief=None, text='%s' % PartyUtils.formatDateTime(self.partyTime), pos=self.gui.find('**/step_03_toontownDateAndTime_loactor').getPos(), textMayChange=True, scale=0.06) self.timePageRecapLocalTimeLabel = DirectLabel(parent=page, relief=None, text='%s%s' % (TTLocalizer.PartyPlannerTimeLocalTime, PartyUtils.formatDateTime(self.partyTime, inLocalTime=True)), pos=self.gui.find('**/step_03_localDateAndTime_loactor').getPos(), textMayChange=True, scale=0.06, text_fg=(1.0, 0.0, 0.0, 1.0)) self.timeInputHourLabel, self.timeInputHourUpButton, self.timeInputHourDownButton = self.getTimeWidgets(page, 'hour') self.timeInputMinuteLabel, self.timeInputMinuteUpButton, self.timeInputMinuteDownButton = self.getTimeWidgets(page, 'minute') self.timeInputAmPmLabel, self.timeInputAmPmUpButton, self.timeInputAmPmDownButton = self.getTimeWidgets(page, 'ampm') self.timePagecolonLabel = DirectLabel(parent=page, relief=None, text=':', pos=self.gui.find('**/step_03_colon_locator').getPos(), scale=0.15) return page def getTimeWidgets(self, page, type): if type == 'ampm': data = self.getCurrentAmPm() else: data = getattr(self.partyTime, type) if data == 0 and type == 'minute': data = '00' else: if type == 'hour': data = data % 12 if data == 0: data = 12 data = '%d' % data label = DirectLabel(parent=page, relief=None, text='%s' % data, textMayChange=True, pos=self.gui.find('**/step_03_%s_locator' % type).getPos(), scale=0.12) def changeValue(self, amount): if type == 'ampm': self.alterPartyTime(hour=(self.partyTime.hour + 12) % 24) newAmount = self.getCurrentAmPm() label['text'] = newAmount else: if type == 'hour': newAmount = getattr(self.partyTime, type) + amount newAmount = newAmount % 12 if self.timeInputAmPmLabel['text'] == TTLocalizer.PartyTimeFormatMeridiemPM: newAmount = newAmount % 12 + 12 self.alterPartyTime(hour=newAmount) elif type == 'minute': newAmount = getattr(self.partyTime, type) + amount self.alterPartyTime(minute=newAmount) else: PartyPlanner.notify.error('Invalid type for changeValue in PartyPlanner: %s' % type) newAmount = getattr(self.partyTime, type) if newAmount < 10 and type == 'minute': label['text'] = '0%d' % newAmount else: if type == 'hour': newAmount = newAmount % 12 if newAmount == 0: newAmount = 12 label['text'] = '%d' % newAmount self.timePageRecapToontownTimeLabel2['text'] = '%s' % PartyUtils.formatDateTime(self.partyTime) self.timePageRecapLocalTimeLabel['text'] = '%s%s' % (TTLocalizer.PartyPlannerTimeLocalTime, PartyUtils.formatDateTime(self.partyTime, inLocalTime=True)) upButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/%sButtonUp_up' % type), self.gui.find('**/%sButtonUp_down' % type), self.gui.find('**/%sButtonUp_rollover' % type)), command=changeValue, extraArgs=[self, self.timeTypeToChangeAmount[type][0]]) downButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/%sButtonDown_up' % type), self.gui.find('**/%sButtonDown_down' % type), self.gui.find('**/%sButtonDown_rollover' % type)), command=changeValue, extraArgs=[self, self.timeTypeToChangeAmount[type][1]]) return (label, upButton, downButton) def getCurrentAmPm(self): if self.partyTime.hour < 12: return TTLocalizer.PartyTimeFormatMeridiemAM else: return TTLocalizer.PartyTimeFormatMeridiemPM def _createGuestPage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerGuestPage') self.guestTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerGuestTitle, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) self.guestBackgroundLabel = DirectLabel(parent=page, relief=None, image=self.gui.find('**/guestListBackground_flat'), scale=(1.2, 1.0, 1.0)) self.friendList = ScrolledFriendList(page, self.gui, makeItemsCheckBoxes=True) if len(base.localAvatar.friendsList) == 0: self.noFriends = True else: self.noFriends = False for friendPair in base.localAvatar.friendsList: self.friendList.addFriend(determineFriendName(friendPair), friendPair[0]) self.friendList.scrollTo(0) pos = self.gui.find('**/step_04_partyWillBe_locator').getPos() self.publicPrivateLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerPublicPrivateLabel, text_align=TextNode.ACenter, text_scale=0.065, pos=pos) self.publicDescriptionLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerPublicDescription, text_align=TextNode.ACenter, text_scale=TTLocalizer.PPpbulicDescriptionLabel, pos=(pos[0] - 0.52, pos[1], pos[2])) self.publicDescriptionLabel.stash() self.privateDescriptionLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerPrivateDescription, text_align=TextNode.ACenter, text_scale=TTLocalizer.PPprivateDescriptionLabel, pos=(pos[0] + 0.55, pos[1], pos[2])) self.privateDescriptionLabel.stash() pos = self.gui.find('**/step_04_public_locator').getPos() self.publicButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/publicButton_up'), self.gui.find('**/publicButton_down'), self.gui.find('**/publicButton_rollover'), self.gui.find('**/publicButton_inactive')), text=TTLocalizer.PartyPlannerPublic, text_pos=(pos[0], pos[2]), text_scale=TTLocalizer.PPpublicButton, command=self.__doTogglePublicPrivate) self.publicButton['state'] = DirectGuiGlobals.DISABLED self.publicButton.bind(DirectGuiGlobals.ENTER, self.__enterPublic) self.publicButton.bind(DirectGuiGlobals.EXIT, self.__exitPublic) pos = self.gui.find('**/step_04_private_locator').getPos() self.privateButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/privateButton_up'), self.gui.find('**/privateButton_down'), self.gui.find('**/privateButton_rollover'), self.gui.find('**/privateButton_inactive')), text=TTLocalizer.PartyPlannerPrivate, text_pos=(pos[0], pos[2]), text_scale=TTLocalizer.PPprivateButton, command=self.__doTogglePublicPrivate) self.privateButton.bind(DirectGuiGlobals.ENTER, self.__enterPrivate) self.privateButton.bind(DirectGuiGlobals.EXIT, self.__exitPrivate) self.checkAllButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/checkAllButton_up'), self.gui.find('**/checkAllButton_down'), self.gui.find('**/checkAllButton_rollover')), command=self.__doCheckAll) self.uncheckAllButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/uncheckAllButton_up'), self.gui.find('**/uncheckAllButton_down'), self.gui.find('**/uncheckAllButton_rollover')), command=self.__doUncheckAll) return page def __doCheckAll(self): for friendBox in self.friendList['items']: friendBox['indicatorValue'] = True def __doUncheckAll(self): for friendBox in self.friendList['items']: friendBox['indicatorValue'] = False def __enterPrivate(self, mouseEvent): self.privateDescriptionLabel.unstash() def __exitPrivate(self, mouseEvent): self.privateDescriptionLabel.stash() def __enterPublic(self, mouseEvent): self.publicDescriptionLabel.unstash() def __exitPublic(self, mouseEvent): self.publicDescriptionLabel.stash() def __doTogglePublicPrivate(self): if self.isPrivate: self.isPrivate = False self.privateButton['state'] = DirectGuiGlobals.NORMAL self.publicButton['state'] = DirectGuiGlobals.DISABLED else: self.isPrivate = True self.privateButton['state'] = DirectGuiGlobals.DISABLED self.publicButton['state'] = DirectGuiGlobals.NORMAL 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 okWithPartyGroundsLayout(self): self.okWithGroundsGui.hide() if self.okWithGroundsGui.doneStatus == 'ok': self.__nextItem() def setNextButtonState(self, enabled): if enabled: self.nextButton['state'] = DirectGuiGlobals.NORMAL self.nextButton.show() else: self.nextButton['state'] = DirectGuiGlobals.DISABLED self.nextButton.hide() def _createInvitationPage(self): self.__handleHolidays() page = DirectFrame(self.frame) page.setName('PartyPlannerInvitationPage') self.invitationTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerConfirmTitle, textMayChange=True, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) self.invitationBackground = DirectFrame(parent=page, relief=None, geom=self.gui.find('**/invitationBackground')) self.inviteVisual = InviteVisual(page) self.selectedInviteThemeLabel = DirectLabel(parent=page, relief=None, pos=self.gui.find('**/step_06_theme_locator').getPos(), text='', text_scale=0.06, textMayChange=True) self.nextThemeButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/topNext_button/nextButton_up'), self.gui.find('**/topNext_button/nextButton_down'), self.gui.find('**/topNext_button/nextButton_rollover')), command=self.__nextTheme) self.prevThemeButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/topPrevious_button/previousButton_up'), self.gui.find('**/topPrevious_button/previousButton_down'), self.gui.find('**/topPrevious_button/previousButton_rollover')), command=self.__prevTheme) pos = self.gui.find('**/step_06_sendInvitation_locator').getPos() self.inviteButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/send_up'), self.gui.find('**/send_down'), self.gui.find('**/send_rollover')), text=TTLocalizer.PartyPlannerInviteButton, textMayChange=True, text_scale=0.05, text_pos=(pos[0], pos[2]), command=self.__handleComplete) return page def __handleHolidays(self): self.inviteThemes = list(range(len(PartyGlobals.InviteTheme))) if hasattr(base.cr, 'newsManager') and base.cr.newsManager: holidayIds = base.cr.newsManager.getHolidayIdList() if ToontownGlobals.VALENTINES_DAY not in holidayIds: self.inviteThemes.remove(PartyGlobals.InviteTheme.Valentoons) if ToontownGlobals.VICTORY_PARTY_HOLIDAY not in holidayIds: self.inviteThemes.remove(PartyGlobals.InviteTheme.VictoryParty) if ToontownGlobals.WINTER_DECORATIONS not in holidayIds and ToontownGlobals.WACKY_WINTER_DECORATIONS not in holidayIds: self.inviteThemes.remove(PartyGlobals.InviteTheme.Winter) def _createFarewellPage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerFarewellPage') self.confirmTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerConfirmationAllOkTitle, textMayChange=True, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) pos = self.gui.find('**/step_07_close_text_locator').getPos() self.closePlannerButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/close_up'), self.gui.find('**/close_down'), self.gui.find('**/close_rollover')), text=TTLocalizer.PartyPlannerClosePlanner, text_scale=0.055, text_pos=(pos[0], pos[2]), command=self.__acceptExit) return page def close(self): self.ignore('addPartyResponseReceived') self.ignore(localAvatar.uniqueName('moneyChange')) self.ignore(localAvatar.uniqueName('bankMoneyChange')) self.timeInputHourUpButton.destroy() self.timeInputHourDownButton.destroy() self.timeInputMinuteUpButton.destroy() self.timeInputMinuteDownButton.destroy() self.timeInputAmPmUpButton.destroy() self.timeInputAmPmDownButton.destroy() self.privateButton.destroy() self.publicButton.destroy() self.makePartyNowButton.destroy() self.checkAllButton.destroy() self.uncheckAllButton.destroy() self.elementBuyButton.destroy() self.nextThemeButton.destroy() self.prevThemeButton.destroy() self.inviteButton.destroy() self.closePlannerButton.destroy() self.ignore(self.okWithPartyGroundsLayoutEvent) if hasattr(self, 'okWithGroundsGui'): self.okWithGroundsGui.cleanup() del self.okWithGroundsGui if hasattr(self, 'frame') and not self.frame.isEmpty(): messenger.send(self.doneEvent) self.hide() self.cleanup() self.friendList.removeAndDestroyAllItems() self.friendList.destroy() self.calendarGuiMonth.destroy() self.frame.destroy() self.partyPlannerHead.delete() self.partyPlannerHead.removeNode() self.clearNametag() self.partyEditor.request('Cleanup') self.partyEditor = None self.destroy() del self return def __handleComplete(self): self.inviteButton['state'] = DirectGuiGlobals.DISABLED self.prevButton['state'] = DirectGuiGlobals.DISABLED endTime = self.partyTime + self.partyDuration hostId = base.localAvatar.doId self.partyActivities = self.partyEditor.partyEditorGrid.getActivitiesOnGrid() decorations = self.partyEditor.partyEditorGrid.getDecorationsOnGrid() invitees = self.getInvitees() self.accept('addPartyResponseReceived', self.processAddPartyResponse) base.cr.partyManager.sendAddParty(hostId, self.partyTime.strftime('%Y-%m-%d %H:%M:%S'), endTime.strftime('%Y-%m-%d %H:%M:%S'), self.isPrivate, self.currentInvitationTheme, self.partyActivities, decorations, invitees) def getInvitees(self): invitees = [] for friendBox in self.friendList['items']: if friendBox['indicatorValue']: invitees.append(friendBox.getPythonTag('id')) return invitees def processAddPartyResponse(self, hostId, errorCode): PartyPlanner.notify.debug('processAddPartyResponse : hostId=%d errorCode=%s' % (hostId, PartyGlobals.AddPartyErrorCode.getString(errorCode))) goingBackAllowed = False if errorCode == PartyGlobals.AddPartyErrorCode.AllOk: goingBackAllowed = False self.confirmTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmationAllOkTitle if self.noFriends or len(self.getInvitees()) == 0: confirmRecapText = TTLocalizer.PartyPlannerConfirmationAllOkTextNoFriends else: confirmRecapText = TTLocalizer.PartyPlannerConfirmationAllOkText elif errorCode == PartyGlobals.AddPartyErrorCode.ValidationError: self.confirmTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle confirmRecapText = TTLocalizer.PartyPlannerConfirmationValidationErrorText elif errorCode == PartyGlobals.AddPartyErrorCode.DatabaseError: self.confirmTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle confirmRecapText = TTLocalizer.PartyPlannerConfirmationDatabaseErrorText elif errorCode == PartyGlobals.AddPartyErrorCode.TooManyHostedParties: goingBackAllowed = False self.confirmTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle confirmRecapText = TTLocalizer.PartyPlannerConfirmationTooManyText self.nametagGroup.setChat(confirmRecapText, CFSpeech) self.request('Farewell', goingBackAllowed) def __acceptExit(self): PartyPlanner.notify.debug('__acceptExit') if hasattr(self, 'frame'): self.hide() messenger.send(self.doneEvent) def __nextItem(self): messenger.send('wakeup') if self.state == 'PartyEditor' and self.okWithGroundsGui.doneStatus != 'ok': self.okWithGroundsGui.show() return if self.state == 'PartyEditor' and self.noFriends: self.request('Date') self.selectedCalendarGuiDay = None self.calendarGuiMonth.clearSelectedDay() return if self.state == 'Guests': self.selectedCalendarGuiDay = None self.calendarGuiMonth.clearSelectedDay() if self.state == 'Time': if self.partyTime < base.cr.toontownTimeManager.getCurServerDateTime(): self.okChooseFutureTimeEvent = 'okChooseFutureTimeEvent' self.acceptOnce(self.okChooseFutureTimeEvent, self.okChooseFutureTime) self.chooseFutureTimeDialog = TTDialog.TTGlobalDialog(dialogName=self.uniqueName('chooseFutureTimeDialog'), doneEvent=self.okChooseFutureTimeEvent, message=TTLocalizer.PartyPlannerChooseFutureTime, style=TTDialog.Acknowledge) self.chooseFutureTimeDialog.show() return self.requestNext() return def okChooseFutureTime(self): if hasattr(self, 'chooseFutureTimeDialog'): self.chooseFutureTimeDialog.cleanup() del self.chooseFutureTimeDialog if hasattr(self, 'okChooseFutureTimeEvent'): self.ignore(self.okChooseFutureTimeEvent) def __prevItem(self): messenger.send('wakeup') if self.state == 'Date' and self.noFriends: self.request('PartyEditor') return if self.state == 'Invitation' and self.selectedCalendarGuiDay is None: self.request('Guests') return self.requestPrev() return def __moneyChange(self, newMoney): if hasattr(self, 'totalMoney'): self.totalMoney = base.localAvatar.getTotalMoney() if hasattr(self, 'beanBank'): self.beanBank['text'] = str(int(self.totalMoney))
class PartyEditorGridElement(DirectButton): __module__ = __name__ notify = directNotify.newCategory('PartyEditorGridElement') def __init__(self, partyEditor, id, isDecoration, checkSoldOutAndPaidStatusAndAffordability, **kw): self.partyEditor = partyEditor self.id = id self.isDecoration = isDecoration self.checkSoldOutAndPaidStatusAndAffordability = checkSoldOutAndPaidStatusAndAffordability if self.isDecoration: self.name = TTLocalizer.PartyDecorationNameDict[self.id]['editor'] colorList = ((1.0, 1.0, 1.0, 1.0), (0.0, 0.0, 1.0, 1.0), (0.0, 1.0, 1.0, 1.0), (0.5, 0.5, 0.5, 1.0)) self.geom = self.partyEditor.partyPlanner.gui.find('**/%s' % PartyGlobals.DecorationInformationDict[self.id]['gridAsset']) else: self.name = TTLocalizer.PartyActivityNameDict[self.id]['editor'] colorList = ((1.0, 1.0, 1.0, 1.0), (0.0, 1.0, 0.0, 1.0), (1.0, 1.0, 0.0, 1.0), (0.5, 0.5, 0.5, 1.0)) self.geom = self.partyEditor.partyPlanner.gui.find('**/%s' % PartyGlobals.ActivityInformationDict[self.id]['gridAsset']) optiondefs = (('geom', self.geom, None), ('geom_scale', 1.0, None), ('geom_color', colorList[0], None), ('geom1_color', colorList[0], None), ('geom2_color', colorList[0], None), ('geom3_color', colorList[0], None), ('relief', None, None)) self.defineoptions(kw, optiondefs) DirectButton.__init__(self, self.partyEditor.parent) self.initialiseoptions(PartyEditorGridElement) self.setName('%sGridElement' % self.name) self.bind(DirectGuiGlobals.B1PRESS, self.clicked) self.bind(DirectGuiGlobals.B1RELEASE, self.released) self.bind(DirectGuiGlobals.ENTER, self.mouseEnter) self.bind(DirectGuiGlobals.EXIT, self.mouseExit) self.uprightNodePath = NodePath('%sUpright' % self.name) self.uprightNodePath.reparentTo(self) rollOverZOffset = self.getGridSize()[1] / 30.0 self.rolloverTitle = DirectLabel(relief=None, parent=self.uprightNodePath, pos=Point3(0.0, 0.0, rollOverZOffset), text=self.name, text_fg=(1.0, 1.0, 1.0, 1.0), text_shadow=(0.0, 0.0, 0.0, 1.0), text_scale=0.075) self.rolloverTitle.stash() self.stash() self.overValidSquare = False self.lastValidPosition = None self.setColorScale(0.9, 0.9, 0.9, 0.7) self.setTransparency(True) self.mouseOverTrash = False self.centerGridSquare = None return def getCorrectRotation(self): r = self.getR() if r == 90.0: r = 270.0 elif r == 270.0: r = 90.0 if self.id == PartyGlobals.ActivityIds.PartyCannon: return PartyUtils.convertDegreesToPartyGrid(r + 180.0) return PartyUtils.convertDegreesToPartyGrid(r) def getDecorationTuple(self, x, y): return (self.id, self.centerGridSquare.x, PartyGlobals.PartyEditorGridSize[1] - 1 - self.centerGridSquare.y, self.getCorrectRotation()) def getActivityTuple(self, x, y): return (self.id, self.centerGridSquare.x, PartyGlobals.PartyEditorGridSize[1] - 1 - self.centerGridSquare.y, self.getCorrectRotation()) def attach(self, mouseEvent): PartyEditorGridElement.notify.debug('attached grid element %s' % self.name) taskMgr.remove('gridElementDragTask%s' % self.name) vWidget2render2d = self.getPos(render2d) vMouse2render2d = Point3(mouseEvent.getMouse()[0], 0, mouseEvent.getMouse()[1]) taskMgr.add(self.elementDragTask, 'gridElementDragTask%s' % self.name) self.unstash() self.rolloverTitle.unstash() self.uprightNodePath.reparentTo(self) self.setPosHprToDefault() def elementDragTask(self, state): mwn = base.mouseWatcherNode if mwn.hasMouse(): vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1]) newPos = vMouse2render2d if newPos[0] > PartyGlobals.PartyEditorGridBounds[0][0] and newPos[0] < PartyGlobals.PartyEditorGridBounds[1][0] and newPos[2] < PartyGlobals.PartyEditorGridBounds[0][1] and newPos[2] > PartyGlobals.PartyEditorGridBounds[1][1]: centerGridSquare = self.snapToGrid(newPos) if centerGridSquare is not None: self.centerGridSquare = centerGridSquare if not self.overValidSquare: self.setOverValidSquare(True) if self.mouseOverTrash: self.setOverTrash(False) return Task.cont if self.id != PartyGlobals.ActivityIds.PartyClock and newPos[0] > PartyGlobals.PartyEditorTrashBounds[0][0] and newPos[0] < PartyGlobals.PartyEditorTrashBounds[1][0] and newPos[2] < PartyGlobals.PartyEditorTrashBounds[0][1] and newPos[2] > PartyGlobals.PartyEditorTrashBounds[1][1]: if not self.mouseOverTrash: self.setOverTrash(True) elif self.mouseOverTrash: self.setOverTrash(False) self.setPos(render2d, newPos) if self.overValidSquare: self.setOverValidSquare(False) return Task.cont def setOverTrash(self, value): self.mouseOverTrash = value if value: self.partyEditor.trashCanButton['state'] = DirectGuiGlobals.DISABLED self.setColorScale(1.0, 0.0, 0.0, 1.0) else: self.partyEditor.trashCanButton['state'] = DirectGuiGlobals.NORMAL self.setColorScale(0.9, 0.9, 0.9, 0.7) def setOverValidSquare(self, value): self.overValidSquare = value if value: self.setColorScale(1.0, 1.0, 1.0, 1.0) else: self.setColorScale(0.9, 0.9, 0.9, 0.7) def removeFromGrid(self): if self.centerGridSquare is not None: self.partyEditor.partyEditorGrid.removeElement(self.centerGridSquare, self.getGridSize()) self.setOverValidSquare(False) self.lastValidPosition = None self.stash() return def snapToGrid(self, newPos): gridSquare = self.getGridSquareFromPosition(newPos) if gridSquare == None: self.setPosHprToDefault() self.setPos(render2d, newPos) return elif not self.partyEditor.partyEditorGrid.checkGridSquareForAvailability(gridSquare, self.getGridSize()): self.setPos(render2d, newPos) return self.setPosHprBasedOnGridSquare(gridSquare) return gridSquare def getGridSize(self): if self.isDecoration: return PartyGlobals.DecorationInformationDict[self.id]['gridsize'] else: return PartyGlobals.ActivityInformationDict[self.id]['gridsize'] def setPosHprToDefault(self): self.setR(0.0) self.uprightNodePath.setR(0.0) def setPosHprBasedOnGridSquare(self, gridSquare): gridPos = gridSquare.getPos() if self.getGridSize()[0] % 2 == 0: gridPos.setX(gridPos[0] + PartyGlobals.PartyEditorGridSquareSize[0] / 2.0) if self.getGridSize()[1] % 2 == 0: gridPos.setZ(gridPos[2] + PartyGlobals.PartyEditorGridSquareSize[1] / 2.0) if self.id != PartyGlobals.ActivityIds.PartyFireworks: if gridPos[0] > PartyGlobals.PartyEditorGridCenter[0] + PartyGlobals.PartyEditorGridRotateThreshold: self.setR(90.0) self.uprightNodePath.setR(-90.0) elif gridPos[0] < PartyGlobals.PartyEditorGridCenter[0] - PartyGlobals.PartyEditorGridRotateThreshold: self.setR(270.0) self.uprightNodePath.setR(-270.0) elif gridPos[2] < PartyGlobals.PartyEditorGridCenter[1] - PartyGlobals.PartyEditorGridRotateThreshold: self.setR(180.0) self.uprightNodePath.setR(-180.0) else: self.setR(0.0) self.uprightNodePath.setR(0.0) else: self.setR(270.0) self.uprightNodePath.setR(-270.0) self.setPos(render2d, gridPos) self.lastValidPosition = gridPos def getGridSquareFromPosition(self, newPos): localX = newPos[0] - PartyGlobals.PartyEditorGridBounds[0][0] localY = newPos[2] - PartyGlobals.PartyEditorGridBounds[1][1] x = int(localX / PartyGlobals.PartyEditorGridSquareSize[0]) y = int(localY / PartyGlobals.PartyEditorGridSquareSize[1]) y = PartyGlobals.PartyEditorGridSize[1] - 1 - y return self.partyEditor.partyEditorGrid.getGridSquare(x, y) def detach(self, mouseEvent): taskMgr.remove('gridElementDragTask%s' % self.name) self.rolloverTitle.stash() if self.overValidSquare: self.partyEditor.partyEditorGrid.registerNewElement(self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.handleMutuallyExclusiveActivities() elif self.lastValidPosition is not None: if self.mouseOverTrash: self.partyEditor.trashCanButton['state'] = DirectGuiGlobals.NORMAL self.lastValidPosition = None self.partyEditor.updateCostsAndBank() self.stash() else: self.setPos(render2d, self.lastValidPosition) self.setOverValidSquare(True) self.partyEditor.partyEditorGrid.registerNewElement(self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.handleMutuallyExclusiveActivities() else: self.stash() self.checkSoldOutAndPaidStatusAndAffordability() return def placeInPartyGrounds(self, desiredXY = None): self.centerGridSquare = self.partyEditor.partyEditorGrid.getClearGridSquare(self.getGridSize(), desiredXY) if self.centerGridSquare is not None: self.setOverValidSquare(True) self.unstash() self.setPosHprBasedOnGridSquare(self.centerGridSquare) self.partyEditor.partyEditorGrid.registerNewElement(self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsPartyGrounds self.checkSoldOutAndPaidStatusAndAffordability() return True else: return False return def clicked(self, mouseEvent): PartyEditorGridElement.notify.debug('clicked grid element %s' % self.name) if self.centerGridSquare is not None: self.attach(mouseEvent) self.partyEditor.partyEditorGrid.removeElement(self.centerGridSquare, self.getGridSize()) return def released(self, mouseEvent): PartyEditorGridElement.notify.debug('released grid element %s' % self.name) self.detach(mouseEvent) def mouseEnter(self, mouseEvent): parent = self.getParent() self.reparentTo(parent) self.rolloverTitle.unstash() def mouseExit(self, mouseEvent): self.rolloverTitle.stash() def destroy(self): self.unbind(DirectGuiGlobals.B1PRESS) self.unbind(DirectGuiGlobals.B1RELEASE) self.unbind(DirectGuiGlobals.ENTER) self.unbind(DirectGuiGlobals.EXIT) DirectButton.destroy(self)
class PartyPlanner(DirectFrame, FSM): notify = DirectNotifyGlobal.directNotify.newCategory('PartyPlanner') def __init__(self, doneEvent = None): FSM.__init__(self, 'PartyPlannerFSM') DirectFrame.__init__(self) self.doneEvent = doneEvent self.stateArray = ['Off', 'Welcome', 'PartyEditor', 'Guests', 'Date', 'Time', 'Invitation', 'Farewell'] self.partyTime = base.cr.toontownTimeManager.getCurServerDateTime() self.partyNowTime = base.cr.toontownTimeManager.getCurServerDateTime() minutesToNextFifteen = 15 - self.partyTime.minute % 15 self.cleanPartyTime = self.partyTime + timedelta(minutes=minutesToNextFifteen, seconds=-self.partyTime.second) self.partyTime = self.cleanPartyTime self.guests = [] self.isPrivate = False self.selectedCalendarGuiDay = None self.gui = loader.loadModel('phase_4/models/parties/partyPlannerGUI') self.partyDuration = timedelta(hours=PartyGlobals.DefaultPartyDuration) self.timeTypeToMaxValue = {'hour': 23, 'minute': 59} self.timeTypeToChangeAmount = {'hour': (1, -1), 'minute': (15, -15), 'ampm': (1, -1)} self.partyInfo = None self.asapMinuteRounding = base.config.GetInt('party-asap-minute-rounding', PartyGlobals.PartyPlannerAsapMinuteRounding) self.load() self.request('Welcome') return def enterWelcome(self, *args): self.prevButton['state'] = DirectGuiGlobals.DISABLED self.prevButton.hide() self.nextButton['state'] = DirectGuiGlobals.NORMAL self.welcomePage.show() self.partyPlannerHead.reparentTo(self.welcomePage) self.partyPlannerHead.startBlink() self.partyPlannerHead.startLookAround() self.nametagNP.reparentTo(self.welcomePage) self.chatNP.reparentTo(self.welcomePage) def exitWelcome(self): self.welcomePage.hide() self.prevButton.show() self.partyPlannerHead.stopBlink() self.partyPlannerHead.stopLookAround() def enterPartyEditor(self, *args): self.prevButton['state'] = DirectGuiGlobals.NORMAL self.nextButton['state'] = DirectGuiGlobals.DISABLED self.nextButton.hide() self.partyEditorPage.show() self.okWithGroundsGui.doneStatus = '' self.partyEditor.request('Idle') def exitPartyEditor(self): self.partyEditor.request('Hidden') self.partyEditorPage.hide() def enterGuests(self, *args): self.prevButton['state'] = DirectGuiGlobals.NORMAL self.nextButton['state'] = DirectGuiGlobals.NORMAL self.nextButton.show() self.guestPage.show() def exitGuests(self): self.guests = [] for friendCheckBox in self.friendList['items']: if friendCheckBox['indicatorValue']: self.guests.append(friendCheckBox.getPythonTag('id')) self.guestPage.hide() def enterDate(self, *args): self.prevButton.show() self.prevButton['state'] = DirectGuiGlobals.NORMAL if self.selectedCalendarGuiDay is None: self.nextButton['state'] = DirectGuiGlobals.DISABLED self.nextButton.hide() self.makePartyNowButton.show() self.datePage.show() return def exitDate(self): self.datePage.hide() self.nextButton.show() if self.selectedCalendarGuiDay is not None: self.partyTime = self.cleanPartyTime self.alterPartyTime(year=self.selectedCalendarGuiDay.myDate.year, month=self.selectedCalendarGuiDay.myDate.month, day=self.selectedCalendarGuiDay.myDate.day) else: self.partyNowTime = self.calcAsapTime() self.partyTime = self.partyNowTime return def calcAsapTime(self): curServerTime = base.cr.toontownTimeManager.getCurServerDateTime() baseTime = curServerTime baseTime = baseTime.replace(baseTime.year, baseTime.month, baseTime.day, baseTime.hour, baseTime.minute, second=0, microsecond=0) minute = curServerTime.minute remainder = minute % self.asapMinuteRounding if remainder: baseTime += timedelta(minutes=self.asapMinuteRounding - remainder) else: baseTime += timedelta(minutes=self.asapMinuteRounding) return baseTime def enterTime(self, *args): self.prevButton.show() self.prevButton['state'] = DirectGuiGlobals.NORMAL self.nextButton.show() self.timePage.show() self.timePageRecapToontownTimeLabel2['text'] = '%s' % PartyUtils.formatDateTime(self.partyTime) self.timePageRecapLocalTimeLabel['text'] = '%s%s' % (TTLocalizer.PartyPlannerTimeLocalTime, PartyUtils.formatDateTime(self.partyTime, inLocalTime=True)) def exitTime(self): self.timePage.hide() self.nextButton.show() def enterInvitation(self, *args): self.prevButton['state'] = DirectGuiGlobals.NORMAL self.nextButton.hide() defaultInviteTheme = PartyGlobals.InviteTheme.GenericMale if hasattr(base.cr, 'newsManager') and base.cr.newsManager: if ToontownGlobals.VICTORY_PARTY_HOLIDAY in base.cr.newsManager.getHolidayIdList(): defaultInviteTheme = PartyGlobals.InviteTheme.VictoryParty elif ToontownGlobals.KARTING_TICKETS_HOLIDAY in base.cr.newsManager.getHolidayIdList() or ToontownGlobals.CIRCUIT_RACING_EVENT in base.cr.newsManager.getHolidayIdList(): defaultInviteTheme = PartyGlobals.InviteTheme.Racing elif ToontownGlobals.VALENTINES_DAY in base.cr.newsManager.getHolidayIdList(): defaultInviteTheme = PartyGlobals.InviteTheme.Valentoons if self.partyInfo is not None: del self.partyInfo activityList = self.partyEditor.partyEditorGrid.getActivitiesOnGrid() decorationList = self.partyEditor.partyEditorGrid.getDecorationsOnGrid() endTime = self.partyTime + self.partyDuration self.partyInfo = PartyInfo(0, 0, self.partyTime.year, self.partyTime.month, self.partyTime.day, self.partyTime.hour, self.partyTime.minute, endTime.year, endTime.month, endTime.day, endTime.hour, endTime.minute, self.isPrivate, defaultInviteTheme, activityList, decorationList, 0) if self.noFriends or len(self.getInvitees()) == 0: self.inviteVisual.setNoFriends(True) self.invitationTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmTitleNoFriends self.inviteButton['text'] = TTLocalizer.PartyPlannerInviteButtonNoFriends self.selectedInviteThemeLabel.stash() self.nextThemeButton.stash() self.prevThemeButton.stash() self.setInviteTheme(defaultInviteTheme) else: self.inviteVisual.setNoFriends(False) self.invitationTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmTitle self.inviteButton['text'] = TTLocalizer.PartyPlannerInviteButton self.selectedInviteThemeLabel.unstash() self.nextThemeButton.unstash() self.prevThemeButton.unstash() self.setInviteTheme(defaultInviteTheme) self.inviteVisual.updateInvitation(base.localAvatar.getName(), self.partyInfo) self.invitationPage.show() return def __prevTheme(self): self.nextThemeButton.show() prevTheme = self.currentInvitationTheme - 1 while prevTheme not in self.inviteThemes: prevTheme -= 1 if prevTheme == self.currentInvitationTheme: self.notify.warning('No previous invite theme found.') break elif prevTheme < 0: prevTheme = len(self.inviteVisual.inviteThemesIdToInfo) - 1 self.setInviteTheme(prevTheme) def __nextTheme(self): self.prevThemeButton.show() nextTheme = self.currentInvitationTheme + 1 while nextTheme not in self.inviteThemes: nextTheme += 1 if nextTheme == self.currentInvitationTheme: self.notify.warning('No next invite theme found.') break elif nextTheme >= len(self.inviteVisual.inviteThemesIdToInfo): nextTheme = 0 self.setInviteTheme(nextTheme) def setInviteTheme(self, themeNumber): self.currentInvitationTheme = themeNumber self.selectedInviteThemeLabel['text'] = '%s %s (%d/%d)' % (self.inviteVisual.inviteThemesIdToInfo[self.currentInvitationTheme][1], TTLocalizer.PartyPlannerInvitationTheme, self.inviteThemes.index(self.currentInvitationTheme) + 1, len(self.inviteThemes)) self.partyInfo.inviteTheme = self.currentInvitationTheme self.inviteVisual.updateInvitation(base.localAvatar.getName(), self.partyInfo) def exitInvitation(self): self.invitationPage.hide() self.nextButton.show() def enterFarewell(self, goingBackAllowed): self.farewellPage.show() if goingBackAllowed: self.prevButton.show() else: self.prevButton.hide() self.nextButton.hide() self.partyPlannerHead.reparentTo(self.farewellPage) self.partyPlannerHead.startBlink() self.partyPlannerHead.startLookAround() self.nametagNP.reparentTo(self.farewellPage) self.chatNP.reparentTo(self.farewellPage) def exitFarewell(self): self.farewellPage.hide() self.nextButton.show() self.prevButton.show() self.partyPlannerHead.stopBlink() self.partyPlannerHead.stopLookAround() def load(self): self.frame = DirectFrame(parent=aspect2d, geom=self.gui.find('**/background'), relief=None, scale=0.85, pos=(0.05, 0.0, 0.1)) self.titleScale = TTLocalizer.PPtitleScale self._createNavButtons() self.welcomePage = self._createWelcomePage() self.welcomePage.hide() self.datePage = self._createDatePage() self.datePage.hide() self.timePage = self._createTimePage() self.timePage.hide() self.guestPage = self._createGuestPage() self.guestPage.hide() self.partyEditorPage = self._createPartyEditorPage() self.partyEditorPage.hide() self.invitationPage = self._createInvitationPage() self.invitationPage.hide() self.farewellPage = self._createFarewellPage() self.farewellPage.hide() return def _createNavButtons(self): self.quitButton = DirectButton(parent=self.frame, relief=None, geom=(self.gui.find('**/cancelButton_up'), self.gui.find('**/cancelButton_down'), self.gui.find('**/cancelButton_rollover')), command=self.__acceptExit) self.nextButton = DirectButton(parent=self.frame, relief=None, geom=(self.gui.find('**/bottomNext_button/nextButton_up'), self.gui.find('**/bottomNext_button/nextButton_down'), self.gui.find('**/bottomNext_button/nextButton_rollover')), command=self.__nextItem, state=DirectGuiGlobals.DISABLED) self.prevButton = DirectButton(parent=self.frame, relief=None, geom=(self.gui.find('**/bottomPrevious_button/previousButton_up'), self.gui.find('**/bottomPrevious_button/previousButton_down'), self.gui.find('**/bottomPrevious_button/previousButton_rollover')), command=self.__prevItem, state=DirectGuiGlobals.DISABLED) self.currentItem = None return def __createNametag(self, parent): if self.nametagGroup == None: self.nametagGroup = NametagGroup() self.nametagGroup.setFont(OTPGlobals.getInterfaceFont()) self.nametagGroup.setActive(0) self.nametagGroup.setAvatar(self.partyPlannerHead) self.nametagGroup.manage(base.marginManager) self.nametagGroup.setColorCode(self.nametagGroup.CCNonPlayer) self.nametagGroup.getNametag2d().setContents(0) self.nametagNode = NametagFloat2d() self.nametagNode.setContents(Nametag.CName) self.nametagGroup.addNametag(self.nametagNode) self.nametagGroup.setName(base.cr.partyManager.getPartyPlannerName()) self.nametagNP = parent.attachNewNode(self.nametagNode.upcastToPandaNode()) nametagPos = self.gui.find('**/step_01_partymanPeteNametag_locator').getPos() self.nametagNP.setPosHprScale(nametagPos[0], 0, nametagPos[2], 0, 0, 0, 0.1, 1, 0.1) self.chatNode = NametagFloat2d() self.chatNode.setContents(Nametag.CSpeech | Nametag.CThought) self.nametagGroup.addNametag(self.chatNode) self.nametagGroup.setChat(TTLocalizer.PartyPlannerInstructions, CFSpeech) self.chatNP = parent.attachNewNode(self.chatNode.upcastToPandaNode()) chatPos = self.gui.find('**/step_01_partymanPeteText_locator').getPos() self.chatNP.setPosHprScale(chatPos[0], 0, chatPos[2], 0, 0, 0, 0.08, 1, 0.08) return def clearNametag(self): if self.nametagGroup != None: self.nametagGroup.unmanage(base.marginManager) self.nametagGroup.removeNametag(self.nametagNode) self.nametagGroup.removeNametag(self.chatNode) self.nametagNP.removeNode() self.chatNP.removeNode() del self.nametagNP del self.chatNP del self.nametagNode del self.chatNode self.nametagGroup.setAvatar(NodePath()) self.nametagGroup = None return def _createWelcomePage(self): self.nametagGroup = None page = DirectFrame(self.frame) page.setName('PartyPlannerWelcomePage') self.welcomeTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerWelcomeTitle, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) self.partyPlannerHead = ToonHead.ToonHead() partyPlannerStyle = base.cr.partyManager.getPartyPlannerStyle() self.partyPlannerHead.setupHead(partyPlannerStyle, forGui=True) self.partyPlannerHead.setPos(self.gui.find('**/step_01_partymanPete_locator').getPos()) animal = partyPlannerStyle.getAnimal() if animal == 'cat' or animal == 'pig': headScale = 0.4 elif animal == 'dog' or animal == 'bear': headScale = 0.45 elif animal == 'rabbit': headScale = 0.35 else: headScale = 0.3 self.partyPlannerHead.setScale(headScale) self.partyPlannerHead.setH(180.0) self.partyPlannerHead.reparentTo(page) self.__createNametag(page) return page def _createDatePage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerDatePage') self.createDateTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerDateTitle, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) pos = self.gui.find('**/step_06_sendInvitation_locator').getPos() self.makePartyNowButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/send_up'), self.gui.find('**/send_down'), self.gui.find('**/send_rollover')), text=TTLocalizer.PartyPlannerPartyNow, text_pos=(pos[0], pos[2]), text_scale=0.05, command=self.__doMakePartyNow) curServerDate = base.cr.toontownTimeManager.getCurServerDateTime() self.calendarGuiMonth = CalendarGuiMonth(page, curServerDate, scale=0.95, pos=(-0.05, 0.0, -0.33), dayClickCallback=self._dayClickCallback, onlyFutureDaysClickable=True) return page def __doMakePartyNow(self): self.request('Invitation') def _dayClickCallback(self, calendarGuiDay): self.selectedCalendarGuiDay = calendarGuiDay self.nextButton['state'] = DirectGuiGlobals.NORMAL self.makePartyNowButton.hide() self.nextButton.show() def alterPartyTime(self, year = None, month = None, day = None, hour = None, minute = None): self.partyTime = datetime(year=self.positiveTime('year', year), month=self.positiveTime('month', month), day=self.positiveTime('day', day), hour=self.positiveTime('hour', hour), minute=self.positiveTime('minute', minute), tzinfo=self.partyTime.tzinfo) def positiveTime(self, type, amount): if amount is None: return getattr(self.partyTime, type) if type == 'hour' or type == 'minute': if amount < 0: return self.timeTypeToMaxValue[type] + 1 + self.timeTypeToChangeAmount[type][1] elif amount > self.timeTypeToMaxValue[type]: return 0 return amount def _createTimePage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerTimePage') self.createTimeTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeTitle, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) self.clockImage = DirectFrame(parent=page, relief=None, geom=self.gui.find('**/toontownTime_background')) self.timePageToontownLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeToontown, pos=self.gui.find('**/step_03_toontown_locator').getPos(), scale=0.15, text_fg=(1.0, 0.0, 0.0, 1.0), text_font=ToontownGlobals.getSignFont()) self.timePageTimeLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeTime, pos=self.gui.find('**/step_03_time_locator').getPos(), scale=0.15, text_fg=(1.0, 0.0, 0.0, 1.0), text_font=ToontownGlobals.getSignFont()) self.timePageRecapLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeRecap, pos=self.gui.find('**/step_03_partyDateAndTime_locator').getPos(), scale=0.09) self.timePageRecapToontownTimeLabel1 = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerTimeToontownTime, pos=self.gui.find('**/step_03_toontownTime_locator').getPos(), scale=0.06) self.timePageRecapToontownTimeLabel2 = DirectLabel(parent=page, relief=None, text='%s' % PartyUtils.formatDateTime(self.partyTime), pos=self.gui.find('**/step_03_toontownDateAndTime_loactor').getPos(), textMayChange=True, scale=0.06) self.timePageRecapLocalTimeLabel = DirectLabel(parent=page, relief=None, text='%s%s' % (TTLocalizer.PartyPlannerTimeLocalTime, PartyUtils.formatDateTime(self.partyTime, inLocalTime=True)), pos=self.gui.find('**/step_03_localDateAndTime_loactor').getPos(), textMayChange=True, scale=0.06, text_fg=(1.0, 0.0, 0.0, 1.0)) self.timeInputHourLabel, self.timeInputHourUpButton, self.timeInputHourDownButton = self.getTimeWidgets(page, 'hour') self.timeInputMinuteLabel, self.timeInputMinuteUpButton, self.timeInputMinuteDownButton = self.getTimeWidgets(page, 'minute') self.timeInputAmPmLabel, self.timeInputAmPmUpButton, self.timeInputAmPmDownButton = self.getTimeWidgets(page, 'ampm') self.timePagecolonLabel = DirectLabel(parent=page, relief=None, text=':', pos=self.gui.find('**/step_03_colon_locator').getPos(), scale=0.15) return page def getTimeWidgets(self, page, type): if type == 'ampm': data = self.getCurrentAmPm() else: data = getattr(self.partyTime, type) if data == 0 and type == 'minute': data = '00' else: if type == 'hour': data = data % 12 if data == 0: data = 12 data = '%d' % data label = DirectLabel(parent=page, relief=None, text='%s' % data, textMayChange=True, pos=self.gui.find('**/step_03_%s_locator' % type).getPos(), scale=0.12) def changeValue(self, amount): if type == 'ampm': self.alterPartyTime(hour=(self.partyTime.hour + 12) % 24) newAmount = self.getCurrentAmPm() label['text'] = newAmount else: if type == 'hour': newAmount = getattr(self.partyTime, type) + amount newAmount = newAmount % 12 if self.timeInputAmPmLabel['text'] == TTLocalizer.PartyTimeFormatMeridiemPM: newAmount = newAmount % 12 + 12 self.alterPartyTime(hour=newAmount) elif type == 'minute': newAmount = getattr(self.partyTime, type) + amount self.alterPartyTime(minute=newAmount) else: PartyPlanner.notify.error('Invalid type for changeValue in PartyPlanner: %s' % type) newAmount = getattr(self.partyTime, type) if newAmount < 10 and type == 'minute': label['text'] = '0%d' % newAmount else: if type == 'hour': newAmount = newAmount % 12 if newAmount == 0: newAmount = 12 label['text'] = '%d' % newAmount self.timePageRecapToontownTimeLabel2['text'] = '%s' % PartyUtils.formatDateTime(self.partyTime) self.timePageRecapLocalTimeLabel['text'] = '%s%s' % (TTLocalizer.PartyPlannerTimeLocalTime, PartyUtils.formatDateTime(self.partyTime, inLocalTime=True)) upButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/%sButtonUp_up' % type), self.gui.find('**/%sButtonUp_down' % type), self.gui.find('**/%sButtonUp_rollover' % type)), command=changeValue, extraArgs=[self, self.timeTypeToChangeAmount[type][0]]) downButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/%sButtonDown_up' % type), self.gui.find('**/%sButtonDown_down' % type), self.gui.find('**/%sButtonDown_rollover' % type)), command=changeValue, extraArgs=[self, self.timeTypeToChangeAmount[type][1]]) return (label, upButton, downButton) def getCurrentAmPm(self): if self.partyTime.hour < 12: return TTLocalizer.PartyTimeFormatMeridiemAM else: return TTLocalizer.PartyTimeFormatMeridiemPM def _createGuestPage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerGuestPage') self.guestTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerGuestTitle, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) self.guestBackgroundLabel = DirectLabel(parent=page, relief=None, image=self.gui.find('**/guestListBackground_flat'), scale=(1.2, 1.0, 1.0)) self.friendList = ScrolledFriendList(page, self.gui, makeItemsCheckBoxes=True) if len(base.localAvatar.friendsList) == 0: self.noFriends = True else: self.noFriends = False for friendPair in base.localAvatar.friendsList: self.friendList.addFriend(determineFriendName(friendPair), friendPair[0]) self.friendList.scrollTo(0) pos = self.gui.find('**/step_04_partyWillBe_locator').getPos() self.publicPrivateLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerPublicPrivateLabel, text_align=TextNode.ACenter, text_scale=0.065, pos=pos) self.publicDescriptionLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerPublicDescription, text_align=TextNode.ACenter, text_scale=TTLocalizer.PPpbulicDescriptionLabel, pos=(pos[0] - 0.52, pos[1], pos[2])) self.publicDescriptionLabel.stash() self.privateDescriptionLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerPrivateDescription, text_align=TextNode.ACenter, text_scale=TTLocalizer.PPprivateDescriptionLabel, pos=(pos[0] + 0.55, pos[1], pos[2])) self.privateDescriptionLabel.stash() pos = self.gui.find('**/step_04_public_locator').getPos() self.publicButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/publicButton_up'), self.gui.find('**/publicButton_down'), self.gui.find('**/publicButton_rollover'), self.gui.find('**/publicButton_inactive')), text=TTLocalizer.PartyPlannerPublic, text_pos=(pos[0], pos[2]), text_scale=TTLocalizer.PPpublicButton, command=self.__doTogglePublicPrivate) self.publicButton['state'] = DirectGuiGlobals.DISABLED self.publicButton.bind(DirectGuiGlobals.ENTER, self.__enterPublic) self.publicButton.bind(DirectGuiGlobals.EXIT, self.__exitPublic) pos = self.gui.find('**/step_04_private_locator').getPos() self.privateButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/privateButton_up'), self.gui.find('**/privateButton_down'), self.gui.find('**/privateButton_rollover'), self.gui.find('**/privateButton_inactive')), text=TTLocalizer.PartyPlannerPrivate, text_pos=(pos[0], pos[2]), text_scale=TTLocalizer.PPprivateButton, command=self.__doTogglePublicPrivate) self.privateButton.bind(DirectGuiGlobals.ENTER, self.__enterPrivate) self.privateButton.bind(DirectGuiGlobals.EXIT, self.__exitPrivate) self.checkAllButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/checkAllButton_up'), self.gui.find('**/checkAllButton_down'), self.gui.find('**/checkAllButton_rollover')), command=self.__doCheckAll) self.uncheckAllButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/uncheckAllButton_up'), self.gui.find('**/uncheckAllButton_down'), self.gui.find('**/uncheckAllButton_rollover')), command=self.__doUncheckAll) return page def __doCheckAll(self): for friendBox in self.friendList['items']: friendBox['indicatorValue'] = True def __doUncheckAll(self): for friendBox in self.friendList['items']: friendBox['indicatorValue'] = False def __enterPrivate(self, mouseEvent): self.privateDescriptionLabel.unstash() def __exitPrivate(self, mouseEvent): self.privateDescriptionLabel.stash() def __enterPublic(self, mouseEvent): self.publicDescriptionLabel.unstash() def __exitPublic(self, mouseEvent): self.publicDescriptionLabel.stash() def __doTogglePublicPrivate(self): if self.isPrivate: self.isPrivate = False self.privateButton['state'] = DirectGuiGlobals.NORMAL self.publicButton['state'] = DirectGuiGlobals.DISABLED else: self.isPrivate = True self.privateButton['state'] = DirectGuiGlobals.DISABLED self.publicButton['state'] = DirectGuiGlobals.NORMAL 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 okWithPartyGroundsLayout(self): self.okWithGroundsGui.hide() if self.okWithGroundsGui.doneStatus == 'ok': self.__nextItem() def setNextButtonState(self, enabled): if enabled: self.nextButton['state'] = DirectGuiGlobals.NORMAL self.nextButton.show() else: self.nextButton['state'] = DirectGuiGlobals.DISABLED self.nextButton.hide() def _createInvitationPage(self): self.__handleHolidays() page = DirectFrame(self.frame) page.setName('PartyPlannerInvitationPage') self.invitationTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerConfirmTitle, textMayChange=True, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) self.invitationBackground = DirectFrame(parent=page, relief=None, geom=self.gui.find('**/invitationBackground')) self.inviteVisual = InviteVisual(page) self.selectedInviteThemeLabel = DirectLabel(parent=page, relief=None, pos=self.gui.find('**/step_06_theme_locator').getPos(), text='', text_scale=0.06, textMayChange=True) self.nextThemeButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/topNext_button/nextButton_up'), self.gui.find('**/topNext_button/nextButton_down'), self.gui.find('**/topNext_button/nextButton_rollover')), command=self.__nextTheme) self.prevThemeButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/topPrevious_button/previousButton_up'), self.gui.find('**/topPrevious_button/previousButton_down'), self.gui.find('**/topPrevious_button/previousButton_rollover')), command=self.__prevTheme) pos = self.gui.find('**/step_06_sendInvitation_locator').getPos() self.inviteButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/send_up'), self.gui.find('**/send_down'), self.gui.find('**/send_rollover')), text=TTLocalizer.PartyPlannerInviteButton, textMayChange=True, text_scale=0.05, text_pos=(pos[0], pos[2]), command=self.__handleComplete) return page def __handleHolidays(self): self.inviteThemes = range(len(PartyGlobals.InviteTheme)) if hasattr(base.cr, 'newsManager') and base.cr.newsManager: holidayIds = base.cr.newsManager.getHolidayIdList() if ToontownGlobals.VALENTINES_DAY not in holidayIds: self.inviteThemes.remove(PartyGlobals.InviteTheme.Valentoons) if ToontownGlobals.VICTORY_PARTY_HOLIDAY not in holidayIds: self.inviteThemes.remove(PartyGlobals.InviteTheme.VictoryParty) if ToontownGlobals.WINTER_DECORATIONS not in holidayIds and ToontownGlobals.WACKY_WINTER_DECORATIONS not in holidayIds: self.inviteThemes.remove(PartyGlobals.InviteTheme.Winter) def _createFarewellPage(self): page = DirectFrame(self.frame) page.setName('PartyPlannerFarewellPage') self.confirmTitleLabel = DirectLabel(parent=page, relief=None, text=TTLocalizer.PartyPlannerConfirmationAllOkTitle, textMayChange=True, pos=self.gui.find('**/title_locator').getPos(), scale=self.titleScale) pos = self.gui.find('**/step_07_close_text_locator').getPos() self.closePlannerButton = DirectButton(parent=page, relief=None, geom=(self.gui.find('**/close_up'), self.gui.find('**/close_down'), self.gui.find('**/close_rollover')), text=TTLocalizer.PartyPlannerClosePlanner, text_scale=0.055, text_pos=(pos[0], pos[2]), command=self.__acceptExit) return page def close(self): self.ignore('addPartyResponseReceived') self.ignore(localAvatar.uniqueName('moneyChange')) self.ignore(localAvatar.uniqueName('bankMoneyChange')) self.timeInputHourUpButton.destroy() self.timeInputHourDownButton.destroy() self.timeInputMinuteUpButton.destroy() self.timeInputMinuteDownButton.destroy() self.timeInputAmPmUpButton.destroy() self.timeInputAmPmDownButton.destroy() self.privateButton.destroy() self.publicButton.destroy() self.makePartyNowButton.destroy() self.checkAllButton.destroy() self.uncheckAllButton.destroy() self.elementBuyButton.destroy() self.nextThemeButton.destroy() self.prevThemeButton.destroy() self.inviteButton.destroy() self.closePlannerButton.destroy() self.ignore(self.okWithPartyGroundsLayoutEvent) if hasattr(self, 'okWithGroundsGui'): self.okWithGroundsGui.cleanup() del self.okWithGroundsGui if hasattr(self, 'frame') and not self.frame.isEmpty(): messenger.send(self.doneEvent) self.hide() self.cleanup() self.friendList.removeAndDestroyAllItems() self.friendList.destroy() self.calendarGuiMonth.destroy() self.frame.destroy() self.partyPlannerHead.delete() self.partyPlannerHead.removeNode() self.clearNametag() self.partyEditor.request('Cleanup') self.partyEditor = None self.destroy() del self return def __handleComplete(self): self.inviteButton['state'] = DirectGuiGlobals.DISABLED self.prevButton['state'] = DirectGuiGlobals.DISABLED endTime = self.partyTime + self.partyDuration hostId = base.localAvatar.doId self.partyActivities = self.partyEditor.partyEditorGrid.getActivitiesOnGrid() decorations = self.partyEditor.partyEditorGrid.getDecorationsOnGrid() invitees = self.getInvitees() self.accept('addPartyResponseReceived', self.processAddPartyResponse) base.cr.partyManager.sendAddParty(hostId, self.partyTime.strftime('%Y-%m-%d %H:%M:%S'), endTime.strftime('%Y-%m-%d %H:%M:%S'), self.isPrivate, self.currentInvitationTheme, self.partyActivities, decorations, invitees) def getInvitees(self): invitees = [] for friendBox in self.friendList['items']: if friendBox['indicatorValue']: invitees.append(friendBox.getPythonTag('id')) return invitees def processAddPartyResponse(self, hostId, errorCode): PartyPlanner.notify.debug('processAddPartyResponse : hostId=%d errorCode=%s' % (hostId, PartyGlobals.AddPartyErrorCode.getString(errorCode))) goingBackAllowed = False if errorCode == PartyGlobals.AddPartyErrorCode.AllOk: goingBackAllowed = False self.confirmTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmationAllOkTitle if self.noFriends or len(self.getInvitees()) == 0: confirmRecapText = TTLocalizer.PartyPlannerConfirmationAllOkTextNoFriends else: confirmRecapText = TTLocalizer.PartyPlannerConfirmationAllOkText elif errorCode == PartyGlobals.AddPartyErrorCode.ValidationError: self.confirmTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle confirmRecapText = TTLocalizer.PartyPlannerConfirmationValidationErrorText elif errorCode == PartyGlobals.AddPartyErrorCode.DatabaseError: self.confirmTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle confirmRecapText = TTLocalizer.PartyPlannerConfirmationDatabaseErrorText elif errorCode == PartyGlobals.AddPartyErrorCode.TooManyHostedParties: goingBackAllowed = False self.confirmTitleLabel['text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle confirmRecapText = TTLocalizer.PartyPlannerConfirmationTooManyText self.nametagGroup.setChat(confirmRecapText, CFSpeech) self.request('Farewell', goingBackAllowed) def __acceptExit(self): PartyPlanner.notify.debug('__acceptExit') if hasattr(self, 'frame'): self.hide() messenger.send(self.doneEvent) def __nextItem(self): messenger.send('wakeup') if self.state == 'PartyEditor' and self.okWithGroundsGui.doneStatus != 'ok': self.okWithGroundsGui.show() return if self.state == 'PartyEditor' and self.noFriends: self.request('Date') self.selectedCalendarGuiDay = None self.calendarGuiMonth.clearSelectedDay() return if self.state == 'Guests': self.selectedCalendarGuiDay = None self.calendarGuiMonth.clearSelectedDay() if self.state == 'Time': if self.partyTime < base.cr.toontownTimeManager.getCurServerDateTime(): self.okChooseFutureTimeEvent = 'okChooseFutureTimeEvent' self.acceptOnce(self.okChooseFutureTimeEvent, self.okChooseFutureTime) self.chooseFutureTimeDialog = TTDialog.TTGlobalDialog(dialogName=self.uniqueName('chooseFutureTimeDialog'), doneEvent=self.okChooseFutureTimeEvent, message=TTLocalizer.PartyPlannerChooseFutureTime, style=TTDialog.Acknowledge) self.chooseFutureTimeDialog.show() return self.requestNext() return def okChooseFutureTime(self): if hasattr(self, 'chooseFutureTimeDialog'): self.chooseFutureTimeDialog.cleanup() del self.chooseFutureTimeDialog if hasattr(self, 'okChooseFutureTimeEvent'): self.ignore(self.okChooseFutureTimeEvent) def __prevItem(self): messenger.send('wakeup') if self.state == 'Date' and self.noFriends: self.request('PartyEditor') return if self.state == 'Invitation' and self.selectedCalendarGuiDay is None: self.request('Guests') return self.requestPrev() return def __moneyChange(self, newMoney): if hasattr(self, 'totalMoney'): self.totalMoney = base.localAvatar.getTotalMoney() if hasattr(self, 'beanBank'): self.beanBank['text'] = str(int(self.totalMoney))
class Avatar(ToonTalker.ToonTalker, Actor, AvatarShared): """ Client side implementation of the base Avatar. An Avatar is an animatable character, playable or non-playable, that can be involved in combat. Also has the ability to chat, have a nametag, hitbox, and more. """ RealShadows = ConfigVariableBool('want-real-shadows', False) AvatarMovedEpsilon = 0.05 def __init__(self, mat=0): try: self.Avatar_initialized return except: self.Avatar_initialized = 1 ToonTalker.ToonTalker.__init__(self) #BasePhysicsObject.__init__(self) AvatarShared.__init__(self) Actor.__init__(self, None, None, None, flattenable=0, setFinal=1) # All avatars should be ambient boosted to help them stand out more in BSP levels. self.setAmbientBoost() self.shapeGroup = CIGlobals.WallGroup | CIGlobals.CharacterGroup #self.getGeomNode().showThrough(CIGlobals.ShadowCameraBitmask) self.usedAnims = [] self.moveAnimProperties = {} self.mat = mat self.chat = '' self.nametagNodePath = None self.__nameVisible = 1 self.nametag = NametagGroup() self.nametag.setAvatar(self) font = CIGlobals.getToonFont() self.nametag.setFont(font) self.nametag.setChatFont(font) self.nametag3d = self.attachNewNode('nametag3d') self.nametag3d.setTag('cam', 'nametag') self.setTwoSided(False) self.forwardSpeed = 0.0 self.rotateSpeed = 0.0 self.strafeSpeed = 0.0 self.currentSpeed = 0.0 self.standWalkRunReverse = None self.currentMoveAction = None self.enableBlend() self.showNametagInMargins = True self.avatarType = None self.charName = None self.tag = None self.splashEffect = None self.splashSound = None self.shadow = None self.prevPos = Point3(0) self.wake = None self.lastWakeTime = 0.0 self.thoughtInProg = False self.shadowFloorToggle = False self.avatarFloorToggle = False self.floorTask = taskMgr.add(self.__keepOnFloorTask, "Avatar.keepOnFloor", sort=30) self.ragdoll = None self.ragdollMode = False self.healthLabel = None self.healthLabelTrack = None self.dmgFadeIval = None self.forcedTorsoAnim = None self.lastForcedTorsoAnim = None self.activityTrack = None self.wasDoingActivity = False self.fadeTrack = None self.playedAnims = None self.chatSoundTable = {} return def doScaleUp(self): self.scaleInterval(2.0, (1, 1, 1), (0.01, 0.01, 0.01)).start() def recordUsedAnim(self, animName): if not animName in self.usedAnims: self.usedAnims.append(animName) def clearFadeTrack(self): if self.fadeTrack: self.fadeTrack.finish() self.fadeTrack = None def fadeOut(self, time=1.0): self.clearFadeTrack() self.fadeTrack = Sequence( Func(self.setTransparency, 1), LerpColorScaleInterval(self, time, (1, 1, 1, 0), (1, 1, 1, 1)), Func(self.hide)) self.fadeTrack.start() def fadeIn(self, time=1.0): self.clearFadeTrack() self.fadeTrack = Sequence( Func(self.setTransparency, 1), LerpColorScaleInterval(self, time, (1, 1, 1, 1), (1, 1, 1, 0)), Func(self.setTransparency, 0)) self.fadeTrack.start() def getAttackMgr(self): return base.cr.attackMgr def stopActivity(self): if self.activityTrack: self.activityTrack.finish() self.activityTrack = None self.doingActivity = False def setActivity(self, activity, timestamp): AvatarShared.setActivity(self, activity, timestamp) self.stopActivity() if activity == -1 or activity not in self.activities: return self.doingActivity = True ts = globalClockDelta.localElapsedTime(timestamp) act = self.activities[activity] loop = act.shouldLoop() self.activityTrack = act.doActivity() self.activityTrack.start() #if loop: # self.activityTrack.loop() #else: # self.activityTrack.start() def setForcedTorsoAnim(self, anim): self.forcedTorsoAnim = anim def hasForcedTorsoAnim(self): return self.forcedTorsoAnim is not None def getForcedTorsoAnim(self): return self.forcedTorsoAnim def clearForcedTorsoAnim(self): if not self.forcedTorsoAnim is None: # Let's switch our current torso and head animation to the # animation the legs are running. legs = self.getLowerBodySubpart()[0] legAnimation = self.getCurrentAnim(partName=legs) frame = self.getCurrentFrame(partName=legs, animName=legAnimation) def __anim(partName): self.stop(partName=partName) self.play(animName=legAnimation, partName=partName, fromFrame=frame) parts = self.getUpperBodySubpart() for part in parts: __anim(part) self.forcedTorsoAnim = None def setPlayRate(self, rate, animName, partName=None): if partName or not self.forcedTorsoAnim: Actor.setPlayRate(self, rate, animName, partName) else: parts = self.getLowerBodySubpart() + self.getUpperBodySubpart() for part in parts: Actor.setPlayRate(self, rate, animName, part) def play(self, animName, partName=None, fromFrame=None, toFrame=None): self.recordUsedAnim(animName) lowerHalfNames = self.getLowerBodySubpart() if self.forcedTorsoAnim is None or (not (partName in lowerHalfNames)): Actor.play(self, animName, partName=partName, fromFrame=fromFrame, toFrame=toFrame) else: # The torso and the head must stay in its current animation. # Let's only update the pants and the legs animation. for part in lowerHalfNames: Actor.play(self, animName, partName=part, fromFrame=fromFrame, toFrame=toFrame) def loop(self, animName, restart=1, partName=None, fromFrame=None, toFrame=None): self.recordUsedAnim(animName) lowerHalfNames = self.getLowerBodySubpart() if self.forcedTorsoAnim is None or (not (partName in lowerHalfNames)): return Actor.loop(self, animName, restart=restart, partName=partName, fromFrame=fromFrame, toFrame=toFrame) else: # The torso and the head must stay in its current animation. # Let's only update the pants and the legs animation. for index, part in enumerate(lowerHalfNames): output = Actor.loop(self, animName, restart=restart, partName=part, fromFrame=fromFrame, toFrame=toFrame) def pingpong(self, animName, restart=1, partName=None, fromFrame=None, toFrame=None): self.recordUsedAnim(animName) lowerHalfNames = self.getLowerBodySubpart() if self.forcedTorsoAnim is None or (not (partName in lowerHalfNames)): Actor.pingpong(self, animName, restart=restart, partName=partName, fromFrame=fromFrame, toFrame=toFrame) else: # The torso and the head must stay in its current animation. # Let's only update the pants and the legs animation. for part in lowerHalfNames: Actor.pingpong(self, animName, restart=restart, partName=part, fromFrame=fromFrame, toFrame=toFrame) def getMoveAction(self, forward, rotate, strafe): return 0 def performAnim(self, anim, partName=None, animInfo=None): if not animInfo: self.loop(anim, partName=partName) else: extraArgs = animInfo.get('args', {}) meth = animInfo.get('method', 'loop') if meth == 'loop': self.loop(anim, **extraArgs) elif meth == 'pingpong': self.pingpong(anim, **extraArgs) def resetMoveAnims(self, anim=None, anim2=None): self.resetAnimBlends() if self.forcedTorsoAnim is None: self.disableBlend() self.stop() if anim and anim2: self.enableBlend() self.performAnim(anim, None, self.moveAnimProperties.get(anim, None)) self.performAnim(anim2, None, self.moveAnimProperties.get(anim2, None)) else: parts = self.getLowerBodySubpart() for part in parts: self.disableBlend(partName=part) self.stop(partName=part) if anim and anim2: self.enableBlend(partName=part) self.performAnim(anim, part, self.moveAnimProperties.get(anim, None)) self.performAnim(anim2, part, self.moveAnimProperties.get(anim2, None)) def resetAnimBlends(self): for animName in self.usedAnims: self.setControlEffect(animName, 0.0) self.usedAnims = [] def setSpeed(self, forwardSpeed, rotateSpeed, strafeSpeed=0.0): if self.ragdollMode: return self.forwardSpeed = forwardSpeed self.rotateSpeed = rotateSpeed self.strafeSpeed = strafeSpeed action = None if self.standWalkRunReverse != None and not self.doingActivity: action = self.getMoveAction(forwardSpeed, rotateSpeed, strafeSpeed) anim, anim2, minSpeed, maxSpeed, rate, rate2 = self.standWalkRunReverse[ action] if self.currentMoveAction != action or self.lastForcedTorsoAnim != self.forcedTorsoAnim or self.wasDoingActivity: self.playingAnim = anim self.lastForcedTorsoAnim = self.forcedTorsoAnim self.currentMoveAction = action self.resetMoveAnims(anim, anim2) speed = max( Vec3(forwardSpeed, strafeSpeed, rotateSpeed / 15.0).length(), minSpeed) self.currentSpeed = speed ratio = speed / maxSpeed ratioClamped = CIGlobals.clamp(ratio, 0, 1) self.setControlEffect(anim, 1 - ratioClamped) self.setControlEffect(anim2, ratioClamped) if ratio > 1: self.setPlayRate(rate * ratio, anim) self.setPlayRate(rate2 * ratio, anim2) else: self.setPlayRate(rate, anim) self.setPlayRate(rate2, anim2) self.wasDoingActivity = False elif self.doingActivity and not self.wasDoingActivity: self.wasDoingActivity = True self.resetMoveAnims() return action def getRightHandNode(self): return NodePath("rightHand") def getLeftHandNode(self): return NodePath("leftHand") def getHeadNode(self): return NodePath("head") def handleHitByToon(self, player, gagId, distance): pass def handleHitByEnemy(self, enemy, weaponId, distance): pass def getLowerBodySubpart(self): return ["legs"] def getUpperBodySubpart(self): return ["torso"] def taskName(self, name): return name + "-" + str(id(self)) def uniqueName(self, name): return name + "-" + str(id(self)) def setupHealthLabel(self): self.healthLabel = DirectLabel(text="", text_fg=CIGlobals.PositiveTextColor, scale=0.9, relief=None, text_decal=True, text_font=CIGlobals.getMickeyFont(), text_align=TextNode.ACenter) self.healthLabel.reparentTo(self) self.healthLabel.setBillboardPointEye() self.healthLabel.stash() self.healthLabel.setLightOff(1) self.healthLabel.hide(CIGlobals.ShadowCameraBitmask | CIGlobals.ReflectionCameraBitmask) def showAndMoveHealthLabel(self, zoffset=0.5, stashWaitTime=1.0): self.unstashHpLabel() self.stopMovingHealthLabel() x = self.nametag3d.getX() y = self.nametag3d.getY() z = self.nametag3d.getZ() moveTrack = LerpPosInterval(self.healthLabel, duration=0.5, pos=(x, y, z + zoffset), startPos=(x, y, z - 2), blendType='easeOut') self.healthLabelTrack = Sequence(moveTrack, Wait(stashWaitTime), Func(self.stashHpLabel)) self.healthLabelTrack.start() def stopMovingHealthLabel(self): if self.healthLabelTrack != None: self.healthLabelTrack.pause() self.healthLabelTrack = None def stashHpLabel(self): self.healthLabel.stash() def unstashHpLabel(self): self.healthLabel.unstash() def doDamageFade(self): # Stop the current fade interval if it exists. if self.dmgFadeIval: self.dmgFadeIval.finish() self.dmgFadeIval = None geomNode = self.getGeomNode() # Do a fade effect when we get hit so we are more aware that we were damaged. self.dmgFadeIval = Sequence( Func(geomNode.setTransparency, 1), LerpColorScaleInterval(geomNode, 0.3, (1, 1, 1, 0.5), (1, 1, 1, 1), blendType='easeOut'), LerpColorScaleInterval(geomNode, 0.3, (1, 1, 1, 1), (1, 1, 1, 0.5), blendType='easeIn'), Func(geomNode.setTransparency, 0)) self.dmgFadeIval.start() def announceHealth(self, level, hp, extraId): if not self.healthLabel: return if hp > 0: prefix = "+" else: prefix = "" if extraId != -1: prefix = self.EXTRAS[extraId] + "\n" + prefix if level == 1: self.healthLabel["text_fg"] = CIGlobals.PositiveTextColor self.healthLabel['text'] = prefix + str(hp) else: textFg = CIGlobals.NegativeTextColor if level == 2: textFg = CIGlobals.OrangeTextColor elif level == 3: textFg = CIGlobals.YellowTextColor self.healthLabel["text_fg"] = textFg self.healthLabel['text'] = prefix + str(hp) self.showAndMoveHealthLabel(1.0 if extraId != -1 else 0.5) def doRagdollMode(self, forceX=0, forceY=0, forceZ=0, forcePosX=0, forcePosY=0, forcePosZ=0): if self.ragdollMode: return forceVec = Vec3(forceX, forceY, forceZ) forcePos = Vec3(forcePosX, forcePosY, forcePosZ) self.stop() self.disableRay() self.disableShadowRay() if self.shadow: self.shadow.hide() self.disableBodyCollisions() if self.ragdoll: self.ragdoll.mode = self.ragdoll.RMRagdoll self.ragdoll.setEnabled(True) self.ragdoll.attachActor() self.ragdoll.applyForce(forceVec, forcePos) self.ragdollMode = True def getSplash(self): if not self.splashEffect: self.splashEffect = Splash(render) self.splashSound = base.loadSfxOnNode( "phase_5.5/audio/sfx/AV_jump_in_water.ogg", self.splashEffect) return self.splashEffect def getWake(self): if not self.wake: self.wake = Wake(render, self) return self.wake def splash(self, x, y, z): spl = self.getSplash() spl.setPos(x, y, z) spl.setScale(2) spl.play() self.splashSound.play() def isLocalAvatar(self): if not hasattr(base, 'localAvatar'): return False return self == base.localAvatar def initializeRay(self, *args, **kwargs): pass def enableShadowRay(self): self.shadowFloorToggle = True def disableShadowRay(self): self.shadowFloorToggle = False def enableRay(self): self.avatarFloorToggle = True def disableRay(self): self.avatarFloorToggle = False def updateFloorHeight(self, z): if self.avatarFloorToggle: self.setZ(render, z) if self.shadowFloorToggle and self.shadow: self.shadow.setZ(render, z) def __keepOnFloorTask(self, task): # First, check if we are above a ground. # If so, go onto that. if self.isEmpty(): return task.done # Create water ripples time = globalClock.getFrameTime() delta = time - self.lastWakeTime dt = globalClock.getDt() pos = self.getPos(render) posDelta = (pos - self.prevPos).lengthSquared() moveMag = posDelta / dt if moveMag > 5.0 and delta > 0.1: if hasattr(base, 'waterReflectionMgr'): result = base.waterReflectionMgr.isTouchingAnyWater( pos, pos + (0, 0, self.getHeight())) if result[0]: self.getWake().createRipple(result[1], rate=1, startFrame=4) self.lastWakeTime = time self.prevPos = pos # Position is updated from server, don't need to move avatar on client return task.cont if (not self.avatarFloorToggle and not self.shadowFloorToggle or moveMag < self.AvatarMovedEpsilon): # Avoid unnecessary ray casting. return task.cont pFrom = self.getPos(render) + (0, 0, 0.1) z = None pTo = pFrom - (0, 0, 2000) aboveResult = base.physicsWorld.rayTestAll( pFrom, pTo, CIGlobals.WallGroup | CIGlobals.FloorGroup | CIGlobals.StreetVisGroup) aboveGround = False if aboveResult.hasHits(): sortedHits = sorted(aboveResult.getHits(), key=lambda hit: (pFrom - hit.getHitPos()).lengthSquared()) for i in range(len(sortedHits)): hit = sortedHits[i] node = hit.getNode() np = NodePath(node) if self.isAncestorOf(np): continue z = hit.getHitPos().getZ() break if z is not None: self.updateFloorHeight(z) return task.cont # We're not above a ground, check above? pTo = pFrom + (0, 0, 2000) belowResult = base.physicsWorld.rayTestAll( pFrom, pTo, CIGlobals.WallGroup | CIGlobals.FloorGroup | CIGlobals.StreetVisGroup) if belowResult.hasHits(): sortedHits = sorted(belowResult.getHits(), key=lambda hit: (pFrom - hit.getHitPos()).lengthSquared()) for i in range(len(sortedHits)): hit = sortedHits[i] node = hit.getNode() np = NodePath(node) if self.isAncestorOf(np): continue z = hit.getHitPos().getZ() break if z is not None: self.updateFloorHeight(z) return task.cont def setupPhysics(self, radius=None, height=None): if not radius: radius = self.getWidth() if not height: height = self.getHeight() self.notify.debug("setupPhysics(r{0}, h{1}) hitboxData: {2}".format( radius, height, self.hitboxData)) # When the height is passed into BulletCapsuleShape, it's # talking about the height only of the cylinder part. # But what we want is the height of the entire capsule. #height -= (radius * 2) # The middle of the capsule is the origin by default. Push the capsule shape up # so the very bottom of the capsule is the origin. zOfs = (height / 2.0) + radius capsule = BulletCapsuleShape(radius, height) bodyNode = BulletRigidBodyNode('avatarBodyNode') bodyNode.addShape(capsule, TransformState.makePos(Point3(0, 0, zOfs))) bodyNode.setKinematic(True) bodyNode.setPythonTag("avatar", self) BasePhysicsObject.setupPhysics(self, bodyNode, True) self.stopWaterCheck() def isDistributed(self): return hasattr(self, 'doId') def chatStompComplete(self, text): chatType = CHAT_LONG if "ooo" in text.lower(): chatType = CHAT_HOWL elif "!" in text.lower(): chatType = CHAT_EXCLAIM elif "?" in text.lower(): chatType = CHAT_QUESTION elif len(text) <= 9: chatType = CHAT_SHORT elif 10 <= len(text) <= 19: chatType = CHAT_MEDIUM elif len(text) >= 20: chatType = CHAT_LONG snd = self.chatSoundTable.get(chatType, None) if isinstance(snd, list): snd = random.choice(snd) if snd: self.playSound(snd) def deleteNameTag(self): self.deleteNametag3d() def disableBodyCollisions(self): self.cleanupPhysics() def loadAvatar(self): self.setupHealthLabel() self.setBlend( frameBlend=base.config.GetBool("interpolate-frames", False)) base.avatars.append(self) def disable(self): try: self.Avatar_disabled except: self.Avatar_disabled = 1 if self.ragdoll: self.ragdoll.cleanup() self.ragdoll = None self.clearFadeTrack() if self in base.avatars: base.avatars.remove(self) if self.dmgFadeIval: self.dmgFadeIval.finish() self.stopActivity() self.dmgFadeIval = None self.stopMovingHealthLabel() if self.healthLabel: self.healthLabel.removeNode() self.healthLabel = None self.healthLabelTrack = None if self.floorTask: self.floorTask.remove() self.floorTask = None self.disableRay() self.deleteNametag3d() self.nametag.destroy() del self.nametag self.nametag3d.removeNode() self.nametag3d = None self.deleteShadow() self.removeLoopTask() self.mat = None self.tag = None self.chat = None self.avatarType = None self.charName = None self.nameTag = None self.cleanupPhysics() self.moveAnimProperties = None self.chatSoundTable = None self.lastWakeTime = None self.prevPos = None if self.wake: self.wake.destroy() self.wake = None if self.splashEffect: self.splashEffect.destroy() self.splashEffect = None self.splashSound = None self.avatarFloorToggle = None self.shadowFloorToggle = None Actor.cleanup(self) def delete(self): try: self.Avatar_deleted except: self.Avatar_deleted = 1 self.removeLoopTask() AvatarShared.delete(self) Actor.delete(self) def getNameTag(self): return self.nametag3d def getNametagJoints(self): return [] def setChat(self, chatString=None): print("setChat on", self.__class__.__name__) self.nametag.setChatType(NametagGlobals.CHAT) shouldClear = self.autoClearChat if self.isThought(chatString): self.thoughtInProg = True chatString = self.removeThoughtPrefix(chatString) self.nametag.setChatBalloonType(NametagGlobals.THOUGHT_BALLOON) shouldClear = False else: self.thoughtInProg = False self.nametag.setChatBalloonType(NametagGlobals.CHAT_BALLOON) self.nametag.setChatText(chatString, timeout=shouldClear) def setName(self, nameString=None, charName=None, createNow=0): if not nameString: return AvatarShared.setName(self, nameString) if charName: self.charName = charName if createNow: self.setupNameTag() def getName(self): return AvatarShared.getName(self) def setupNameTag(self, tempName=None): if not self._name and not tempName: return if tempName: name = tempName else: name = self._name offset = 0.0 z = 0.0 if self.avatarType: if self.avatarType in [CIGlobals.Suit]: offset = 1.0 z = self.getHeight() elif self.avatarType == CIGlobals.Toon: offset = 0.5 self.deleteNametag3d() self.initializeNametag3d() if self.avatarType == CIGlobals.Toon: self.nametag3d.setZ(self.getHeight() + offset) elif self.avatarType == CIGlobals.Suit or self.avatarType == CIGlobals.CChar: self.nametag3d.setZ(z + offset) if self.avatarType == CIGlobals.Suit: self.nametag.setFont(CIGlobals.getSuitFont()) self.nametag.setChatFont(CIGlobals.getSuitFont()) self.nametag.setNametagColor( NametagGlobals.NametagColors[NametagGlobals.CCSuit]) self.nametag.setActive(0) else: self.nametag.setFont(CIGlobals.getToonFont()) self.nametag.setChatFont(CIGlobals.getToonFont()) self.nametag.setNametagColor( NametagGlobals.NametagColors[NametagGlobals.CCOtherPlayer]) self.nametag.setText(name) if self.showNametagInMargins: self.nametag.manage(base.marginManager) self.nametag.updateAll() def setAvatarScale(self, scale): self.getGeomNode().setScale(scale) def getShadow(self): if hasattr(self, 'shadow'): if self.shadow: return self.shadow return None def initShadow(self): if metadata.USE_REAL_SHADOWS: self.shadow = None else: self.shadow = loader.loadModel( "phase_3/models/props/drop_shadow.bam") self.shadow.setScale(CIGlobals.ShadowScales[self.avatarType]) self.shadow.flattenMedium() self.shadow.setBillboardAxis(4) self.shadow.setColor(0, 0, 0, 0.5, 1) if self.avatarType == CIGlobals.Toon: self.shadow.reparentTo( self.getPart('legs').find('**/joint_shadow')) elif self.avatarType == CIGlobals.Suit: self.shadow.reparentTo(self) else: self.shadow.reparentTo(self) self.enableShadowRay() def deleteShadow(self): if hasattr(self, 'shadow'): if self.shadow: self.shadow.removeNode() self.shadow = None def loopFromFrameToZero(self, animName, restart=1, partName=None, fromFrame=None): # Loop an animation from a frame, restarting at 0. # This is only used in Make A Toon, but could be used in other things, # that are not distributed. dur = self.getDuration(animName, fromFrame=fromFrame) self.play(animName, partName=partName, fromFrame=fromFrame) taskName = self.uniqueName('loopTask') taskMgr.doMethodLater(dur, self.loopTask, taskName, extraArgs=[animName, restart, partName], appendTask=True) def removeLoopTask(self): taskMgr.remove(self.uniqueName('loopTask')) def removePart(self, partName, lodName="lodRoot"): self.removeLoopTask() part = Actor.getPart(self, partName, lodName) if part: Actor.removePart(self, partName, lodName=lodName) def loopTask(self, animName, restart, partName, task): self.loop(animName, restart, partName) return task.done def getGhost(self): return 0 def hideName(self): nametag3d = self.nametag.getNametag3d() nametag3d.hideNametag() nametag3d.showChat() nametag3d.showThought() nametag3d.update() def showName(self): if self.__nameVisible and not self.getGhost(): nametag3d = self.nametag.getNametag3d() nametag3d.showNametag() nametag3d.showChat() nametag3d.showThought() nametag3d.update() def hideNametag2d(self): nametag2d = self.nametag.getNametag2d() nametag2d.hideNametag() nametag2d.hideChat() nametag2d.update() def showNametag2d(self): nametag2d = self.nametag.getNametag2d() if not self.getGhost(): nametag2d.showNametag() nametag2d.showChat() else: nametag2d.hideNametag() nametag2d.hideChat() nametag2d.update() def hideNametag3d(self): nametag3d = self.nametag.getNametag3d() nametag3d.hideNametag() nametag3d.hideChat() nametag3d.hideThought() nametag3d.update() def showNametag3d(self): nametag3d = self.nametag.getNametag3d() if self.__nameVisible and (not self.getGhost()): nametag3d.showNametag() nametag3d.showChat() nametag3d.showThought() else: nametag3d.hideNametag() nametag3d.hideChat() nametag3d.hideThought() nametag3d.update() def setPickable(self, flag): self.nametag.setActive(flag) def clickedNametag(self): if self.nametag.getActive(): messenger.send('clickedNametag', [self]) def initializeNametag3d(self): self.deleteNametag3d() nametagNode = self.nametag.getNametag3d() self.nametagNodePath = self.nametag3d.attachNewNode(nametagNode) for cJoint in self.getNametagJoints(): cJoint.clearNetTransforms() cJoint.addNetTransform(nametagNode) def deleteNametag3d(self): if self.nametagNodePath: self.nametagNodePath.removeNode() self.nametagNodePath = None def getNameVisible(self): return self.__nameVisible def setNameVisible(self, visible): self.__nameVisible = visible if visible: self.showName() else: self.hideName()
class RepairSawingGame(RepairMincroGame): sawSounds = None boardComplet = None boardDestroyed = None def __init__(self, repairGame): self.config = RepairGlobals.Sawing notify = DirectNotifyGlobal.directNotify.newCategory( 'RepairSawingGame') RepairMincroGame.__init__(self, repairGame, 'sawing', PLocalizer.Minigame_Repair_Sawing_Start) def _initVars(self): RepairMincroGame._initVars(self) self.boardsPool = {} self.currentBoard = None self.currentBoardIndex = 0 self.onDeckBoard = None self.onDeckBoardIndex = 0 self.totalScore = 0.0 self.hitZone1Penalty = False self.hitZone2Penalty = False self.hitBoardPenalty = False self.moveDiffForSound = 0.0 self.startPositions = (Point3(0.0, 0.0, 0.0), ) self.currentStartIndex = 0 self.lastMousePos = None self.board_left = None self.board_right = None self.cut = None self.zone1_right = None self.zone1_left = None self.zone2_right = None self.zone2_left = None self.piece1 = None self.piece2 = None self.lastHitIndex = -1 self.sawWaypoints = [] def _initAudio(self): RepairMincroGame._initAudio(self) if not self.sawSounds: RepairSawingGame.sawSounds = ( loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_INOUT01), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_INOUT02), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_INOUT03), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_INOUT04)) RepairSawingGame.boardComplete = loadSfx( SoundGlobals.SFX_MINIGAME_REPAIR_SAW_COMPLETE) RepairSawingGame.boardDestroyed = loadSfx( SoundGlobals.SFX_MINIGAME_REPAIR_SAW_FAIL) def _initVisuals(self): RepairMincroGame._initVisuals(self) self.setBin('fixed', 36) self.model = loader.loadModel('models/gui/pir_m_gui_srp_sawing_main') sawModel = self.model.find('**/saw') sawModel.setR(193) sawModel.setPos(0.90000000000000002, 0.0, -0.16500000000000001) sawModel.setBin('gui-popup', 0) self.sawButton = RepairSaw( parent=self, clickDownCommand=self.sawAttachedToMouse, clickUpCommand=self.sawRemovedFromMouse, geom=sawModel, text_pos=(0.20000000000000001, -0.29999999999999999), text_fg=(1, 0, 0, 1), scale=(0.29999999999999999, 0.29999999999999999, 0.29999999999999999), relief=None, pressEffect=0, frameSize=(-0.050000000000000003, 1.05, -0.29999999999999999, 0.050000000000000003), rolloverSound=None, clickSound=None) self.sawingLine = RepairSawingLine(self, self.config.sawlineLineThickness, self.config.sawlineColor, self.config.sawlineLinespawnDist) self.progressDescriptionLabel = DirectLabel( text=PLocalizer.Minigame_Repair_Sawing_Description, text_fg=(1.0, 1.0, 1.0, 1.0), text_pos=(0.0, 0.0), text_shadow=(0.0, 0.0, 0.0, 1.0), text_font=PiratesGlobals.getPirateFont(), text_align=TextNode.ARight, relief=None, scale=(0.080000000000000002, 0.080000000000000002, 0.080000000000000002), pos=(-0.20000000000000001, 0.0, 0.5), parent=self) self.progressLabel = DirectLabel( text=PLocalizer.Minigame_Repair_Sawing_Thresholds[3], text_fg=(1.0, 1.0, 1.0, 1.0), text_pos=(0.0, 0.0), text_shadow=(0.0, 0.0, 0.0, 1.0), text_font=PiratesGlobals.getPirateFont(), text_align=TextNode.ALeft, relief=None, scale=(0.080000000000000002, 0.080000000000000002, 0.080000000000000002), pos=(-0.17999999999999999, 0.0, 0.5), parent=self) self.boardDestroyedLabel = DirectLabel( text=PLocalizer.Minigame_Repair_Sawing_Board_Destroyed, text_fg=(1.0, 0.0, 0.0, 1.0), text_pos=(0.0, 0.0), text_font=PiratesGlobals.getPirateFont(), text_shadow=(0.0, 0.0, 0.0, 1.0), relief=None, scale=(0.10000000000000001, 0.10000000000000001, 0.10000000000000001), pos=(0.0, 0.0, 0.10000000000000001), parent=self) self.boardDestroyedLabel.setBin('fixed', 38) self.boardDestroyedLabel.stash() def _initIntervals(self): RepairMincroGame._initIntervals(self) self.newBoardSequence = Sequence( name='RepairSawingGame.newBoardSequence') self.splitBoardSequence = Sequence( name='RepairSawGame.splitBoardSequence') self.dropBoardSequence = Sequence( name='RepairSawGame.dropBoardSequence') def getNewBoard(self, boardIndex): board = self.model.find('**/wood%i' % boardIndex).copyTo( NodePath('board%i' % len(self.boardsPool))) board.reparentTo(self) piece1 = board.find('**/piece_1') piece1.setPythonTag('piece_1', self.piece1) piece1.setY(self.config.boardYDist) piece2 = board.find('**/piece_2') piece2.setPythonTag('piece_2', self.piece2) piece2.setY(self.config.boardYDist) pieceCut = board.find('**/piece_cut') pieceCut.setPythonTag('cut', self.cut) pieceCut.setColor(self.config.cutColor) pieceCut.setY(self.config.boardYDist) board_left = piece1.find('**/board') board_left.setPythonTag('left', self.board_left) board_right = piece2.find('**/board') board_right.setPythonTag('right', self.board_right) zone1_right = piece2.find('**/zone_1') zone1_right.setPythonTag('zone1_right', self.zone1_right) zone1_right.setColor(self.config.zone1Color) zone1_left = piece1.find('**/zone_1') zone1_left.setPythonTag('zone1_left', self.zone1_left) zone1_left.setColor(self.config.zone1Color) zone2_right = piece2.find('**/zone_2') zone2_right.setPythonTag('zone2_right', self.zone2_right) zone2_right.setColor(self.config.zone2Color) zone2_left = piece1.find('**/zone_2') zone2_left.setPythonTag('zone2_left', self.zone2_left) zone2_left.setColor(self.config.zone2Color) board.stash() return board def reset(self): for key in self.boardsPool.keys(): board = self.boardsPool[key] board.removeNode() self.boardsPool.clear() if self.currentBoard: self.currentBoard.removeNode() self.currentBoard = None if self.onDeckBoard: self.onDeckBoard.removeNode() self.onDeckBoard = None for boardIndex in self.currentDifficultySet: boardIndex -= 1 if 'copy1_%s' % boardIndex not in self.boardsPool: board = self.getNewBoard(boardIndex) self.boardsPool['copy1_%s' % boardIndex] = board if 'copy2_%s' % boardIndex not in self.boardsPool: board = self.getNewBoard(boardIndex) self.boardsPool['copy2_%s' % boardIndex] = board continue self.currentBoardIndex = 0 self.currentBoard = None self.moveNewBoardOnDeck() self.onDeckBoard.unstash() self.totalScore = 0 self.startPositions = (Point3(0.0, 0.0, 0.0), ) self.sawButton.stash() self.sawButton.reparentTo(self) self.lastHitIndex = -1 self.moveDiffForSound = 0.0 RepairMincroGame.reset(self) self.repairGame.gui.setTutorial(self.name) self.repairGame.gui.setTitle(self.name) def destroy(self): RepairMincroGame.destroy(self) taskMgr.remove('SawingGame.updateSawTask') self.sawButton.destroy() self.sawButton.removeNode() del self.sawButton if self.currentBoard: self.currentBoard.removeNode() self.currentBoard = None if self.onDeckBoard: self.onDeckBoard.removeNode() self.onDeckBoard = None self.sawingLine = None self.progressDescriptionLabel.destroy() self.progressDescriptionLabel = None self.progressLabel.destroy() self.progressLabel = None self.boardDestroyedLabel.destroy() self.boardDestroyedLabel = None for key in self.boardsPool.keys(): board = self.boardsPool[key] if not board.isEmpty(): board.removeNode() continue self.boardsPool.clear() self.newBoardSequence.clearToInitial() del self.newBoardSequence self.splitBoardSequence.clearToInitial() del self.splitBoardSequence self.dropBoardSequence.clearToInitial() del self.dropBoardSequence def setDifficulty(self, difficulty): RepairMincroGame.setDifficulty(self, difficulty) percent = difficulty / self.repairGame.difficultyMax difIndex = int( math.floor(percent * (len(self.config.difficultySets) - 1))) self.currentDifficultySet = self.config.difficultySets[difIndex] def splitBoard(self): self.sawingLine.reset() board = self.currentBoard boardIndex = self.currentBoardIndex if self.hitZone2Penalty: boardSplitAnim = Parallel( LerpPosInterval(self.board_left, duration=self.config.splitBoardAnimTime, pos=Point3(-2.0, 0.0, 0.0)), LerpPosInterval(self.board_right, duration=self.config.splitBoardAnimTime, pos=Point3(2.0, 0.0, 0.0)), LerpFunc(self.zone2_left.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0), LerpFunc(self.zone2_right.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0), LerpFunc(self.zone1_left.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0), LerpFunc(self.zone1_right.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0), LerpFunc(self.cut.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0)) elif self.hitZone1Penalty: boardSplitAnim = Parallel( LerpPosInterval(self.board_left, duration=self.config.splitBoardAnimTime, pos=Point3(-2.0, 0.0, 0.0)), LerpPosInterval(self.board_right, duration=self.config.splitBoardAnimTime, pos=Point3(2.0, 0.0, 0.0)), LerpPosInterval(self.zone2_left, duration=self.config.splitBoardAnimTime, pos=Point3(-2.0, 0.0, 0.0)), LerpPosInterval(self.zone2_right, duration=self.config.splitBoardAnimTime, pos=Point3(2.0, 0.0, 0.0)), LerpFunc(self.zone1_left.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0), LerpFunc(self.zone1_right.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0), LerpFunc(self.cut.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0)) else: boardSplitAnim = Parallel( LerpPosInterval(self.piece1, duration=self.config.splitBoardAnimTime, pos=Point3(-2.0, self.config.boardYDist, 0.0)), LerpPosInterval(self.piece2, duration=self.config.splitBoardAnimTime, pos=Point3(2.0, self.config.boardYDist, 0.0)), LerpFunc(self.cut.setSa, duration=self.config.splitBoardAnimTime / 2.0, fromData=1.0, toData=0.0)) self.splitBoardSequence = Sequence( Func(self.updateScore), Func(self.boardComplete.play), boardSplitAnim, Func(board.stash), Func(self.piece1.setPos, self.piece1.getPos()), Func(self.piece2.setPos, self.piece2.getPos()), Func(self.board_right.setPos, self.board_right.getPos()), Func(self.board_left.setPos, self.board_left.getPos()), Func(self.zone2_right.setPos, self.zone2_right.getPos()), Func(self.zone2_left.setPos, self.zone2_left.getPos()), Func(self.zone1_right.setPos, self.zone1_right.getPos()), Func(self.zone1_left.setPos, self.zone1_left.getPos()), Func(self.cut.setSa, 1.0), Func(self.zone1_right.setSa, 1.0), Func(self.zone1_left.setSa, 1.0), Func(self.zone2_right.setSa, 1.0), Func(self.zone2_left.setSa, 1.0), Func(self.board_right.setSa, 1.0), Func(self.board_left.setSa, 1.0), Func(self.loadNewBoard), Func(self.addBoardBackToPool, board, boardIndex), name='RepairSawGame.splitBoardSequence') self.splitBoardSequence.start() def dropBoard(self): board = self.currentBoard boardIndex = self.currentBoardIndex self.dropBoardSequence = Sequence( Parallel( Sequence(Func(self.boardDestroyedLabel.unstash), Wait(1.5), Func(self.boardDestroyedLabel.stash)), Sequence( Wait(0.5), Func(self.boardDestroyed.play), Func(self.sawingLine.reset), LerpPosInterval(board, duration=self.config.splitBoardAnimTime, pos=Point3(0.0, 0.0, -2.0)), Func(board.stash), Wait(0.5), Func(self.loadNewBoard), Func(self.addBoardBackToPool, board, boardIndex))), name='RepairSawGame.dropBoardSequence') self.dropBoardSequence.start() def addBoardBackToPool(self, board, boardIndex): if 'copy1_%s' % boardIndex not in self.boardsPool: self.boardsPool['copy1_%s' % boardIndex] = board elif 'copy2_%s' % boardIndex not in self.boardsPool: self.boardsPool['copy2_%s' % boardIndex] = board else: self.notify.error( 'Two copies of board type %i already in the boardsPool!' % boardIndex) def updateScoreText(self): self.progressLabel.unstash() self.progressDescriptionLabel.unstash() if self.hitBoardPenalty: self.progressLabel[ 'text'] = PLocalizer.Minigame_Repair_Sawing_Thresholds[0] self.progressLabel['text_fg'] = Vec4(1.0, 0.0, 0.0, 1.0) self.progressLabel.setText() elif self.hitZone2Penalty: self.progressLabel[ 'text'] = PLocalizer.Minigame_Repair_Sawing_Thresholds[1] self.progressLabel['text_fg'] = Vec4(1.0, 0.5, 0.0, 1.0) self.progressLabel.setText() elif self.hitZone1Penalty: self.progressLabel[ 'text'] = PLocalizer.Minigame_Repair_Sawing_Thresholds[2] self.progressLabel['text_fg'] = Vec4(1.0, 1.0, 0.0, 1.0) self.progressLabel.setText() else: self.progressLabel[ 'text'] = PLocalizer.Minigame_Repair_Sawing_Thresholds[3] self.progressLabel['text_fg'] = Vec4(0.0, 1.0, 0.0, 1.0) self.progressLabel.setText() def moveNewBoardOnDeck(self): boardIndex = random.randint(0, len(self.currentDifficultySet) - 1) boardType = self.currentDifficultySet[boardIndex] boardType -= 1 if 'copy1_%s' % boardType in self.boardsPool: self.onDeckBoard = self.boardsPool['copy1_%s' % boardType] del self.boardsPool['copy1_%s' % boardType] elif 'copy2_%s' % boardType in self.boardsPool: self.onDeckBoard = self.boardsPool['copy2_%s' % boardType] del self.boardsPool['copy2_%s' % boardType] else: self.notify.error('No copies of board type %i in the boardsPool!' % boardType) self.onDeckBoardIndex = boardType self.onDeckBoard.setScale(0.25) self.onDeckBoard.setPos(0.5, -2.0, 0.56000000000000005) self.onDeckBoard.unstash() def loadNewBoard(self): self.progressLabel.stash() self.progressDescriptionLabel.stash() if self.totalScore >= self.config.totalPoints: if self.onDeckBoard: self.onDeckBoard.stash() self.progressDescriptionLabel.stash() taskMgr.remove('SawingGame.updateSawTask') self.request('Outro') return None self.currentBoard = self.onDeckBoard self.currentBoardIndex = self.onDeckBoardIndex self.piece1 = self.currentBoard.find('**/piece_1') self.piece1.setTransparency(1) self.piece2 = self.currentBoard.find('**/piece_2') self.piece2.setTransparency(1) self.cut = self.currentBoard.find('**/piece_cut') self.cut.setColor(self.config.cutColor) self.cut.setTransparency(1) self.board_left = self.piece1.find('**/board') self.board_left.setTransparency(1) self.zone1_left = self.piece1.find('**/zone_1') self.zone1_left.setTransparency(1) self.zone2_left = self.piece1.find('**/zone_2') self.zone2_left.setTransparency(1) self.board_right = self.piece2.find('**/board') self.board_right.setTransparency(1) self.zone1_right = self.piece2.find('**/zone_1') self.zone1_right.setTransparency(1) self.zone2_right = self.piece2.find('**/zone_2') self.zone2_right.setTransparency(1) self.board_left.setCollideMask(SAW_COLLIDE_MASK) self.board_right.setCollideMask(SAW_COLLIDE_MASK) self.cut.setCollideMask(SAW_COLLIDE_MASK) self.zone1_right.setCollideMask(SAW_COLLIDE_MASK) self.zone1_left.setCollideMask(SAW_COLLIDE_MASK) self.zone2_right.setCollideMask(SAW_COLLIDE_MASK) self.zone2_left.setCollideMask(SAW_COLLIDE_MASK) self.startPositions = ( self.currentBoard.find('**/locator_start_0').getPos() + Point3(*self.config.activeBoardPosition), self.currentBoard.find('**/locator_start_1').getPos() + Point3(*self.config.activeBoardPosition)) self.currentStartIndex = 0 for waypoint in self.sawWaypoints: waypoint.removeNode() self.sawWaypoints = [] locator = self.currentBoard.find('**/locator_0') index = 0 while not locator.isEmpty(): self.sawWaypoints.append( SawWaypoint(index, self.currentBoard, locator.getPos())) locator = self.currentBoard.find('**/locator_%i' % (index + 1)) index += 1 self.sawButton.deactivate() self.sawButton.setPos(self.startPositions[self.currentStartIndex]) self.hitBoardPenalty = False self.hitZone1Penalty = False self.hitZone2Penalty = False self.lastMousePos = None self.moveDiffForSound = self.config.playSawingSoundDelta + 0.10000000000000001 self.newBoardSequence = Sequence( Parallel( self.currentBoard.posInterval( self.config.newBoardAnimTime, Point3(*self.config.activeBoardPosition)), self.currentBoard.scaleInterval(self.config.newBoardAnimTime, 1.0)), name='RepairSawingGame.newBoardSequence') if self.state in ['Game']: self.newBoardSequence.append(Func(self.sawButton.activate)) self.newBoardSequence.append(Wait(0.5)) self.newBoardSequence.append(Func(self.moveNewBoardOnDeck)) self.newBoardSequence.start() def updateSawTask(self, task): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() relative = Point3(mpos.getX(), 0.0, mpos.getY()) relative = self.getRelativePoint(render2d, relative) moveDiff = 0.0 if self.lastMousePos != None: moveDiff = (relative - self.lastMousePos).length() pickedObjects = self.repairGame.mousePicker.getCollisions( self.currentBoard, useIntoNodePaths=True) self.updateWaypoints() if len(pickedObjects) > 0: self.moveDiffForSound += moveDiff if self.moveDiffForSound > self.config.playSawingSoundDelta: sawSoundPlaying = False for sound in self.sawSounds: if sound.status() == 2: sawSoundPlaying = True break continue if sawSoundPlaying == False: sound = random.choice(self.sawSounds) sound.play() self.moveDiffForSound = 0.0 if self.board_right in pickedObjects or self.board_left in pickedObjects: for waypoint in self.sawWaypoints: waypoint.hit = False self.hitBoardPenalty = True self.dropBoard() self.sawButton.deactivate() elif self.cut in pickedObjects: self.updateWaypoints() elif self.zone1_right in pickedObjects or self.zone1_left in pickedObjects: self.updateWaypoints() if self.hitZone1Penalty == False: self.hitZone1Penalty = True elif self.zone2_right in pickedObjects or self.zone2_left in pickedObjects: self.updateWaypoints() if self.hitZone2Penalty == False: self.hitZone2Penalty = True self.updateScoreText() else: boardComplete = True for waypoint in self.sawWaypoints: if not waypoint.hit: boardComplete = False break continue if boardComplete: self.splitBoard() self.sawButton.deactivate() self.lastMousePos = self.sawButton.getPos() return Task.cont def updateScore(self): if not self.hitBoardPenalty: currBoardScore = self.config.pointsPerBoard if not self.hitZone1Penalty: pass currBoardScore -= self.config.pointsLostForZone1 * self.hitZone2Penalty currBoardScore -= self.config.pointsLostForZone2 * self.hitZone2Penalty rating = 4 - 1 * self.hitZone2Penalty - 3 * self.hitZone1Penalty self.totalScore += currBoardScore self.totalScore = min(self.totalScore, self.config.totalPoints) percent = int((self.totalScore / self.config.totalPoints) * 100.0) self.repairGame.d_reportMincroGameProgress(percent, rating) def resetWaypoints(self): for waypoint in self.sawWaypoints: waypoint.hit = False def updateWaypoints(self): waypointList = self.getHitWaypoints() for waypointIndex in waypointList: self.lastHitIndex = waypointIndex self.sawWaypoints[waypointIndex].hit = True if waypointIndex == 0 and not (self.sawWaypoints[-1].hit): self.currentStartIndex = 0 continue if waypointIndex == len( self.sawWaypoints) - 1 and not (self.sawWaypoints[0].hit): self.currentStartIndex = 1 continue def getHitWaypoints(self): waypointsHit = [] testDelta = self.config.testWaypointDelta for i in range(len(self.sawWaypoints)): waypointPos = self.sawWaypoints[i].getPos(self) closestDistance = 9999 if self.lastMousePos != None: currMousePos = self.sawButton.getPos() lastMousePos = self.lastMousePos totalLength = (currMousePos - lastMousePos).length() testLength = testDelta while testLength < totalLength: testPos = (currMousePos - lastMousePos) * ( testLength / totalLength) + lastMousePos self.updateSawLine(testPos) testDistance = (testPos - waypointPos).length() closestDistance = min(testDistance, closestDistance) testLength += testDelta self.updateSawLine(self.sawButton.getPos()) testDistance = (self.sawButton.getPos() - waypointPos).length() closestDistance = min(testDistance, closestDistance) if closestDistance < self.config.waypointRange[ self.currentBoardIndex]: waypointsHit.append(i) continue return waypointsHit def updateSawLine(self, pos): if pos.getX() < -0.63300000000000001 or pos.getX( ) > 0.63300000000000001: self.sawingLine.reset() return None if pos.getZ() < -0.183 or pos.getZ() > 0.375: self.sawingLine.reset() return None self.sawingLine.update(pos) def getClosestPosition(self, positions): closestIndex = -1 if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() relative = Point3(mpos.getX(), 0.0, mpos.getY()) relative = self.getRelativePoint(base.a2dBackground, relative) bestDistance = 99999.0 for i in range(len(positions)): dX = relative.getX() - positions[i].getX() dZ = relative.getZ() - positions[i].getZ() newDistance = dX * dX + dZ * dZ if newDistance < bestDistance: bestDistance = newDistance closestIndex = i continue return closestIndex def sawAttachedToMouse(self): self.lastHitIndex = -1 if not taskMgr.hasTaskNamed('SawingGame.updateSawTask'): taskMgr.add(self.updateSawTask, 'SawingGame.updateSawTask', priority=2) def sawRemovedFromMouse(self): if not self.sawButton.isStashed(): self.sawButton.setPos(self.startPositions[self.currentStartIndex]) self.lastHitIndex = -1 self.resetWaypoints() self.lastMousePos = None self.progressLabel.stash() self.progressDescriptionLabel.stash() self.sawingLine.reset() self.hitBoardPenalty = False self.hitZone1Penalty = False self.hitZone2Penalty = False taskMgr.remove('SawingGame.updateSawTask') def enterIntro(self): RepairMincroGame.enterIntro(self) self.loadNewBoard() def enterGame(self): RepairMincroGame.enterGame(self) self.repairGame.mousePicker.setCollisionMask(SAW_COLLIDE_MASK) self.sawButton.activate() def exitGame(self): RepairMincroGame.exitGame(self) self.sawButton.deactivate() self.repairGame.mousePicker.clearCollisionMask() taskMgr.remove('SawingGame.updateSawTask') self.splitBoardSequence.clearToInitial() self.dropBoardSequence.clearToInitial() localAvatar.guiMgr._showCursor() def enterOutro(self): RepairMincroGame.enterOutro(self) self.repairGame.d_reportMincroGameScore(150)
class PartyEditorGridElement(DirectButton): notify = directNotify.newCategory('PartyEditorGridElement') def __init__(self, partyEditor, id, isDecoration, checkSoldOutAndPaidStatusAndAffordability, **kw): self.partyEditor = partyEditor self.id = id self.isDecoration = isDecoration self.checkSoldOutAndPaidStatusAndAffordability = checkSoldOutAndPaidStatusAndAffordability if self.isDecoration: self.name = TTLocalizer.PartyDecorationNameDict[self.id]['editor'] colorList = ((1.0, 1.0, 1.0, 1.0), (0.0, 0.0, 1.0, 1.0), (0.0, 1.0, 1.0, 1.0), (0.5, 0.5, 0.5, 1.0)) self.geom = self.partyEditor.partyPlanner.gui.find('**/%s' % PartyGlobals.DecorationInformationDict[self.id]['gridAsset']) else: self.name = TTLocalizer.PartyActivityNameDict[self.id]['editor'] colorList = ((1.0, 1.0, 1.0, 1.0), (0.0, 1.0, 0.0, 1.0), (1.0, 1.0, 0.0, 1.0), (0.5, 0.5, 0.5, 1.0)) self.geom = self.partyEditor.partyPlanner.gui.find('**/%s' % PartyGlobals.ActivityInformationDict[self.id]['gridAsset']) optiondefs = (('geom', self.geom, None), ('geom_scale', 1.0, None), ('geom_color', colorList[0], None), ('geom1_color', colorList[0], None), ('geom2_color', colorList[0], None), ('geom3_color', colorList[0], None), ('relief', None, None)) self.defineoptions(kw, optiondefs) DirectButton.__init__(self, self.partyEditor._parent) self.initialiseoptions(PartyEditorGridElement) self.setName('%sGridElement' % self.name) self.bind(DirectGuiGlobals.B1PRESS, self.clicked) self.bind(DirectGuiGlobals.B1RELEASE, self.released) self.bind(DirectGuiGlobals.ENTER, self.mouseEnter) self.bind(DirectGuiGlobals.EXIT, self.mouseExit) self.uprightNodePath = NodePath('%sUpright' % self.name) self.uprightNodePath.reparentTo(self) rollOverZOffset = self.getGridSize()[1] / 30.0 self.rolloverTitle = DirectLabel(relief=None, parent=self.uprightNodePath, pos=Point3(0.0, 0.0, rollOverZOffset), text=self.name, text_fg=(1.0, 1.0, 1.0, 1.0), text_shadow=(0.0, 0.0, 0.0, 1.0), text_scale=0.075) self.rolloverTitle.stash() self.stash() self.overValidSquare = False self.lastValidPosition = None self.setColorScale(0.9, 0.9, 0.9, 0.7) self.setTransparency(True) self.mouseOverTrash = False self.centerGridSquare = None return def getCorrectRotation(self): r = self.getR() if r == 90.0: r = 270.0 elif r == 270.0: r = 90.0 if self.id == PartyGlobals.ActivityIds.PartyCannon: return PartyUtils.convertDegreesToPartyGrid(r + 180.0) return PartyUtils.convertDegreesToPartyGrid(r) def getDecorationTuple(self, x, y): return (self.id, self.centerGridSquare.x, PartyGlobals.PartyEditorGridSize[1] - 1 - self.centerGridSquare.y, self.getCorrectRotation()) def getActivityTuple(self, x, y): return (self.id, self.centerGridSquare.x, PartyGlobals.PartyEditorGridSize[1] - 1 - self.centerGridSquare.y, self.getCorrectRotation()) def attach(self, mouseEvent): PartyEditorGridElement.notify.debug('attached grid element %s' % self.name) taskMgr.remove('gridElementDragTask%s' % self.name) vWidget2render2d = self.getPos(render2d) vMouse2render2d = Point3(mouseEvent.getMouse()[0], 0, mouseEvent.getMouse()[1]) taskMgr.add(self.elementDragTask, 'gridElementDragTask%s' % self.name) self.unstash() self.rolloverTitle.unstash() self.uprightNodePath.reparentTo(self) self.setPosHprToDefault() def elementDragTask(self, state): mwn = base.mouseWatcherNode if mwn.hasMouse(): vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1]) newPos = vMouse2render2d if newPos[0] > PartyGlobals.PartyEditorGridBounds[0][0] and newPos[0] < PartyGlobals.PartyEditorGridBounds[1][0] and newPos[2] < PartyGlobals.PartyEditorGridBounds[0][1] and newPos[2] > PartyGlobals.PartyEditorGridBounds[1][1]: centerGridSquare = self.snapToGrid(newPos) if centerGridSquare is not None: self.centerGridSquare = centerGridSquare if not self.overValidSquare: self.setOverValidSquare(True) if self.mouseOverTrash: self.setOverTrash(False) return Task.cont if self.id != PartyGlobals.ActivityIds.PartyClock and newPos[0] > PartyGlobals.PartyEditorTrashBounds[0][0] and newPos[0] < PartyGlobals.PartyEditorTrashBounds[1][0] and newPos[2] < PartyGlobals.PartyEditorTrashBounds[0][1] and newPos[2] > PartyGlobals.PartyEditorTrashBounds[1][1]: if not self.mouseOverTrash: self.setOverTrash(True) elif self.mouseOverTrash: self.setOverTrash(False) self.setPos(render2d, newPos) if self.overValidSquare: self.setOverValidSquare(False) return Task.cont def setOverTrash(self, value): self.mouseOverTrash = value if value: self.partyEditor.trashCanButton['state'] = DirectGuiGlobals.DISABLED self.setColorScale(1.0, 0.0, 0.0, 1.0) else: self.partyEditor.trashCanButton['state'] = DirectGuiGlobals.NORMAL self.setColorScale(0.9, 0.9, 0.9, 0.7) def setOverValidSquare(self, value): self.overValidSquare = value if value: self.setColorScale(1.0, 1.0, 1.0, 1.0) else: self.setColorScale(0.9, 0.9, 0.9, 0.7) def removeFromGrid(self): if self.centerGridSquare is not None: self.partyEditor.partyEditorGrid.removeElement(self.centerGridSquare, self.getGridSize()) self.setOverValidSquare(False) self.lastValidPosition = None self.stash() return def snapToGrid(self, newPos): gridSquare = self.getGridSquareFromPosition(newPos) if gridSquare == None: self.setPosHprToDefault() self.setPos(render2d, newPos) return elif not self.partyEditor.partyEditorGrid.checkGridSquareForAvailability(gridSquare, self.getGridSize()): self.setPos(render2d, newPos) return self.setPosHprBasedOnGridSquare(gridSquare) return gridSquare def getGridSize(self): if self.isDecoration: return PartyGlobals.DecorationInformationDict[self.id]['gridsize'] else: return PartyGlobals.ActivityInformationDict[self.id]['gridsize'] def setPosHprToDefault(self): self.setR(0.0) self.uprightNodePath.setR(0.0) def setPosHprBasedOnGridSquare(self, gridSquare): gridPos = gridSquare.getPos() if self.getGridSize()[0] % 2 == 0: gridPos.setX(gridPos[0] + PartyGlobals.PartyEditorGridSquareSize[0] / 2.0) if self.getGridSize()[1] % 2 == 0: gridPos.setZ(gridPos[2] + PartyGlobals.PartyEditorGridSquareSize[1] / 2.0) if self.id != PartyGlobals.ActivityIds.PartyFireworks: if gridPos[0] > PartyGlobals.PartyEditorGridCenter[0] + PartyGlobals.PartyEditorGridRotateThreshold: self.setR(90.0) self.uprightNodePath.setR(-90.0) elif gridPos[0] < PartyGlobals.PartyEditorGridCenter[0] - PartyGlobals.PartyEditorGridRotateThreshold: self.setR(270.0) self.uprightNodePath.setR(-270.0) elif gridPos[2] < PartyGlobals.PartyEditorGridCenter[1] - PartyGlobals.PartyEditorGridRotateThreshold: self.setR(180.0) self.uprightNodePath.setR(-180.0) else: self.setR(0.0) self.uprightNodePath.setR(0.0) else: self.setR(270.0) self.uprightNodePath.setR(-270.0) self.setPos(render2d, gridPos) self.lastValidPosition = gridPos def getGridSquareFromPosition(self, newPos): localX = newPos[0] - PartyGlobals.PartyEditorGridBounds[0][0] localY = newPos[2] - PartyGlobals.PartyEditorGridBounds[1][1] x = int(localX / PartyGlobals.PartyEditorGridSquareSize[0]) y = int(localY / PartyGlobals.PartyEditorGridSquareSize[1]) y = PartyGlobals.PartyEditorGridSize[1] - 1 - y return self.partyEditor.partyEditorGrid.getGridSquare(x, y) def detach(self, mouseEvent): taskMgr.remove('gridElementDragTask%s' % self.name) self.rolloverTitle.stash() if self.overValidSquare: self.partyEditor.partyEditorGrid.registerNewElement(self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.handleMutuallyExclusiveActivities() elif self.lastValidPosition is not None: if self.mouseOverTrash: self.partyEditor.trashCanButton['state'] = DirectGuiGlobals.NORMAL self.lastValidPosition = None self.partyEditor.updateCostsAndBank() self.stash() else: self.setPos(render2d, self.lastValidPosition) self.setOverValidSquare(True) self.partyEditor.partyEditorGrid.registerNewElement(self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.handleMutuallyExclusiveActivities() else: self.stash() self.checkSoldOutAndPaidStatusAndAffordability() return def placeInPartyGrounds(self, desiredXY = None): self.centerGridSquare = self.partyEditor.partyEditorGrid.getClearGridSquare(self.getGridSize(), desiredXY) if self.centerGridSquare is not None: self.setOverValidSquare(True) self.unstash() self.setPosHprBasedOnGridSquare(self.centerGridSquare) self.partyEditor.partyEditorGrid.registerNewElement(self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsPartyGrounds self.checkSoldOutAndPaidStatusAndAffordability() return True else: return False return def clicked(self, mouseEvent): PartyEditorGridElement.notify.debug('clicked grid element %s' % self.name) if self.centerGridSquare is not None: self.attach(mouseEvent) self.partyEditor.partyEditorGrid.removeElement(self.centerGridSquare, self.getGridSize()) return def released(self, mouseEvent): PartyEditorGridElement.notify.debug('released grid element %s' % self.name) self.detach(mouseEvent) def mouseEnter(self, mouseEvent): parent = self.getParent() self.reparentTo(parent) self.rolloverTitle.unstash() def mouseExit(self, mouseEvent): self.rolloverTitle.stash() def destroy(self): self.unbind(DirectGuiGlobals.B1PRESS) self.unbind(DirectGuiGlobals.B1RELEASE) self.unbind(DirectGuiGlobals.ENTER) self.unbind(DirectGuiGlobals.EXIT) DirectButton.destroy(self)
class RepairMincroGame(DirectFrame, FSM.FSM): readySound = None goSound = None completeSound = None def __init__(self, repairGame, name, startText): DirectFrame.__init__(self, parent = repairGame.gui, relief = None) FSM.FSM.__init__(self, '%sFSM' % name) self.defaultTransitions = { 'Idle': [ 'Intro', 'Final'], 'Intro': [ 'Game', 'Idle', 'Final'], 'Game': [ 'Outro', 'Idle', 'Final'], 'Outro': [ 'Idle', 'Final'], 'Final': [] } self.name = name self.repairGame = repairGame self.startText = startText self._initVars() self._initAudio() self._initVisuals() self._initIntervals() self.request('Idle') def _initVars(self): self.complete = False self.difficulty = 0 def _initAudio(self): if not self.readySound: RepairMincroGame.readySound = loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_GENERAL_READY) RepairMincroGame.goSound = loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_GENERAL_GO) RepairMincroGame.completeSound = loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_GENERAL_GAMECOMPLETE) def _initVisuals(self): self.countDownLabel = DirectLabel(text = self.startText, text_fg = (1.0, 1.0, 1.0, 1.0), text_shadow = (0.0, 0.0, 0.0, 1.0), text_font = PiratesGlobals.getPirateFont(), scale = (0.16, 0.16, 0.16), pos = (0.0, 0.0, 0.14999999999999999), parent = self, relief = None, textMayChange = 1) self.countDownLabel.setBin('fixed', 37) self.winLabel = DirectLabel(text = PLocalizer.Minigame_Repair_Win, text_fg = (1.0, 1.0, 1.0, 1.0), text_font = PiratesGlobals.getPirateFont(), text_shadow = (0.0, 0.0, 0.0, 1.0), scale = (0.16, 0.16, 0.16), pos = RepairGlobals.Common.youWinPos[self.name], relief = None, parent = self) self.winLabel.setBin('fixed', 37) self.winLabel.stash() self.scoreLabel = DirectLabel(text = PLocalizer.Minigame_Repair_Win, text_fg = (1.0, 1.0, 1.0, 1.0), text_font = PiratesGlobals.getPirateFont(), text_shadow = (0.0, 0.0, 0.0, 1.0), scale = (0.10000000000000001, 0.10000000000000001, 0.10000000000000001), pos = RepairGlobals.Common.scorePos[self.name], relief = None, parent = self) self.scoreLabel.setBin('fixed', 37) self.scoreLabel.stash() self.postWinLabel = DirectLabel(text = PLocalizer.Minigame_Repair_Pick_New_Game, text_fg = (1.0, 1.0, 1.0, 1.0), text_font = PiratesGlobals.getPirateFont(), text_shadow = (0.0, 0.0, 0.0, 1.0), scale = (0.14000000000000001, 0.14000000000000001, 0.14000000000000001), pos = RepairGlobals.Common.youWinPos[self.name], relief = None, textMayChange = 1, parent = self.repairGame.gui) self.postWinLabel.setBin('fixed', 37) self.postWinLabel.stash() def _initIntervals(self): normalPos = Vec3(0.0, 0.0, 0.14999999999999999) belowScreenPos = Vec3(normalPos.getX(), normalPos.getY(), normalPos.getZ() - 0.25) aboveScreenPos = Vec3(normalPos.getX(), normalPos.getY(), normalPos.getZ() + 0.25) self.introSequence = Sequence(Func(self.setCountDown, PLocalizer.Minigame_Repair_Countdown_Ready), Parallel(LerpFunc(self.countDownLabel.setPos, fromData = belowScreenPos, toData = normalPos, duration = 0.25), LerpFunc(self.countDownLabel.setAlphaScale, fromData = 0.0, toData = 1.0, duration = 0.25)), Func(self.readySound.play), Wait(0.5), Parallel(LerpFunc(self.countDownLabel.setPos, fromData = normalPos, toData = aboveScreenPos, duration = 0.25), LerpFunc(self.countDownLabel.setAlphaScale, fromData = 1.0, toData = 0.0, duration = 0.25)), Func(self.setCountDown, self.startText), Parallel(LerpFunc(self.countDownLabel.setPos, fromData = belowScreenPos, toData = normalPos, duration = 0.25), LerpFunc(self.countDownLabel.setAlphaScale, fromData = 0.0, toData = 1.0, duration = 0.25)), Func(self.goSound.play), Wait(0.5), Parallel(LerpFunc(self.countDownLabel.setPos, fromData = normalPos, toData = aboveScreenPos, duration = 0.25), LerpFunc(self.countDownLabel.setAlphaScale, fromData = 1.0, toData = 0.0, duration = 0.25)), Func(self.request, 'Game'), name = 'RepairMincroGame.introSequence') normalPos = Vec3(RepairGlobals.Common.youWinPos[self.name]) normalScorePos = Vec3(RepairGlobals.Common.scorePos[self.name]) belowScreenPos = Vec3(normalPos.getX(), normalPos.getY(), normalPos.getZ() - 0.25) aboveScreenPos = Vec3(normalPos.getX(), normalPos.getY(), normalPos.getZ() + 0.25) belowScreenScorePos = Vec3(normalScorePos.getX(), normalScorePos.getY(), normalScorePos.getZ() - 0.25) aboveScreenScorePos = Vec3(normalScorePos.getX(), normalScorePos.getY(), normalScorePos.getZ() + 0.25) self.outroSequence = Sequence(Func(self.winLabel.setAlphaScale, 0), Func(self.scoreLabel.setAlphaScale, 0), Func(self.postWinLabel.setAlphaScale, 0), Func(self.winLabel.setPos, belowScreenPos), Func(self.scoreLabel.setPos, belowScreenScorePos), Func(self.postWinLabel.setPos, belowScreenPos), Func(self.setScoreLabelText), Func(self.winLabel.unstash), Func(self.scoreLabel.unstash), Func(self.postWinLabel.unstash), Parallel(LerpFunc(self.scoreLabel.setPos, fromData = belowScreenScorePos, toData = normalScorePos, duration = 0.25), LerpFunc(self.scoreLabel.setAlphaScale, fromData = 0.0, toData = 1.0, duration = 0.25), LerpFunc(self.winLabel.setPos, fromData = belowScreenPos, toData = normalPos, duration = 0.25), LerpFunc(self.winLabel.setAlphaScale, fromData = 0.0, toData = 1.0, duration = 0.25)), Func(self.completeSound.play), Wait(1.0), Parallel(LerpFunc(self.winLabel.setPos, fromData = normalPos, toData = aboveScreenPos, duration = 0.25), LerpFunc(self.winLabel.setAlphaScale, fromData = 1.0, toData = 0.0, duration = 0.25), LerpFunc(self.scoreLabel.setPos, fromData = normalScorePos, toData = aboveScreenScorePos, duration = 0.25), LerpFunc(self.scoreLabel.setAlphaScale, fromData = 1.0, toData = 0.0, duration = 0.25)), Func(self.winLabel.stash), Func(self.scoreLabel.stash), Func(self.stashPostWinLabelIfCycleComplete), Wait(0.25), Parallel(LerpFunc(self.postWinLabel.setPos, fromData = belowScreenPos, toData = normalPos, duration = 0.25), LerpFunc(self.postWinLabel.setAlphaScale, fromData = 0.0, toData = 1.0, duration = 0.25)), name = 'outroSequence') self.cleanupSequence = Sequence(Parallel(LerpFunc(self.postWinLabel.setPos, fromData = normalPos, toData = aboveScreenPos, duration = 0.5), LerpFunc(self.postWinLabel.setAlphaScale, fromData = 1.0, toData = 0.0, duration = 0.5), LerpFunc(self.scoreLabel.setAlphaScale, fromData = 1.0, toData = 0.0, duration = 0.5)), Func(self.scoreLabel.stash), Func(self.postWinLabel.stash), name = 'cleanupSequence') def updatePostWinLabel(self): if self.repairGame.isThereAnOpenGame(): self.postWinLabel['text'] = PLocalizer.Minigame_Repair_Pick_New_Game else: self.postWinLabel['text'] = PLocalizer.Minigame_Repair_Waiting_For_Players self.postWinLabel.setText() def setScoreLabelText(self): labelSet = False for i in [ 0, 1, 2]: if not labelSet: percent = self.difficulty / self.repairGame.difficultyMax dif = RepairGlobals.Common.speedThresholds[self.name][i][1] - RepairGlobals.Common.speedThresholds[self.name][i][0] goalTime = RepairGlobals.Common.speedThresholds[self.name][i][0] + dif * percent if self.repairGame.repairClock.gameTime < goalTime: labelSet = True self.scoreLabel['text'] = PLocalizer.Minigame_Repair_Speed_Thresholds[i] self.repairGame.repairClock.gameTime < goalTime if not labelSet: self.scoreLabel['text'] = PLocalizer.Minigame_Repair_Speed_Thresholds[3] def stashPostWinLabelIfCycleComplete(self): if self.repairGame.isCycleComplete(): self.postWinLabel.stash() def setDifficulty(self, difficulty): self.difficulty = difficulty def setCountDown(self, text): self.countDownLabel['text'] = text self.countDownLabel.setText() self.countDownLabel.setAlphaScale(0.0) def destroy(self): DirectFrame.destroy(self) self.countDownLabel.destroy() del self.countDownLabel self.winLabel.destroy() del self.winLabel self.introSequence.clearToInitial() del self.introSequence self.outroSequence.clearToInitial() del self.outroSequence self.cleanupSequence.clearToInitial() del self.cleanupSequence del self.repairGame self.cleanup() def reset(self): self.complete = False self.repairGame.repairClock.stop() def enterIdle(self): self.stash() def exitIdle(self): pass def enterIntro(self): self.unstash() self.countDownLabel.unstash() self.introSequence.start() self.reset() self.countDownLabel.reparentTo(self) def exitIntro(self): self.countDownLabel.stash() self.introSequence.clearToInitial() def enterGame(self): self.repairGame.repairClock.restart() def exitGame(self): self.repairGame.repairClock.pause() def enterOutro(self): self.outroSequence.start() self.complete = True def exitOutro(self): self.outroSequence.finish() self.cleanupSequence.start() self.reset() self.repairGame.gui.clearTutorial() self.repairGame.gui.clearTitle() def enterFinal(self): pass
class RepairPumpingGame(RepairMincroGame): pumpDownSounds = None pumpUpSounds = None pumpGoodSounds = None pumpBadSounds = None def __init__(self, repairGame): self.config = RepairGlobals.Pumping RepairMincroGame.__init__(self, repairGame, 'pumping', PLocalizer.Minigame_Repair_Pumping_Start) def _initVars(self): RepairMincroGame._initVars(self) self.pumpRate = 0.0 self.remainingWater = 1.0 self.chainCount = 0 self.barDirection = UP self.goalIndex = TOP self.currentBarRate = self.config.barStartRange[0] self.hitRange = self.config.hitRange[0] self.barPercent = 0.0 self.failedPercentAndDirection = (-1.0, UP) def _initAudio(self): RepairMincroGame._initAudio(self) if not self.pumpDownSounds: RepairPumpingGame.pumpDownSounds = (loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_DOWN01), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_DOWN02), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_DOWN03)) RepairPumpingGame.pumpUpSounds = (loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_UP01), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_UP02), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_UP03)) RepairPumpingGame.pumpGoodSounds = (loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_GOOD01), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_GOOD02), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_GOOD03), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_GOOD04), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_GOOD05), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_GOOD06)) RepairPumpingGame.pumpBadSounds = (loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_PUMP_BAD),) def _initVisuals(self): RepairMincroGame._initVisuals(self) self.model = loader.loadModel('models/gui/pir_m_gui_srp_pumping_main') self.visual = self.attachNewNode('visual') self.visual.setPos(-0.25, 0.0, 0.074999999999999997) goalTopLoc = self.model.find('**/locator_top') goalTopLoc.reparentTo(self.visual) goalBottomLoc = self.model.find('**/locator_bottom') goalBottomLoc.reparentTo(self.visual) self.goalPositions = (goalBottomLoc.getPos(self), goalTopLoc.getPos(self)) self.greatLabel = DirectLabel(text = PLocalizer.Minigame_Repair_Pumping_Great, text_fg = (0.20000000000000001, 0.80000000000000004, 0.29999999999999999, 1.0), text_pos = (0.0, 0.59999999999999998), text_align = TextNode.ACenter, text_font = PiratesGlobals.getPirateFont(), relief = None, text_shadow = (0.0, 0.0, 0.0, 1.0), scale = (0.080000000000000002, 0.080000000000000002, 0.080000000000000002), pos = (-0.46500000000000002, 0.0, 0.0), parent = self) self.failLabel = DirectLabel(text = PLocalizer.Minigame_Repair_Pumping_Fail, text_fg = (0.80000000000000004, 0.20000000000000001, 0.29999999999999999, 1.0), text_pos = (0.0, 0.59999999999999998), text_align = TextNode.ARight, text_font = PiratesGlobals.getPirateFont(), text_shadow = (0.0, 0.0, 0.0, 1.0), relief = None, scale = (0.080000000000000002, 0.080000000000000002, 0.080000000000000002), pos = (-0.625, 0.0, 0.0), parent = self) self.shipBackground = self.model.find('**/static_ship_background') self.shipBackground.reparentTo(self.visual) self.waterMeter = self.model.find('**/sprite_waterBottom') self.waterMeter.reparentTo(self.visual) self.waterTop = self.model.find('**/sprite_waterTop') self.waterTop.reparentTo(self.visual) self.waterMeterTopLoc = self.waterMeter.find('**/locator_topOfShipWater') self.pumpBackground = self.model.find('**/pumpBackground') self.pumpBackground.reparentTo(self.visual) self.pumpWaterTop = self.model.find('**/sprite_pumpWaterTop') self.pumpWaterTop.reparentTo(self.visual) self.pumpWaterBottom = self.model.find('**/sprite_pumpWaterBottom') self.pumpWaterBottom.reparentTo(self.visual) self.pumpWaterTopLoc = self.pumpWaterBottom.find('**/locator_topOfPumpWater') self.pumpHandle = self.model.find('**/sprite_handle') self.pumpHandle.reparentTo(self.visual) self.pumpBar = self.model.find('**/static_pump') self.pumpBar.reparentTo(self.visual) self.goalBox = self.model.find('**/sprite_clickField') self.goalBox.reparentTo(self.visual) self.goalBox.setTransparency(1) self.enableGoalBox() self.pumpLine = self.model.find('**/sprite_bar') self.pumpLine.reparentTo(self.visual) self.ghostLine = self.visual.attachNewNode('ghostLine') self.pumpLine.getChild(0).copyTo(self.ghostLine) self.ghostLine.setScale(self.pumpLine.getScale()) self.ghostLine.setColor(1.0, 0.20000000000000001, 0.20000000000000001, 1.0) self.shipForground = self.model.find('**/static_ship_foreground') self.shipForground.reparentTo(self.visual) cm = CardMaker('cardMaker') cm.setFrame(-0.33000000000000002, 0.33000000000000002, 0.0, 1.0) self.goalBox.setZ(self.goalPositions[TOP].getZ()) self.goalBoxStartScale = self.goalBox.getSz() self.enableGoalBox() self.pumpWaterUpLerp = LerpFunc(self.setPumpWater, fromData = -0.10000000000000001, toData = 1.0, duration = 0.5) self.pumpWaterDownLerp = LerpFunc(self.setPumpWater, fromData = 1.0, toData = -0.10000000000000001, duration = 0.5) self.model.removeNode() del self.model def destroy(self): del self.goalPositions self.pumpBar.removeNode() self.pumpLine.removeNode() self.goalBox.removeNode() self.pumpHandle.removeNode() self.waterMeter.removeNode() self.waterTop.removeNode() self.ghostLine.removeNode() self.shipBackground.removeNode() self.shipForground.removeNode() def reset(self): RepairMincroGame.reset(self) self.remainingWater = WATER_LEVEL_START self.chainCount = 0 self.barDirection = UP self.goalIndex = TOP self.barPercent = 0.0 self.failedPercentAndDirection = (-1.0, UP) actualZ = self.goalPositions[BOTTOM].getZ() actualZ -= self.visual.getZ() self.pumpLine.setZ(actualZ) self.setGoalIndex(TOP) self.pumpHandle.setR(ROTATION_MIN) self.waterMeter.setSz(WATER_LEVEL_START) self.waterTop.setZ(self.waterMeterTopLoc.getZ(self.visual)) self.ghostLine.stash() self.setPumpWater(1.0) self.failLabel.stash() self.greatLabel.stash() self.repairGame.gui.setTutorial(self.name) self.repairGame.gui.setTitle(self.name) def setDifficulty(self, difficulty): RepairMincroGame.setDifficulty(self, difficulty) percent = difficulty / self.repairGame.difficultyMax dif = self.config.pumpPowerRange[0] - self.config.pumpPowerRange[1] self.pumpRate = self.config.pumpPowerRange[0] - dif * percent dif = self.config.barStartRange[0] - self.config.barStartRange[1] self.currentBarRate = self.config.barStartRange[0] - dif * percent dif = self.config.hitRange[0] - self.config.hitRange[1] self.hitRange = self.config.hitRange[0] - dif * percent self.goalBox.setSz((self.hitRange / 0.17999999999999999) * self.goalBoxStartScale) def setGoalIndex(self, goalIndex): self.goalIndex = goalIndex self.goalBox.setZ(self, self.goalPositions[goalIndex].getZ()) self.goalBox.setR(180 * (goalIndex - 1)) def resetFail(self): self.failedPercentAndDirection = (-1.0, UP) self.enableGoalBox() self.hideMarkers() def updateTask(self, task): dt = globalClock.getDt() percentTimeThisStep = dt / (self.currentBarRate + self.config.barSpeedMax) self.barPercent = self.barPercent + percentTimeThisStep * self.barDirection if self.failedPercentAndDirection[0] >= 0.0: if self.failedPercentAndDirection[1] != self.barDirection: if self.failedPercentAndDirection[0] * self.barDirection < self.barPercent * self.barDirection: self.resetFail() if self.barPercent >= 1.0: self.barPercent = 1.0 self.barDirection = DOWN if not self.isLineInBox(): self.chainCount = 0 if self.failedPercentAndDirection[0] < 0.5: self.resetFail() elif self.barPercent <= 0.0: self.barPercent = 0.0 self.barDirection = UP if not self.isLineInBox(): self.chainCount = 0 if self.failedPercentAndDirection[0] > 0.5: self.resetFail() actualZ = self.goalPositions[0].getZ() + (self.goalPositions[1].getZ() - self.goalPositions[0].getZ()) * self.barPercent actualZ -= self.visual.getZ() self.pumpLine.setZ(actualZ) return Task.cont def enableGoalBox(self): self.goalBox.setColor(0.20000000000000001, 1.0, 0.20000000000000001, 0.59999999999999998) self.goalBoxEnabled = 1 def disableGoalBox(self): self.goalBox.setColor(1.0, 0.20000000000000001, 0.20000000000000001, 0.29999999999999999) self.goalBoxEnabled = 0 def isLineInBox(self): if self.goalIndex == TOP: return self.barPercent >= 1.0 - self.hitRange else: return self.barPercent <= self.hitRange def onMouseClick(self): if self.isLineInBox() and self.goalBoxEnabled == 1: actualPumpAmount = self.pumpRate + self.config.chainMultiplier * self.chainCount * self.pumpRate actualPumpAmount *= WATER_LEVEL_START - WATER_LEVEL_DONE self.remainingWater -= actualPumpAmount self.remainingWater = max(0.0, self.remainingWater) self.waterMeter.setSz(self.remainingWater) self.waterTop.setZ(self.waterMeterTopLoc.getZ(self.visual) - 0.001) if self.barPercent > 0.5: self.pumpWaterDownLerp.duration = self.currentBarRate self.pumpWaterDownLerp.start() self.barDirection = DOWN self.pumpHandle.setR(ROTATION_MAX) random.choice(self.pumpDownSounds).play() else: self.pumpWaterUpLerp.duration = self.currentBarRate self.pumpWaterUpLerp.start() self.barDirection = UP self.pumpHandle.setR(ROTATION_MIN) random.choice(self.pumpUpSounds).play() if self.barPercent > 0.5: self.setGoalIndex(BOTTOM) else: self.setGoalIndex(TOP) self.currentBarRate /= self.config.barSpeedIncrease self.chainCount += 1 self.setSuccessMarker() if self.remainingWater <= WATER_LEVEL_DONE and self.barDirection == DOWN: self.remainingWater = 0.0 self.request('Outro') return None totalRange = WATER_LEVEL_START - WATER_LEVEL_DONE current = WATER_LEVEL_START - self.remainingWater percent = min(100, int((current / totalRange) * 100)) self.repairGame.d_reportMincroGameProgress(percent, max(0, min(5, self.chainCount) - 1)) else: self.disableGoalBox() self.currentBarRate /= self.config.barSpeedDecrease self.currentBarRate += (1 - self.config.barSpeedDecrease) * self.config.barSpeedMin self.currentBarRate = min(self.currentBarRate, self.config.barSpeedMin) self.setFailMarker() self.chainCount = 0 self.failedPercentAndDirection = (self.barPercent, self.barDirection) def setPumpWater(self, value): self.pumpWaterBottom.setSz(value) self.pumpWaterTop.setZ(self.pumpWaterTopLoc.getZ(self.visual)) def setSuccessMarker(self): self.greatLabel.setZ(self.pumpLine.getZ()) self.greatLabel.unstash() pumpSoundIndex = min(len(self.pumpGoodSounds) - 1, self.chainCount / 2) self.pumpGoodSounds[pumpSoundIndex].play() def setFailMarker(self): self.hideMarkers() self.ghostLine.setPos(self.pumpLine.getPos()) self.ghostLine.unstash() self.failLabel.setZ(self.pumpLine.getZ()) self.failLabel.unstash() random.choice(self.pumpBadSounds).play() def hideMarkers(self): self.ghostLine.stash() self.greatLabel.stash() self.failLabel.stash() def enterGame(self): RepairMincroGame.enterGame(self) taskMgr.add(self.updateTask, 'RepairPumpingGame.updateTask') self.accept('mouse1', self.onMouseClick) self.enableGoalBox() def exitGame(self): RepairMincroGame.exitGame(self) taskMgr.remove('RepairPumpingGame.updateTask') self.ignore('mouse1') def enterOutro(self): RepairMincroGame.enterOutro(self) self.repairGame.d_reportMincroGameScore(150)
class CogdoFlyingGuiManager: def __init__(self, player): self.player = player self.root = NodePath("CogdoFlyingGui") self.root.reparentTo(aspect2d) self.fuelMeter = NodePath("scrubMeter") self.fuelMeter.reparentTo(self.root) self.fuelMeter.setPos(1.1, 0.0, -0.7) self.fuelMeter.setSz(2.0) cm = CardMaker('card') cm.setFrame(-0.07, 0.07, 0.0, 0.75) self.fuelMeterBar = self.fuelMeter.attachNewNode(cm.generate()) self.fuelMeterBar.setColor(0.95, 0.95, 0.0, 1.0) self.fuelLabel = DirectLabel( parent=self.root, relief=None, pos=(1.1, 0, -0.8), scale=0.075, text="Fuel", text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getInterfaceFont(), ) self.messageLabel = DirectLabel( parent=self.root, relief=None, pos=(0.0, 0.0, -0.9), scale=0.1, text=" ", text_align=TextNode.ACenter, text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getInterfaceFont(), textMayChange=1, ) self.messageLabel.stash() self.winLabel = DirectLabel( parent=self.root, relief=None, pos=(0.0, 0.0, 0.0), scale=0.25, text="You win!", text_align=TextNode.ACenter, text_fg=(0.95, 0.95, 0, 1), text_shadow=(0, 0, 0, 1), text_font=ToontownGlobals.getInterfaceFont(), ) self.winLabel.stash() self.refuelLerp = LerpFunctionInterval(self.fuelMeterBar.setSz, fromData=0.0, toData=1.0, duration=2.0) def setRefuelLerpFromData(self): startScale = self.fuelMeterBar.getSz() self.refuelLerp.fromData = startScale def setMessageLabelText(self, text): self.messageLabel["text"] = text self.messageLabel.setText() def update(self): self.fuelMeterBar.setSz(self.player.fuel) def destroy(self): # print "Destroying GUI" self.fuelMeterBar.detachNode() self.fuelMeterBar = None self.fuelLabel.detachNode() self.fuelLabel = None self.fuelMeter.detachNode() self.fuelMeter = None self.winLabel.detachNode() self.winLabel = None self.root.detachNode() self.root = None self.player = None
class RepairSawingGame(RepairMincroGame): sawSounds = None boardComplet = None boardDestroyed = None def __init__(self, repairGame): self.config = RepairGlobals.Sawing notify = DirectNotifyGlobal.directNotify.newCategory('RepairSawingGame') RepairMincroGame.__init__(self, repairGame, 'sawing', PLocalizer.Minigame_Repair_Sawing_Start) def _initVars(self): RepairMincroGame._initVars(self) self.boardsPool = { } self.currentBoard = None self.currentBoardIndex = 0 self.onDeckBoard = None self.onDeckBoardIndex = 0 self.totalScore = 0.0 self.hitZone1Penalty = False self.hitZone2Penalty = False self.hitBoardPenalty = False self.moveDiffForSound = 0.0 self.startPositions = (Point3(0.0, 0.0, 0.0),) self.currentStartIndex = 0 self.lastMousePos = None self.board_left = None self.board_right = None self.cut = None self.zone1_right = None self.zone1_left = None self.zone2_right = None self.zone2_left = None self.piece1 = None self.piece2 = None self.lastHitIndex = -1 self.sawWaypoints = [] def _initAudio(self): RepairMincroGame._initAudio(self) if not self.sawSounds: RepairSawingGame.sawSounds = (loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_INOUT01), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_INOUT02), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_INOUT03), loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_INOUT04)) RepairSawingGame.boardComplete = loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_COMPLETE) RepairSawingGame.boardDestroyed = loadSfx(SoundGlobals.SFX_MINIGAME_REPAIR_SAW_FAIL) def _initVisuals(self): RepairMincroGame._initVisuals(self) self.setBin('fixed', 36) self.model = loader.loadModel('models/gui/pir_m_gui_srp_sawing_main') sawModel = self.model.find('**/saw') sawModel.setR(193) sawModel.setPos(0.90000000000000002, 0.0, -0.16500000000000001) sawModel.setBin('gui-popup', 0) self.sawButton = RepairSaw(parent = self, clickDownCommand = self.sawAttachedToMouse, clickUpCommand = self.sawRemovedFromMouse, geom = sawModel, text_pos = (0.20000000000000001, -0.29999999999999999), text_fg = (1, 0, 0, 1), scale = (0.29999999999999999, 0.29999999999999999, 0.29999999999999999), relief = None, pressEffect = 0, frameSize = (-0.050000000000000003, 1.05, -0.29999999999999999, 0.050000000000000003), rolloverSound = None, clickSound = None) self.sawingLine = RepairSawingLine(self, self.config.sawlineLineThickness, self.config.sawlineColor, self.config.sawlineLinespawnDist) self.progressDescriptionLabel = DirectLabel(text = PLocalizer.Minigame_Repair_Sawing_Description, text_fg = (1.0, 1.0, 1.0, 1.0), text_pos = (0.0, 0.0), text_shadow = (0.0, 0.0, 0.0, 1.0), text_font = PiratesGlobals.getPirateFont(), text_align = TextNode.ARight, relief = None, scale = (0.080000000000000002, 0.080000000000000002, 0.080000000000000002), pos = (-0.20000000000000001, 0.0, 0.5), parent = self) self.progressLabel = DirectLabel(text = PLocalizer.Minigame_Repair_Sawing_Thresholds[3], text_fg = (1.0, 1.0, 1.0, 1.0), text_pos = (0.0, 0.0), text_shadow = (0.0, 0.0, 0.0, 1.0), text_font = PiratesGlobals.getPirateFont(), text_align = TextNode.ALeft, relief = None, scale = (0.080000000000000002, 0.080000000000000002, 0.080000000000000002), pos = (-0.17999999999999999, 0.0, 0.5), parent = self) self.boardDestroyedLabel = DirectLabel(text = PLocalizer.Minigame_Repair_Sawing_Board_Destroyed, text_fg = (1.0, 0.0, 0.0, 1.0), text_pos = (0.0, 0.0), text_font = PiratesGlobals.getPirateFont(), text_shadow = (0.0, 0.0, 0.0, 1.0), relief = None, scale = (0.10000000000000001, 0.10000000000000001, 0.10000000000000001), pos = (0.0, 0.0, 0.10000000000000001), parent = self) self.boardDestroyedLabel.setBin('fixed', 38) self.boardDestroyedLabel.stash() def _initIntervals(self): RepairMincroGame._initIntervals(self) self.newBoardSequence = Sequence(name = 'RepairSawingGame.newBoardSequence') self.splitBoardSequence = Sequence(name = 'RepairSawGame.splitBoardSequence') self.dropBoardSequence = Sequence(name = 'RepairSawGame.dropBoardSequence') def getNewBoard(self, boardIndex): board = self.model.find('**/wood%i' % boardIndex).copyTo(NodePath('board%i' % len(self.boardsPool))) board.reparentTo(self) piece1 = board.find('**/piece_1') piece1.setPythonTag('piece_1', self.piece1) piece1.setY(self.config.boardYDist) piece2 = board.find('**/piece_2') piece2.setPythonTag('piece_2', self.piece2) piece2.setY(self.config.boardYDist) pieceCut = board.find('**/piece_cut') pieceCut.setPythonTag('cut', self.cut) pieceCut.setColor(self.config.cutColor) pieceCut.setY(self.config.boardYDist) board_left = piece1.find('**/board') board_left.setPythonTag('left', self.board_left) board_right = piece2.find('**/board') board_right.setPythonTag('right', self.board_right) zone1_right = piece2.find('**/zone_1') zone1_right.setPythonTag('zone1_right', self.zone1_right) zone1_right.setColor(self.config.zone1Color) zone1_left = piece1.find('**/zone_1') zone1_left.setPythonTag('zone1_left', self.zone1_left) zone1_left.setColor(self.config.zone1Color) zone2_right = piece2.find('**/zone_2') zone2_right.setPythonTag('zone2_right', self.zone2_right) zone2_right.setColor(self.config.zone2Color) zone2_left = piece1.find('**/zone_2') zone2_left.setPythonTag('zone2_left', self.zone2_left) zone2_left.setColor(self.config.zone2Color) board.stash() return board def reset(self): for key in self.boardsPool.keys(): board = self.boardsPool[key] board.removeNode() self.boardsPool.clear() if self.currentBoard: self.currentBoard.removeNode() self.currentBoard = None if self.onDeckBoard: self.onDeckBoard.removeNode() self.onDeckBoard = None for boardIndex in self.currentDifficultySet: boardIndex -= 1 if 'copy1_%s' % boardIndex not in self.boardsPool: board = self.getNewBoard(boardIndex) self.boardsPool['copy1_%s' % boardIndex] = board if 'copy2_%s' % boardIndex not in self.boardsPool: board = self.getNewBoard(boardIndex) self.boardsPool['copy2_%s' % boardIndex] = board continue self.currentBoardIndex = 0 self.currentBoard = None self.moveNewBoardOnDeck() self.onDeckBoard.unstash() self.totalScore = 0 self.startPositions = (Point3(0.0, 0.0, 0.0),) self.sawButton.stash() self.sawButton.reparentTo(self) self.lastHitIndex = -1 self.moveDiffForSound = 0.0 RepairMincroGame.reset(self) self.repairGame.gui.setTutorial(self.name) self.repairGame.gui.setTitle(self.name) def destroy(self): RepairMincroGame.destroy(self) taskMgr.remove('SawingGame.updateSawTask') self.sawButton.destroy() self.sawButton.removeNode() del self.sawButton if self.currentBoard: self.currentBoard.removeNode() self.currentBoard = None if self.onDeckBoard: self.onDeckBoard.removeNode() self.onDeckBoard = None self.sawingLine = None self.progressDescriptionLabel.destroy() self.progressDescriptionLabel = None self.progressLabel.destroy() self.progressLabel = None self.boardDestroyedLabel.destroy() self.boardDestroyedLabel = None for key in self.boardsPool.keys(): board = self.boardsPool[key] if not board.isEmpty(): board.removeNode() continue self.boardsPool.clear() self.newBoardSequence.clearToInitial() del self.newBoardSequence self.splitBoardSequence.clearToInitial() del self.splitBoardSequence self.dropBoardSequence.clearToInitial() del self.dropBoardSequence def setDifficulty(self, difficulty): RepairMincroGame.setDifficulty(self, difficulty) percent = difficulty / self.repairGame.difficultyMax difIndex = int(math.floor(percent * (len(self.config.difficultySets) - 1))) self.currentDifficultySet = self.config.difficultySets[difIndex] def splitBoard(self): self.sawingLine.reset() board = self.currentBoard boardIndex = self.currentBoardIndex if self.hitZone2Penalty: boardSplitAnim = Parallel(LerpPosInterval(self.board_left, duration = self.config.splitBoardAnimTime, pos = Point3(-2.0, 0.0, 0.0)), LerpPosInterval(self.board_right, duration = self.config.splitBoardAnimTime, pos = Point3(2.0, 0.0, 0.0)), LerpFunc(self.zone2_left.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0), LerpFunc(self.zone2_right.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0), LerpFunc(self.zone1_left.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0), LerpFunc(self.zone1_right.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0), LerpFunc(self.cut.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0)) elif self.hitZone1Penalty: boardSplitAnim = Parallel(LerpPosInterval(self.board_left, duration = self.config.splitBoardAnimTime, pos = Point3(-2.0, 0.0, 0.0)), LerpPosInterval(self.board_right, duration = self.config.splitBoardAnimTime, pos = Point3(2.0, 0.0, 0.0)), LerpPosInterval(self.zone2_left, duration = self.config.splitBoardAnimTime, pos = Point3(-2.0, 0.0, 0.0)), LerpPosInterval(self.zone2_right, duration = self.config.splitBoardAnimTime, pos = Point3(2.0, 0.0, 0.0)), LerpFunc(self.zone1_left.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0), LerpFunc(self.zone1_right.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0), LerpFunc(self.cut.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0)) else: boardSplitAnim = Parallel(LerpPosInterval(self.piece1, duration = self.config.splitBoardAnimTime, pos = Point3(-2.0, self.config.boardYDist, 0.0)), LerpPosInterval(self.piece2, duration = self.config.splitBoardAnimTime, pos = Point3(2.0, self.config.boardYDist, 0.0)), LerpFunc(self.cut.setSa, duration = self.config.splitBoardAnimTime / 2.0, fromData = 1.0, toData = 0.0)) self.splitBoardSequence = Sequence(Func(self.updateScore), Func(self.boardComplete.play), boardSplitAnim, Func(board.stash), Func(self.piece1.setPos, self.piece1.getPos()), Func(self.piece2.setPos, self.piece2.getPos()), Func(self.board_right.setPos, self.board_right.getPos()), Func(self.board_left.setPos, self.board_left.getPos()), Func(self.zone2_right.setPos, self.zone2_right.getPos()), Func(self.zone2_left.setPos, self.zone2_left.getPos()), Func(self.zone1_right.setPos, self.zone1_right.getPos()), Func(self.zone1_left.setPos, self.zone1_left.getPos()), Func(self.cut.setSa, 1.0), Func(self.zone1_right.setSa, 1.0), Func(self.zone1_left.setSa, 1.0), Func(self.zone2_right.setSa, 1.0), Func(self.zone2_left.setSa, 1.0), Func(self.board_right.setSa, 1.0), Func(self.board_left.setSa, 1.0), Func(self.loadNewBoard), Func(self.addBoardBackToPool, board, boardIndex), name = 'RepairSawGame.splitBoardSequence') self.splitBoardSequence.start() def dropBoard(self): board = self.currentBoard boardIndex = self.currentBoardIndex self.dropBoardSequence = Sequence(Parallel(Sequence(Func(self.boardDestroyedLabel.unstash), Wait(1.5), Func(self.boardDestroyedLabel.stash)), Sequence(Wait(0.5), Func(self.boardDestroyed.play), Func(self.sawingLine.reset), LerpPosInterval(board, duration = self.config.splitBoardAnimTime, pos = Point3(0.0, 0.0, -2.0)), Func(board.stash), Wait(0.5), Func(self.loadNewBoard), Func(self.addBoardBackToPool, board, boardIndex))), name = 'RepairSawGame.dropBoardSequence') self.dropBoardSequence.start() def addBoardBackToPool(self, board, boardIndex): if 'copy1_%s' % boardIndex not in self.boardsPool: self.boardsPool['copy1_%s' % boardIndex] = board elif 'copy2_%s' % boardIndex not in self.boardsPool: self.boardsPool['copy2_%s' % boardIndex] = board else: self.notify.error('Two copies of board type %i already in the boardsPool!' % boardIndex) def updateScoreText(self): self.progressLabel.unstash() self.progressDescriptionLabel.unstash() if self.hitBoardPenalty: self.progressLabel['text'] = PLocalizer.Minigame_Repair_Sawing_Thresholds[0] self.progressLabel['text_fg'] = Vec4(1.0, 0.0, 0.0, 1.0) self.progressLabel.setText() elif self.hitZone2Penalty: self.progressLabel['text'] = PLocalizer.Minigame_Repair_Sawing_Thresholds[1] self.progressLabel['text_fg'] = Vec4(1.0, 0.5, 0.0, 1.0) self.progressLabel.setText() elif self.hitZone1Penalty: self.progressLabel['text'] = PLocalizer.Minigame_Repair_Sawing_Thresholds[2] self.progressLabel['text_fg'] = Vec4(1.0, 1.0, 0.0, 1.0) self.progressLabel.setText() else: self.progressLabel['text'] = PLocalizer.Minigame_Repair_Sawing_Thresholds[3] self.progressLabel['text_fg'] = Vec4(0.0, 1.0, 0.0, 1.0) self.progressLabel.setText() def moveNewBoardOnDeck(self): boardIndex = random.randint(0, len(self.currentDifficultySet) - 1) boardType = self.currentDifficultySet[boardIndex] boardType -= 1 if 'copy1_%s' % boardType in self.boardsPool: self.onDeckBoard = self.boardsPool['copy1_%s' % boardType] del self.boardsPool['copy1_%s' % boardType] elif 'copy2_%s' % boardType in self.boardsPool: self.onDeckBoard = self.boardsPool['copy2_%s' % boardType] del self.boardsPool['copy2_%s' % boardType] else: self.notify.error('No copies of board type %i in the boardsPool!' % boardType) self.onDeckBoardIndex = boardType self.onDeckBoard.setScale(0.25) self.onDeckBoard.setPos(0.5, -2.0, 0.56000000000000005) self.onDeckBoard.unstash() def loadNewBoard(self): self.progressLabel.stash() self.progressDescriptionLabel.stash() if self.totalScore >= self.config.totalPoints: if self.onDeckBoard: self.onDeckBoard.stash() self.progressDescriptionLabel.stash() taskMgr.remove('SawingGame.updateSawTask') self.request('Outro') return None self.currentBoard = self.onDeckBoard self.currentBoardIndex = self.onDeckBoardIndex self.piece1 = self.currentBoard.find('**/piece_1') self.piece1.setTransparency(1) self.piece2 = self.currentBoard.find('**/piece_2') self.piece2.setTransparency(1) self.cut = self.currentBoard.find('**/piece_cut') self.cut.setColor(self.config.cutColor) self.cut.setTransparency(1) self.board_left = self.piece1.find('**/board') self.board_left.setTransparency(1) self.zone1_left = self.piece1.find('**/zone_1') self.zone1_left.setTransparency(1) self.zone2_left = self.piece1.find('**/zone_2') self.zone2_left.setTransparency(1) self.board_right = self.piece2.find('**/board') self.board_right.setTransparency(1) self.zone1_right = self.piece2.find('**/zone_1') self.zone1_right.setTransparency(1) self.zone2_right = self.piece2.find('**/zone_2') self.zone2_right.setTransparency(1) self.board_left.setCollideMask(SAW_COLLIDE_MASK) self.board_right.setCollideMask(SAW_COLLIDE_MASK) self.cut.setCollideMask(SAW_COLLIDE_MASK) self.zone1_right.setCollideMask(SAW_COLLIDE_MASK) self.zone1_left.setCollideMask(SAW_COLLIDE_MASK) self.zone2_right.setCollideMask(SAW_COLLIDE_MASK) self.zone2_left.setCollideMask(SAW_COLLIDE_MASK) self.startPositions = (self.currentBoard.find('**/locator_start_0').getPos() + Point3(*self.config.activeBoardPosition), self.currentBoard.find('**/locator_start_1').getPos() + Point3(*self.config.activeBoardPosition)) self.currentStartIndex = 0 for waypoint in self.sawWaypoints: waypoint.removeNode() self.sawWaypoints = [] locator = self.currentBoard.find('**/locator_0') index = 0 while not locator.isEmpty(): self.sawWaypoints.append(SawWaypoint(index, self.currentBoard, locator.getPos())) locator = self.currentBoard.find('**/locator_%i' % (index + 1)) index += 1 self.sawButton.deactivate() self.sawButton.setPos(self.startPositions[self.currentStartIndex]) self.hitBoardPenalty = False self.hitZone1Penalty = False self.hitZone2Penalty = False self.lastMousePos = None self.moveDiffForSound = self.config.playSawingSoundDelta + 0.10000000000000001 self.newBoardSequence = Sequence(Parallel(self.currentBoard.posInterval(self.config.newBoardAnimTime, Point3(*self.config.activeBoardPosition)), self.currentBoard.scaleInterval(self.config.newBoardAnimTime, 1.0)), name = 'RepairSawingGame.newBoardSequence') if self.state in [ 'Game']: self.newBoardSequence.append(Func(self.sawButton.activate)) self.newBoardSequence.append(Wait(0.5)) self.newBoardSequence.append(Func(self.moveNewBoardOnDeck)) self.newBoardSequence.start() def updateSawTask(self, task): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() relative = Point3(mpos.getX(), 0.0, mpos.getY()) relative = self.getRelativePoint(render2d, relative) moveDiff = 0.0 if self.lastMousePos != None: moveDiff = (relative - self.lastMousePos).length() pickedObjects = self.repairGame.mousePicker.getCollisions(self.currentBoard, useIntoNodePaths = True) self.updateWaypoints() if len(pickedObjects) > 0: self.moveDiffForSound += moveDiff if self.moveDiffForSound > self.config.playSawingSoundDelta: sawSoundPlaying = False for sound in self.sawSounds: if sound.status() == 2: sawSoundPlaying = True break continue if sawSoundPlaying == False: sound = random.choice(self.sawSounds) sound.play() self.moveDiffForSound = 0.0 if self.board_right in pickedObjects or self.board_left in pickedObjects: for waypoint in self.sawWaypoints: waypoint.hit = False self.hitBoardPenalty = True self.dropBoard() self.sawButton.deactivate() elif self.cut in pickedObjects: self.updateWaypoints() elif self.zone1_right in pickedObjects or self.zone1_left in pickedObjects: self.updateWaypoints() if self.hitZone1Penalty == False: self.hitZone1Penalty = True elif self.zone2_right in pickedObjects or self.zone2_left in pickedObjects: self.updateWaypoints() if self.hitZone2Penalty == False: self.hitZone2Penalty = True self.updateScoreText() else: boardComplete = True for waypoint in self.sawWaypoints: if not waypoint.hit: boardComplete = False break continue if boardComplete: self.splitBoard() self.sawButton.deactivate() self.lastMousePos = self.sawButton.getPos() return Task.cont def updateScore(self): if not self.hitBoardPenalty: currBoardScore = self.config.pointsPerBoard if not self.hitZone1Penalty: pass currBoardScore -= self.config.pointsLostForZone1 * self.hitZone2Penalty currBoardScore -= self.config.pointsLostForZone2 * self.hitZone2Penalty rating = 4 - 1 * self.hitZone2Penalty - 3 * self.hitZone1Penalty self.totalScore += currBoardScore self.totalScore = min(self.totalScore, self.config.totalPoints) percent = int((self.totalScore / self.config.totalPoints) * 100.0) self.repairGame.d_reportMincroGameProgress(percent, rating) def resetWaypoints(self): for waypoint in self.sawWaypoints: waypoint.hit = False def updateWaypoints(self): waypointList = self.getHitWaypoints() for waypointIndex in waypointList: self.lastHitIndex = waypointIndex self.sawWaypoints[waypointIndex].hit = True if waypointIndex == 0 and not (self.sawWaypoints[-1].hit): self.currentStartIndex = 0 continue if waypointIndex == len(self.sawWaypoints) - 1 and not (self.sawWaypoints[0].hit): self.currentStartIndex = 1 continue def getHitWaypoints(self): waypointsHit = [] testDelta = self.config.testWaypointDelta for i in range(len(self.sawWaypoints)): waypointPos = self.sawWaypoints[i].getPos(self) closestDistance = 9999 if self.lastMousePos != None: currMousePos = self.sawButton.getPos() lastMousePos = self.lastMousePos totalLength = (currMousePos - lastMousePos).length() testLength = testDelta while testLength < totalLength: testPos = (currMousePos - lastMousePos) * (testLength / totalLength) + lastMousePos self.updateSawLine(testPos) testDistance = (testPos - waypointPos).length() closestDistance = min(testDistance, closestDistance) testLength += testDelta self.updateSawLine(self.sawButton.getPos()) testDistance = (self.sawButton.getPos() - waypointPos).length() closestDistance = min(testDistance, closestDistance) if closestDistance < self.config.waypointRange[self.currentBoardIndex]: waypointsHit.append(i) continue return waypointsHit def updateSawLine(self, pos): if pos.getX() < -0.63300000000000001 or pos.getX() > 0.63300000000000001: self.sawingLine.reset() return None if pos.getZ() < -0.183 or pos.getZ() > 0.375: self.sawingLine.reset() return None self.sawingLine.update(pos) def getClosestPosition(self, positions): closestIndex = -1 if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() relative = Point3(mpos.getX(), 0.0, mpos.getY()) relative = self.getRelativePoint(base.a2dBackground, relative) bestDistance = 99999.0 for i in range(len(positions)): dX = relative.getX() - positions[i].getX() dZ = relative.getZ() - positions[i].getZ() newDistance = dX * dX + dZ * dZ if newDistance < bestDistance: bestDistance = newDistance closestIndex = i continue return closestIndex def sawAttachedToMouse(self): self.lastHitIndex = -1 if not taskMgr.hasTaskNamed('SawingGame.updateSawTask'): taskMgr.add(self.updateSawTask, 'SawingGame.updateSawTask', priority = 2) def sawRemovedFromMouse(self): if not self.sawButton.isStashed(): self.sawButton.setPos(self.startPositions[self.currentStartIndex]) self.lastHitIndex = -1 self.resetWaypoints() self.lastMousePos = None self.progressLabel.stash() self.progressDescriptionLabel.stash() self.sawingLine.reset() self.hitBoardPenalty = False self.hitZone1Penalty = False self.hitZone2Penalty = False taskMgr.remove('SawingGame.updateSawTask') def enterIntro(self): RepairMincroGame.enterIntro(self) self.loadNewBoard() def enterGame(self): RepairMincroGame.enterGame(self) self.repairGame.mousePicker.setCollisionMask(SAW_COLLIDE_MASK) self.sawButton.activate() def exitGame(self): RepairMincroGame.exitGame(self) self.sawButton.deactivate() self.repairGame.mousePicker.clearCollisionMask() taskMgr.remove('SawingGame.updateSawTask') self.splitBoardSequence.clearToInitial() self.dropBoardSequence.clearToInitial() localAvatar.guiMgr._showCursor() def enterOutro(self): RepairMincroGame.enterOutro(self) self.repairGame.d_reportMincroGameScore(150)
class PartyEditorGridElement(DirectButton): """ PartyEditorGridElement is created when a PartyEditorListElement is created. They are what are placed on PartyEditorGridSquares to represent the element. """ notify = directNotify.newCategory("PartyEditorGridElement") def __init__(self, partyEditor, id, isDecoration, checkSoldOutAndPaidStatusAndAffordability, **kw): self.partyEditor = partyEditor self.id = id self.isDecoration = isDecoration self.checkSoldOutAndPaidStatusAndAffordability = checkSoldOutAndPaidStatusAndAffordability # method # Change the name and the up, down, rollover, and disabled colors if self.isDecoration: self.name = TTLocalizer.PartyDecorationNameDict[self.id]["editor"] colorList = ((1.0, 1.0, 1.0, 1.0), (0.0, 0.0, 1.0, 1.0), (0.0, 1.0, 1.0, 1.0), (0.5, 0.5, 0.5, 1.0)) self.geom = self.partyEditor.partyPlanner.gui.find( "**/%s" % PartyGlobals.DecorationInformationDict[self.id]["gridAsset"]) else: self.name = TTLocalizer.PartyActivityNameDict[self.id]["editor"] colorList = ((1.0, 1.0, 1.0, 1.0), (0.0, 1.0, 0.0, 1.0), (1.0, 1.0, 0.0, 1.0), (0.5, 0.5, 0.5, 1.0)) self.geom = self.partyEditor.partyPlanner.gui.find( "**/%s" % PartyGlobals.ActivityInformationDict[self.id]["gridAsset"]) optiondefs = ( ('geom', self.geom, None), ('geom_scale', 1.0, None), ('geom_color', colorList[0], None), ('geom1_color', colorList[0], None), ('geom2_color', colorList[0], None), ('geom3_color', colorList[0], None), ('relief', None, None), ) # Merge keyword options with default options, plus, this call makes # DirectButton work... that and the initializeoptions below... without # those two calls, strange... and I mean hard to debug, stuff happens. self.defineoptions(kw, optiondefs) DirectButton.__init__(self, self.partyEditor.parent) self.initialiseoptions(PartyEditorGridElement) self.setName("%sGridElement" % self.name) # Since normal buttons only call their command methods upon release # of the mouse button, we will not specify a command method and # instead bind our own methods to press and release. self.bind(DirectGuiGlobals.B1PRESS, self.clicked) self.bind(DirectGuiGlobals.B1RELEASE, self.released) self.bind(DirectGuiGlobals.ENTER, self.mouseEnter) self.bind(DirectGuiGlobals.EXIT, self.mouseExit) self.uprightNodePath = NodePath("%sUpright" % self.name) self.uprightNodePath.reparentTo(self) #debugAxis = loader.loadModel("models/misc/xyzAxis") #debugAxis.reparentTo(self.uprightNodePath) #debugAxis.setScale(0.01) rollOverZOffset = self.getGridSize()[1] / 30.0 self.rolloverTitle = DirectLabel( relief=None, parent=self.uprightNodePath, pos=Point3(0.0, 0.0, rollOverZOffset), text=self.name, text_fg=(1.0, 1.0, 1.0, 1.0), text_shadow=(0.0, 0.0, 0.0, 1.0), text_scale=0.075, ) self.rolloverTitle.stash() self.stash() self.overValidSquare = False self.lastValidPosition = None self.setColorScale(0.9, 0.9, 0.9, 0.7) self.setTransparency(True) self.mouseOverTrash = False self.centerGridSquare = None def getCorrectRotation(self): """ Since the y value is inverted in our grid, we need to flip the rotation of elements that are to either side, but not top/bottom. """ r = self.getR() if r == 90.0: r = 270.0 elif r == 270.0: r = 90.0 if self.id == PartyGlobals.ActivityIds.PartyCannon: return PartyUtils.convertDegreesToPartyGrid((r + 180.0)) return PartyUtils.convertDegreesToPartyGrid(r) def getDecorationTuple(self, x, y): return (self.id, self.centerGridSquare.x, PartyGlobals.PartyEditorGridSize[1] - 1 - self.centerGridSquare.y, self.getCorrectRotation()) def getActivityTuple(self, x, y): return (self.id, self.centerGridSquare.x, PartyGlobals.PartyEditorGridSize[1] - 1 - self.centerGridSquare.y, self.getCorrectRotation()) def attach(self, mouseEvent): PartyEditorGridElement.notify.debug("attached grid element %s" % self.name) taskMgr.remove("gridElementDragTask%s" % self.name) vWidget2render2d = self.getPos(render2d) vMouse2render2d = Point3(mouseEvent.getMouse()[0], 0, mouseEvent.getMouse()[1]) taskMgr.add(self.elementDragTask, "gridElementDragTask%s" % self.name) self.unstash() self.rolloverTitle.unstash() self.uprightNodePath.reparentTo(self) self.setPosHprToDefault() def elementDragTask(self, state): mwn = base.mouseWatcherNode if mwn.hasMouse(): vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1]) newPos = vMouse2render2d # Check to see if the new position is within the grounds bounds if newPos[0] > PartyGlobals.PartyEditorGridBounds[0][0] and \ newPos[0] < PartyGlobals.PartyEditorGridBounds[1][0] and \ newPos[2] < PartyGlobals.PartyEditorGridBounds[0][1] and \ newPos[2] > PartyGlobals.PartyEditorGridBounds[1][1]: centerGridSquare = self.snapToGrid(newPos) if centerGridSquare is not None: # The mouse is over the grid and over a valid square self.centerGridSquare = centerGridSquare if not self.overValidSquare: self.setOverValidSquare(True) if self.mouseOverTrash: self.setOverTrash(False) return Task.cont # Check to see if it is within the trash bounds if self.id != PartyGlobals.ActivityIds.PartyClock and \ newPos[0] > PartyGlobals.PartyEditorTrashBounds[0][0] and \ newPos[0] < PartyGlobals.PartyEditorTrashBounds[1][0] and \ newPos[2] < PartyGlobals.PartyEditorTrashBounds[0][1] and \ newPos[2] > PartyGlobals.PartyEditorTrashBounds[1][1]: if not self.mouseOverTrash: self.setOverTrash(True) else: if self.mouseOverTrash: self.setOverTrash(False) self.setPos(render2d, newPos) if self.overValidSquare: self.setOverValidSquare(False) return Task.cont def setOverTrash(self, value): self.mouseOverTrash = value if value: self.partyEditor.trashCanButton[ "state"] = DirectGuiGlobals.DISABLED self.setColorScale(1.0, 0.0, 0.0, 1.0) else: self.partyEditor.trashCanButton["state"] = DirectGuiGlobals.NORMAL self.setColorScale(0.9, 0.9, 0.9, 0.7) def setOverValidSquare(self, value): self.overValidSquare = value if value: self.setColorScale(1.0, 1.0, 1.0, 1.0) else: self.setColorScale(0.9, 0.9, 0.9, 0.7) def removeFromGrid(self): assert self.notify.debugStateCall(self) if self.centerGridSquare is not None: self.partyEditor.partyEditorGrid.removeElement( self.centerGridSquare, self.getGridSize()) self.setOverValidSquare(False) self.lastValidPosition = None self.stash() def snapToGrid(self, newPos): gridSquare = self.getGridSquareFromPosition(newPos) # If it's None, it's not a square that is allowed to be used if gridSquare == None: self.setPosHprToDefault() self.setPos(render2d, newPos) return None else: # We know the grid square the mouse is over is good, but is it good # for all the squares that our element would take up? if not self.partyEditor.partyEditorGrid.checkGridSquareForAvailability( gridSquare, self.getGridSize()): # It's not available... sorry. self.setPos(render2d, newPos) return None self.setPosHprBasedOnGridSquare(gridSquare) return gridSquare def getGridSize(self): if self.isDecoration: return PartyGlobals.DecorationInformationDict[self.id]["gridsize"] else: return PartyGlobals.ActivityInformationDict[self.id]["gridsize"] def setPosHprToDefault(self): """Handle edge case we move the element of the edge of grid.""" self.setR(0.0) self.uprightNodePath.setR(0.0) # assert self.notify.debug("uprightNodePathR=%s" % self.uprightNodePath.getR()) def setPosHprBasedOnGridSquare(self, gridSquare): gridPos = gridSquare.getPos() # Move the position over if the element has any even dimensions if self.getGridSize()[0] % 2 == 0: gridPos.setX(gridPos[0] + PartyGlobals.PartyEditorGridSquareSize[0] / 2.0) if self.getGridSize()[1] % 2 == 0: gridPos.setZ(gridPos[2] + PartyGlobals.PartyEditorGridSquareSize[1] / 2.0) # Rotate the element so it always faces towards the center of the grid if self.id != PartyGlobals.ActivityIds.PartyFireworks: if gridPos[0] > PartyGlobals.PartyEditorGridCenter[ 0] + PartyGlobals.PartyEditorGridRotateThreshold: self.setR(90.0) self.uprightNodePath.setR(-90.0) # assert self.notify.debug("uprightNodePathR=%s" % self.uprightNodePath.getR()) elif gridPos[0] < PartyGlobals.PartyEditorGridCenter[ 0] - PartyGlobals.PartyEditorGridRotateThreshold: self.setR(270.0) self.uprightNodePath.setR(-270.0) # assert self.notify.debug("uprightNodePathR=%s" % self.uprightNodePath.getR()) elif gridPos[2] < PartyGlobals.PartyEditorGridCenter[ 1] - PartyGlobals.PartyEditorGridRotateThreshold: self.setR(180.0) self.uprightNodePath.setR(-180.0) # assert self.notify.debug("uprightNodePathR=%s" % self.uprightNodePath.getR()) else: self.setR(0.0) self.uprightNodePath.setR(0.0) # assert self.notify.debug("uprightNodePathR=%s" % self.uprightNodePath.getR()) else: self.setR(270.0) self.uprightNodePath.setR(-270.0) # assert self.notify.debug("not fireworks uprightNodePathR=%s" % self.uprightNodePath.getR()) self.setPos(render2d, gridPos) self.lastValidPosition = gridPos def getGridSquareFromPosition(self, newPos): localX = newPos[0] - PartyGlobals.PartyEditorGridBounds[0][0] localY = newPos[2] - PartyGlobals.PartyEditorGridBounds[1][1] x = int(localX / PartyGlobals.PartyEditorGridSquareSize[0]) y = int(localY / PartyGlobals.PartyEditorGridSquareSize[1]) # Reverse y value because y goes from bottom to top y = PartyGlobals.PartyEditorGridSize[1] - 1 - y return self.partyEditor.partyEditorGrid.getGridSquare(x, y) def detach(self, mouseEvent): assert PartyEditorGridElement.notify.debug("detached grid element %s" % self.name) taskMgr.remove("gridElementDragTask%s" % self.name) self.rolloverTitle.stash() if self.overValidSquare: self.partyEditor.partyEditorGrid.registerNewElement( self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.handleMutuallyExclusiveActivities() else: if self.lastValidPosition is not None: if self.mouseOverTrash: self.partyEditor.trashCanButton[ "state"] = DirectGuiGlobals.NORMAL self.lastValidPosition = None self.partyEditor.updateCostsAndBank() self.stash() else: self.setPos(render2d, self.lastValidPosition) self.setOverValidSquare(True) self.partyEditor.partyEditorGrid.registerNewElement( self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.handleMutuallyExclusiveActivities() else: self.stash() self.checkSoldOutAndPaidStatusAndAffordability() def placeInPartyGrounds(self, desiredXY=None): self.centerGridSquare = self.partyEditor.partyEditorGrid.getClearGridSquare( self.getGridSize(), desiredXY) if self.centerGridSquare is not None: self.setOverValidSquare(True) self.unstash() self.setPosHprBasedOnGridSquare(self.centerGridSquare) self.partyEditor.partyEditorGrid.registerNewElement( self, self.centerGridSquare, self.getGridSize()) self.partyEditor.updateCostsAndBank() self.partyEditor.partyPlanner.instructionLabel[ "text"] = TTLocalizer.PartyPlannerEditorInstructionsPartyGrounds self.checkSoldOutAndPaidStatusAndAffordability() #self.uprightNodePath.wrtReparentTo(aspect2dp) return True else: return False def clicked(self, mouseEvent): PartyEditorGridElement.notify.debug("clicked grid element %s" % self.name) if self.centerGridSquare is not None: self.attach(mouseEvent) self.partyEditor.partyEditorGrid.removeElement( self.centerGridSquare, self.getGridSize()) def released(self, mouseEvent): PartyEditorGridElement.notify.debug("released grid element %s" % self.name) self.detach(mouseEvent) def mouseEnter(self, mouseEvent): # make sure our text isn't obscured by other stuff in the grid parent = self.getParent() self.reparentTo(parent) self.rolloverTitle.unstash() def mouseExit(self, mouseEvent): self.rolloverTitle.stash() def destroy(self): self.unbind(DirectGuiGlobals.B1PRESS) self.unbind(DirectGuiGlobals.B1RELEASE) self.unbind(DirectGuiGlobals.ENTER) self.unbind(DirectGuiGlobals.EXIT) DirectButton.destroy(self)