예제 #1
0
class AreYouSure(Stage):
    def enter(self, data):
        self.btn_yes = DirectButton(
            text=("Yes", "Yes", "Yes", "Yes"),
            text_pos=(-0.6, -0.05),
            text_scale=0.2,
            frameSize=(-1, -0.2, -0.2, 0.2),
            borderWidth=(0.01, 0.01),
            command=self.yes,
        )
        self.btn_no = DirectButton(
            text=("No", "No", "No", "No"),
            text_pos=(0.6, -0.05),
            text_scale=0.2,
            frameSize=(0.2, 1, -0.2, 0.2),
            borderWidth=(0.01, 0.01),
            command=self.no,
        )
        self.data = data

    def exit(self, data):
        self.btn_yes.destroy()
        self.btn_no.destroy()
        return (self.data, data)

    def yes(self):
        base.flow.pop_substage(True)

    def no(self):
        base.flow.pop_substage(False)
 def destroy(self):
     if hasattr(self, 'playerCount'):
         if self.playerCount:
             self.playerCount.destroy()
             del self.playerCount
     
     DirectButton.destroy(self)
예제 #3
0
    def destroy(self):
        if hasattr(self, 'playerCount'):
            if self.leaderImage:
                self.leaderImage.destroy()
                del self.leaderImage

        DirectButton.destroy(self)
예제 #4
0
    def destroy(self):
        if hasattr(self, 'playerCount'):
            if self.playerCount:
                self.playerCount.destroy()
                del self.playerCount

        DirectButton.destroy(self)
예제 #5
0
class MainGameLoop(Stage):
    def enter(self, data):
        self.btn_menu = DirectButton(
            text=(
                "Ingame Menu",
                "Ingame Menu",
                "Ingame Menu",
                "(Ingame Menu)",
            ),
            text_pos=(0, -0.05),
            text_scale=0.2,
            frameSize=(-1, 1, -0.15, 0.15),
            borderWidth=(0.01, 0.01),
            command=self.ingame_menu,
        )

    def exit(self, data):
        self.btn_menu.destroy()
        return data

    def exit_to_substage(self, substage, data):
        for btn in [self.btn_menu]:
            btn["state"] = DGG.DISABLED
        return data

    def reenter_from_substage(self, substage, data):
        for btn in [self.btn_menu]:
            btn["state"] = DGG.NORMAL
        if data == 'main_menu':
            base.flow.transition('main_menu')
        if data == 'quit':
            base.flow.transition('quit')

    def ingame_menu(self):
        base.flow.push_substage('ingame_menu')
 def destroy(self):
     if hasattr(self, 'playerCount'):
         if self.leaderImage:
             self.leaderImage.destroy()
             del self.leaderImage
     
     DirectButton.destroy(self)
예제 #7
0
class Alert(Notifier):
    def __init__(self, reason):
        Notifier.__init__(self, "alert")
        VirtualFileSystem.getGlobalPtr().mount(Filename("mf/alert.mf"), ".",
                                               VirtualFileSystem.MFReadOnly)
        ok = loader.loadModel("alert.egg")

        if reason not in LOCAL_EN:
            reason = GENERAL

        self.reason = reason

        self.bg_frame = DirectFrame(frameColor=(0, 0, 0, 0),
                                    frameSize=(-1, 1, -1, 1),
                                    suppressMouse=1,
                                    state=DGG.NORMAL,
                                    sortOrder=1000)
        self.frame = DirectFrame(frameSize=(1, 1, 1, 1),
                                 image=ok.find('**/alert'),
                                 image_scale=(1, 0, 0.6),
                                 state=DGG.NORMAL,
                                 parent=self.bg_frame)
        self.text = OnscreenText(text=LOCAL_EN[reason],
                                 fg=(1, 1, 1, 1),
                                 pos=(0, 0.15, 0),
                                 align=TextNode.ACenter,
                                 wordwrap=13,
                                 parent=self.frame)
        self.button = DirectButton(geom=(ok.find('**/ok-ready'),
                                         ok.find('**/ok-click'),
                                         ok.find('**/ok-hover'),
                                         ok.find('**/ok-click')),
                                   relief=None,
                                   geom_scale=(0.3, 0, 0.15),
                                   geom_pos=(0, 0, -0.175),
                                   pressEffect=0,
                                   command=self.destroy,
                                   parent=self.frame)

        self.notify.debug(
            f"[__init__] Created Alert with reason {self.reason}")

        loader.unloadModel(ok)

    def __repr__(self):
        return str(self.reason)

    def destroy(self):
        VirtualFileSystem.getGlobalPtr().unmount("mf/alert.mf")
        VirtualFileSystem.getGlobalPtr().unmount("mf/ok_small.mf")
        self.bg_frame.destroy()
        self.frame.destroy()
        self.button.destroy()
        self.text.cleanup()
        self.text.destroy()
        del self.frame
        del self.button
        del self.text
        del self
class ModPanelButton:
    def __init__(self, menu, name, command, register):
        self.menu = menu
        self.name = name
        
        self.command = command
        if type(command) == types.StringType:
            command = self.call_word

        self.button = DirectButton(frameSize=None, text=name, 
            image=(ModPanelGlobals.Button.find('**/QuitBtn_UP'),
            ModPanelGlobals.Button.find('**/QuitBtn_DN'),
            ModPanelGlobals.Button.find('**/QuitBtn_RLVR')),
            relief=None, command=command, text_pos=(0, -0.015),
            geom=None, pad=(0.01, 0.01), suppressKeys=0, pos=(0, 0, 0), 
            text_scale=0.059, borderWidth=(0.015, 0.01), scale=.7
        )
        
        self.button.reparent_to(menu)
        
        if register:
            self.button.bind(DirectGuiGlobals.B2PRESS, self.delete_button)
            self.button.bind(DirectGuiGlobals.B3PRESS, self.button.editStart)
            self.button.bind(DirectGuiGlobals.B3RELEASE, self.edit_stop)
            self.menu.buttons.append(self)
            messenger.send('save-file')
        
    def call_word(self):
        messenger.send('magicWord', [self.command])
        
    def hide(self):
        self.button.hide()
        
    def show(self):
        self.button.show()
        
    def place(self):
        self.button.place()
        
    def set_pos(self, x, y, z):
        self.button.set_pos(x, y, z)
        
    def destroy(self):
        self.button.destroy()
        
    def edit_stop(self, dispatch):
        self.button.editStop(dispatch)
        
        messenger.send('save-file')

    def delete_button(self, dispatch):
        self.button.destroy()
        if self in self.menu.buttons:
            self.menu.buttons.remove(self)
            
        messenger.send('save-file')
        
    def get_data(self):
        return (self.name, self.command, self.button.get_pos())
    def destroy(self):
        self.unbind(DirectGuiGlobals.B1PRESS)
        self.unbind(DirectGuiGlobals.B1RELEASE)
        for partyEditorGridElement in self.partyEditorGridElements:
            partyEditorGridElement.destroy()

        del self.partyEditorGridElements
        self.partyEditor = None
        DirectButton.destroy(self)
예제 #10
0
    def destroy(self):
        self.unbind(DirectGuiGlobals.B1PRESS)
        self.unbind(DirectGuiGlobals.B1RELEASE)
        for partyEditorGridElement in self.partyEditorGridElements:
            partyEditorGridElement.destroy()

        del self.partyEditorGridElements
        self.partyEditor = None
        DirectButton.destroy(self)
예제 #11
0
 def destroy(self):
     self.unbind(DirectGuiGlobals.B1PRESS)
     self.unbind(DirectGuiGlobals.B1RELEASE)
     for partyEditorGridElement in self.partyEditorGridElements:
         partyEditorGridElement.destroy()
     del self.partyEditorGridElements
     # break the cycle to clean up properly
     self.partyEditor = None
     DirectButton.destroy(self)
class DMenuDisclaimer(DirectObject):
    notify = directNotify.newCategory('DisclaimerScreen')

    def __init__(self):
        DirectObject.__init__(self)
        base.setBackgroundColor(0, 0, 0)
        disclaimerText = "Project Altis is a not-for-profit fanmade parody made under Fair Use. Project Altis is not affiliated with The Walt Disney Company and/or the Disney Interactive Media Group (collectively referred to as \"Disney\") by clicking I agree you hereby agree that you acknowledge this fact."
        self.disclaimer = OnscreenText(text=disclaimerText,
                                       font=ToontownGlobals.getMinnieFont(),
                                       style=3,
                                       wordwrap=30,
                                       scale=.08,
                                       pos=(0, .3, 0))
        gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_mainGui.bam')
        yesUp = gui.find('**/tt_t_gui_mat_okUp')
        yesDown = gui.find('**/tt_t_gui_mat_okDown')
        noUp = gui.find('**/tt_t_gui_mat_closeUp')
        noDown = gui.find('**/tt_t_gui_mat_closeDown')

        self.accept = DirectButton(parent=aspect2d,
                                   relief=None,
                                   image=(yesUp, yesDown, yesUp),
                                   image_scale=(0.6, 0.6, 0.6),
                                   image1_scale=(0.7, 0.7, 0.7),
                                   image2_scale=(0.7, 0.7, 0.7),
                                   text=('', 'I Agree', 'I Agree'),
                                   text_pos=(0, -0.175),
                                   text_style=3,
                                   text_scale=0.08,
                                   pos=(.4, 0, -.5),
                                   command=self.accept)

        self.deny = DirectButton(parent=aspect2d,
                                 relief=None,
                                 image=(noUp, noDown, noUp),
                                 image_scale=(0.6, 0.6, 0.6),
                                 image1_scale=(0.7, 0.7, 0.7),
                                 image2_scale=(0.7, 0.7, 0.7),
                                 text=('', 'I Disagree', 'I Disagree'),
                                 text_pos=(0, -0.175),
                                 text_style=3,
                                 text_scale=0.08,
                                 pos=(-.4, 0, -.5),
                                 command=self.deny)

    def accept(self):
        self.disclaimer['text'] = 'Loading...'
        self.accept.destroy()
        self.deny.destroy()
        base.graphicsEngine.renderFrame()
        messenger.send("AgreeToGame")
        base.cr.hasAccepted = True
        self.disclaimer.removeNode()

    def deny(self):
        base.exitFunc()
예제 #13
0
 def destroy(self):
     if self.fadeSequence is not None:
         self.fadeSequence.clearToInitial()
     self['extraArgs'] = None
     taskMgr.remove('RepairLeak_%s.update' % self.name)
     if self.onCleanup is not None:
         self.onCleanup(self)
     self.cleanup()
     self.waterStream.removeNode()
     self.waterStream2.removeNode()
     DirectButton.destroy(self)
     return
    def destroy(self):
        if self.fadeSequence is not None:
            self.fadeSequence.clearToInitial()

        self['extraArgs'] = None
        taskMgr.remove('RepairLeak_%s.update' % self.name)
        if self.onCleanup is not None:
            self.onCleanup(self)

        self.cleanup()
        self.waterStream.removeNode()
        self.waterStream2.removeNode()
        DirectButton.destroy(self)
class CannonGui(DirectObject):
    notify = directNotify.newCategory('CannonGui')
    FIRE_KEY = base.JUMP
    UP_KEY = base.MOVE_UP
    DOWN_KEY = base.MOVE_DOWN
    LEFT_KEY = base.MOVE_LEFT
    RIGHT_KEY = base.MOVE_RIGHT
    FIRE_PRESSED = 'cannongui_fire_pressed'

    def __init__(self):
        self.__loaded = False
        self.leftPressed = 0
        self.rightPressed = 0
        self.upPressed = 0
        self.downPressed = 0
        self.__aimPad = None
        self.__timerPad = None
        return

    def load(self):
        if self.__loaded:
            return
        self.__timerPad = PartyUtils.getNewToontownTimer()
        guiModel = 'phase_4/models/gui/cannon_game_gui'
        guiNode = loader.loadModel(guiModel)
        self.__aimPad = DirectFrame(image=guiNode.find('**/CannonFire_PAD'), relief=None, pos=(0.7, 0, -0.553333), scale=0.8)
        guiNode.removeNode()
        self.fireButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Fire_Btn_UP'), (guiModel, '**/Fire_Btn_DN'), (guiModel, '**/Fire_Btn_RLVR')), relief=None, pos=(0.0115741, 0, 0.00505051), scale=1.0, command=self.__firePressed)
        self.upButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0115741, 0, 0.221717))
        self.downButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0136112, 0, -0.210101), image_hpr=(0, 0, 180))
        self.leftButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(-0.199352, 0, -0.000505269), image_hpr=(0, 0, -90))
        self.rightButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.219167, 0, -0.00101024), image_hpr=(0, 0, 90))
        self.__aimPad.setColor(1, 1, 1, 0.9)

        def bindButton(button, upHandler, downHandler):
            button.bind(DGG.B1PRESS, lambda x, handler = upHandler: handler())
            button.bind(DGG.B1RELEASE, lambda x, handler = downHandler: handler())

        bindButton(self.upButton, self.__upPressed, self.__upReleased)
        bindButton(self.downButton, self.__downPressed, self.__downReleased)
        bindButton(self.leftButton, self.__leftPressed, self.__leftReleased)
        bindButton(self.rightButton, self.__rightPressed, self.__rightReleased)
        self.__loaded = True
        return

    def unload(self):
        self.ignoreAll()
        if not self.__loaded:
            return
        self.disable()
        self.upButton.unbind(DGG.B1PRESS)
        self.upButton.unbind(DGG.B1RELEASE)
        self.downButton.unbind(DGG.B1PRESS)
        self.downButton.unbind(DGG.B1RELEASE)
        self.leftButton.unbind(DGG.B1PRESS)
        self.leftButton.unbind(DGG.B1RELEASE)
        self.rightButton.unbind(DGG.B1PRESS)
        self.rightButton.unbind(DGG.B1RELEASE)
        self.fireButton.destroy()
        self.__aimPad.destroy()
        del self.__aimPad
        del self.fireButton
        del self.upButton
        del self.downButton
        del self.leftButton
        del self.rightButton
        self.__timerPad.destroy()
        del self.__timerPad
        self.__loaded = False

    def enable(self, timer = 0):
        self.__aimPad.show()
        base.setCellsAvailable([base.bottomCells[3], base.bottomCells[4]], 0)
        base.setCellsAvailable([base.rightCells[1]], 0)
        if timer > 0:
            self.__timerPad.setTime(timer)
            self.__timerPad.countdown(timer)
            self.__timerPad.show()
        self.enableKeys()

    def disable(self):
        self.__aimPad.hide()
        base.setCellsAvailable([base.bottomCells[3], base.bottomCells[4]], 1)
        base.setCellsAvailable([base.rightCells[1]], 1)
        self.__timerPad.hide()
        self.disableKeys()

    def enableKeys(self):
        self.enableAimKeys()
        self.enableFireKey()

    def disableKeys(self):
        self.__aimPad.hide()
        self.disableAimKeys()
        self.disableFireKey()

    def enableAimKeys(self):
        self.leftPressed = 0
        self.rightPressed = 0
        self.upPressed = 0
        self.downPressed = 0
        self.accept(self.UP_KEY, self.__upKeyPressed)
        self.accept(self.DOWN_KEY, self.__downKeyPressed)
        self.accept(self.LEFT_KEY, self.__leftKeyPressed)
        self.accept(self.RIGHT_KEY, self.__rightKeyPressed)

    def disableAimKeys(self):
        self.ignore(self.UP_KEY)
        self.ignore(self.DOWN_KEY)
        self.ignore(self.LEFT_KEY)
        self.ignore(self.RIGHT_KEY)
        messenger.send(self.UP_KEY + '-up')
        messenger.send(self.DOWN_KEY + '-up')
        messenger.send(self.LEFT_KEY + '-up')
        messenger.send(self.RIGHT_KEY + '-up')
        self.ignore(self.UP_KEY + '-up')
        self.ignore(self.DOWN_KEY + '-up')
        self.ignore(self.LEFT_KEY + '-up')
        self.ignore(self.RIGHT_KEY + '-up')

    def enableFireKey(self):
        self.accept(self.FIRE_KEY, self.__fireKeyPressed)

    def disableFireKey(self):
        self.ignore(self.FIRE_KEY)
        self.ignore(self.FIRE_KEY + '-up')

    def __fireKeyPressed(self):
        self.ignore(self.FIRE_KEY)
        self.accept(self.FIRE_KEY + '-up', self.__fireKeyReleased)
        self.__firePressed()

    def __upKeyPressed(self):
        self.ignore(self.UP_KEY)
        self.accept(self.UP_KEY + '-up', self.__upKeyReleased)
        self.__upPressed()

    def __downKeyPressed(self):
        self.ignore(self.DOWN_KEY)
        self.accept(self.DOWN_KEY + '-up', self.__downKeyReleased)
        self.__downPressed()

    def __leftKeyPressed(self):
        self.ignore(self.LEFT_KEY)
        self.accept(self.LEFT_KEY + '-up', self.__leftKeyReleased)
        self.__leftPressed()

    def __rightKeyPressed(self):
        self.ignore(self.RIGHT_KEY)
        self.accept(self.RIGHT_KEY + '-up', self.__rightKeyReleased)
        self.__rightPressed()

    def __fireKeyReleased(self):
        self.ignore(self.FIRE_KEY + '-up')
        self.accept(self.FIRE_KEY, self.__fireKeyPressed)

    def __leftKeyReleased(self):
        self.ignore(self.LEFT_KEY + '-up')
        self.accept(self.LEFT_KEY, self.__leftKeyPressed)
        self.__leftReleased()

    def __rightKeyReleased(self):
        self.ignore(self.RIGHT_KEY + '-up')
        self.accept(self.RIGHT_KEY, self.__rightKeyPressed)
        self.__rightReleased()

    def __upKeyReleased(self):
        self.ignore(self.UP_KEY + '-up')
        self.accept(self.UP_KEY, self.__upKeyPressed)
        self.__upReleased()

    def __downKeyReleased(self):
        self.ignore(self.DOWN_KEY + '-up')
        self.accept(self.DOWN_KEY, self.__downKeyPressed)
        self.__downReleased()

    def __upPressed(self):
        self.notify.debug('up pressed')
        self.upPressed = self.__enterControlActive(self.upPressed)

    def __downPressed(self):
        self.notify.debug('down pressed')
        self.downPressed = self.__enterControlActive(self.downPressed)

    def __leftPressed(self):
        self.notify.debug('left pressed')
        self.leftPressed = self.__enterControlActive(self.leftPressed)

    def __rightPressed(self):
        self.notify.debug('right pressed')
        self.rightPressed = self.__enterControlActive(self.rightPressed)

    def __upReleased(self):
        self.notify.debug('up released')
        self.upPressed = self.__exitControlActive(self.upPressed)

    def __downReleased(self):
        self.notify.debug('down released')
        self.downPressed = self.__exitControlActive(self.downPressed)

    def __leftReleased(self):
        self.notify.debug('left released')
        self.leftPressed = self.__exitControlActive(self.leftPressed)

    def __rightReleased(self):
        self.notify.debug('right released')
        self.rightPressed = self.__exitControlActive(self.rightPressed)

    def __firePressed(self):
        self.notify.debug('fire pressed')
        messenger.send(CannonGui.FIRE_PRESSED)

    def __enterControlActive(self, control):
        return control + 1

    def __exitControlActive(self, control):
        return max(0, control - 1)
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))
예제 #17
0
class GroupTrackerPlayer(DirectButton):
    def __init__(self, parent, avId, name, isLeader, **kw):
        self.avId = avId
        self.name = name
        self.isLeader = isLeader
        self.leaderImage = None

        if parent is None:
            parent = aspect2d

        text = self.getName()

        optiondefs = (('text', text, None), ('text_fg', (0.0, 0.0, 0.0, 1.0),
                                             None), ('text_align',
                                                     TextNode.ALeft, None),
                      ('text_pos', (-0.2, 0.0, 0.0), None),
                      ('relief', None, None), ('text_scale', 0.05, None),
                      ('command', self.loadPlayerDetails, None))

        self.defineoptions(kw, optiondefs)
        DirectButton.__init__(self, parent)
        self.initialiseoptions(GroupTrackerPlayer)

        boardingGroupIcons = loader.loadModel(
            'phase_9/models/gui/tt_m_gui_brd_status')
        self.leaderButtonImage = boardingGroupIcons.find(
            '**/tt_t_gui_brd_statusLeader')
        self.leaderImage = DirectButton(parent=self,
                                        relief=None,
                                        state=DGG.DISABLED,
                                        image=(self.leaderButtonImage),
                                        image_scale=(0.06, 1.0, 0.06),
                                        pos=(-0.26, 0, 0.02),
                                        command=None)

        self.setLeaderStatus(self.isLeader)
        boardingGroupIcons.removeNode()

    def destroy(self):
        if hasattr(self, 'playerCount'):
            if self.leaderImage:
                self.leaderImage.destroy()
                del self.leaderImage

        DirectButton.destroy(self)

    def setLeaderStatus(self, isLeader):
        self.isLeader = isLeader

        if self.isLeader:
            self.leaderImage.show()
        if not self.isLeader:
            self.leaderImage.hide()

    def getLeader(self):
        return self.isLeader

    def getName(self):
        # Lets cap a length so we dont have too long of names
        name = self.name
        if len(name) > 15:
            name = name[:16] + '...'  # Chop the first x characters
        return name

    def getId(self):
        return self.avId

    def loadPlayerDetails(self):
        # TODO: Load player details based off avId for localAvatar
        pass
예제 #18
0
class GroupTrackerPage(ShtikerPage.ShtikerPage):
    notify = directNotify.newCategory('GroupTrackerPage')

    def __init__(self):
        ShtikerPage.ShtikerPage.__init__(self)
        self.groupWidgets = []
        self.playerWidgets = []
        self.images = []  # image nodes: Possible images to apply on groups
        self.scrollList = None  # DirectScrolledList: Holds the GroupTrackerGroup widgets
        self.scrollTitle = None  # DirectLabel: Title of the list that holds the groups
        self.playerList = None  # DirectScrolledList: Holds players when showing a specific group details
        self.playerListTitle = None  # DirectLabel: Title of the playerList
        self.groupInfoTitle = None  # DirectLabel: holds the group detail title to show on the right
        self.groupInfoDistrict = None  # DirectLabel: shows group detail district on the right
        self.statusMessage = None  # DirectLabel: Shows important messages like Loading... or "No boarding groups available"
        self.groupIcon = None  # DirectButton: Icon to associate with the group ex. sellbot icon or cashbot icon depending on group info
        self.wantGroupToggle = None  # DirectButton: Allows the toon to toggle his listing

    def load(self):
        self.listXorigin = -0.02
        self.listFrameSizeX = 0.67
        self.listZorigin = -0.96
        self.listFrameSizeZ = 1.04
        self.arrowButtonScale = 1.3
        self.itemFrameXorigin = -0.237
        self.itemFrameZorigin = 0.365
        self.buttonXstart = self.itemFrameXorigin + 0.293
        self.gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui')
        guiButton = loader.loadModel('phase_3/models/gui/quit_button')
        self.scrollList = DirectScrolledList(
            parent=self,
            relief=None,
            pos=(-0.5, 0, 0),
            incButton_image=(self.gui.find('**/FndsLst_ScrollUp'),
                             self.gui.find('**/FndsLst_ScrollDN'),
                             self.gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             self.gui.find('**/FndsLst_ScrollUp')),
            incButton_relief=None,
            incButton_scale=(self.arrowButtonScale, self.arrowButtonScale,
                             -self.arrowButtonScale),
            incButton_pos=(self.buttonXstart, 0,
                           self.itemFrameZorigin - 0.999),
            incButton_image3_color=Vec4(1, 1, 1, 0.2),
            decButton_image=(self.gui.find('**/FndsLst_ScrollUp'),
                             self.gui.find('**/FndsLst_ScrollDN'),
                             self.gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             self.gui.find('**/FndsLst_ScrollUp')),
            decButton_relief=None,
            decButton_scale=(self.arrowButtonScale, self.arrowButtonScale,
                             self.arrowButtonScale),
            decButton_pos=(self.buttonXstart, 0,
                           self.itemFrameZorigin + 0.227),
            decButton_image3_color=Vec4(1, 1, 1, 0.2),
            itemFrame_pos=(self.itemFrameXorigin, 0, self.itemFrameZorigin),
            itemFrame_scale=1.0,
            itemFrame_relief=DGG.SUNKEN,
            itemFrame_frameSize=(self.listXorigin,
                                 self.listXorigin + self.listFrameSizeX,
                                 self.listZorigin,
                                 self.listZorigin + self.listFrameSizeZ),
            itemFrame_frameColor=(0.85, 0.95, 1, 1),
            itemFrame_borderWidth=(0.01, 0.01),
            numItemsVisible=15,
            forceHeight=0.065,
            items=self.groupWidgets)

        self.scrollTitle = DirectFrame(parent=self.scrollList,
                                       text=TTLocalizer.GroupTrackerListTitle,
                                       text_scale=0.06,
                                       text_align=TextNode.ACenter,
                                       relief=None,
                                       pos=(self.buttonXstart, 0,
                                            self.itemFrameZorigin + 0.127))

        self.playerList = DirectScrolledList(
            parent=self,
            relief=None,
            pos=(0.45, 0, 0.1),
            incButton_image=(self.gui.find('**/FndsLst_ScrollUp'),
                             self.gui.find('**/FndsLst_ScrollDN'),
                             self.gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             self.gui.find('**/FndsLst_ScrollUp')),
            incButton_relief=None,
            incButton_scale=(1.0, 1.0, -1.0),
            incButton_pos=(0, 0, -0.28),
            incButton_image3_color=Vec4(1, 1, 1, 0.05),
            decButton_image=(self.gui.find('**/FndsLst_ScrollUp'),
                             self.gui.find('**/FndsLst_ScrollDN'),
                             self.gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             self.gui.find('**/FndsLst_ScrollUp')),
            decButton_relief=None,
            decButton_scale=(1.0, 1.0, 1.0),
            decButton_pos=(0.0, 0, 0.04),
            decButton_image3_color=Vec4(1, 1, 1, 0.25),
            itemFrame_pos=(0, 0, -0.05),
            itemFrame_scale=1.0,
            itemFrame_relief=DGG.SUNKEN,
            itemFrame_frameSize=(
                -0.3,
                0.3,  #x
                -0.2,
                0.06),  #z
            itemFrame_frameColor=(0.85, 0.95, 1, 1),
            itemFrame_borderWidth=(0.01, 0.01),
            numItemsVisible=4,
            forceHeight=0.05,
            items=self.playerWidgets)

        self.playerListTitle = DirectFrame(parent=self.playerList,
                                           text='',
                                           text_scale=0.05,
                                           text_align=TextNode.ACenter,
                                           relief=None,
                                           pos=(0, 0, 0.08))
        self.groupInfoTitle = DirectLabel(parent=self,
                                          text='',
                                          text_scale=0.080,
                                          text_align=TextNode.ACenter,
                                          text_wordwrap=15,
                                          relief=None,
                                          pos=(0.45, 0, 0.5))
        self.groupInfoDistrict = DirectLabel(parent=self,
                                             text='',
                                             text_scale=0.050,
                                             text_align=TextNode.ACenter,
                                             text_wordwrap=15,
                                             relief=None,
                                             pos=(0.45, 0, 0.4))

        self.statusMessage = DirectLabel(parent=self,
                                         text='',
                                         text_scale=0.060,
                                         text_align=TextNode.ACenter,
                                         text_wordwrap=5,
                                         relief=None,
                                         pos=(0.45, 0, 0.1))

        # Group Image:
        self.groupIcon = DirectButton(parent=self,
                                      relief=None,
                                      state=DGG.DISABLED,
                                      image=None,
                                      image_scale=(0.35, 1, 0.35),
                                      image_color=Vec4(1.0, 1.0, 1.0, 0.75),
                                      pos=(0.45, 10, -0.45),
                                      command=self.doNothing)

        # Group Toggle:
        self.wantGroupToggle = DirectButton(
            parent=self,
            relief=None,
            image=(guiButton.find('**/QuitBtn_UP'),
                   guiButton.find('**/QuitBtn_DN'),
                   guiButton.find('**/QuitBtn_RLVR')),
            image_scale=(0.7, 1, 1),
            text='',
            text_scale=0.052,
            text_pos=(0, -0.02),
            pos=(0.2, 0, -0.65),
            command=self.toggleWantGroup)
        self.updateWantGroupButton()

        # Loading possible group icons
        suitIcons = loader.loadModel('phase_3/models/gui/cog_icons')
        bossbotIcon = suitIcons.find('**/CorpIcon')
        bossbotIcon.setColor(SUIT_ICON_COLORS[0])
        self.images.append(bossbotIcon)

        lawbotIcon = suitIcons.find('**/LegalIcon')
        lawbotIcon.setColor(SUIT_ICON_COLORS[1])
        self.images.append(lawbotIcon)

        cashbotIcon = suitIcons.find('**/MoneyIcon')
        cashbotIcon.setColor(SUIT_ICON_COLORS[2])
        self.images.append(cashbotIcon)

        sellbotIcon = suitIcons.find('**/SalesIcon')
        sellbotIcon.setColor(SUIT_ICON_COLORS[3])
        self.images.append(sellbotIcon)

        # Clean up
        self.clearGroupInfo()
        self.statusMessage.hide()

        suitIcons.removeNode()
        self.gui.removeNode()
        guiButton.removeNode()

        self.accept('GroupTrackerResponse', self.updatePage)

    def unload(self):
        self.scrollList.destroy()
        self.groupInfoDistrict.destroy()
        self.playerList.destroy()
        self.groupInfoTitle.destroy()
        self.groupIcon.destroy()
        self.wantGroupToggle.destroy()
        for widget in self.playerWidgets:
            widget.destroy()
        for widget in self.groupWidgets:
            widget.destroy()
        self.playerWidgets = []

        del self.scrollList
        del self.groupInfoDistrict
        del self.playerList
        del self.groupInfoTitle
        del self.groupIcon
        del self.wantGroupToggle
        ShtikerPage.ShtikerPage.unload(self)

    def enter(self):
        ShtikerPage.ShtikerPage.enter(self)
        self.setGroups([])  # CLEAR IT ALL
        self.setPlayers()  # CLEAR IT ALL
        if (self.scrollList['items'] == []):
            self.statusMessage['text'] = TTLocalizer.GroupTrackerLoading
            self.statusMessage.show()
        base.cr.globalGroupTracker.requestGroups()
        taskMgr.doMethodLater(3, self.displayNoGroupsTaskHandler,
                              self.uniqueName('timeout'))

    def displayNoGroups(self):
        self.statusMessage['text'] = TTLocalizer.GroupTrackerEmpty
        self.statusMessage.show()
        self.clearGroupInfo()

    def displayNoGroupsTaskHandler(self, task):
        self.displayNoGroups()
        return task.done

    def updatePage(self):
        taskMgr.remove(self.uniqueName('timeout'))
        groups = base.cr.globalGroupTracker.getGroupInfo()
        self.setGroups(groups)

    def exit(self):
        self.clearGroupInfo()
        ShtikerPage.ShtikerPage.exit(self)
        base.cr.globalGroupTracker.doneRequesting()

    def updateGroupInfoEventHandle(self, groupWidget, mouseEvent):
        self.updateGroupInfo(groupWidget)

    def updateGroupInfo(self, groupWidget):
        ''' Updates the Right Page of the Group Tracker Page with new Info '''
        self.statusMessage.hide()

        # Update the Player List
        self.setPlayers(groupWidget)
        self.playerList.show()

        # Update the Player List Title
        self.playerListTitle['text'] = ('Players ' +
                                        str(groupWidget.getCurrentPlayers()) +
                                        '/' +
                                        str(groupWidget.getMaxPlayers()) + ':')
        self.playerListTitle.show()

        # Update the District
        self.groupInfoDistrict[
            'text'] = TTLocalizer.BoardingGroupDistrictInformation % {
                'district': groupWidget.getDistrict()
            }
        self.groupInfoDistrict.show()

        # Update the Title
        self.groupInfoTitle['text'] = groupWidget.getTitle()
        self.groupInfoTitle.show()

        # Update the Image
        self.groupIcon['image'] = self.images[
            GroupTrackerGlobals.CATEGORY_TO_IMAGE_ID[
                groupWidget.getCategory()]]
        self.groupIcon['image_scale'] = (0.35, 1, 0.35)
        self.groupIcon.show()

    def clearGroupInfo(self):
        self.playerList.hide()
        self.playerListTitle.hide()
        self.groupInfoDistrict.hide()
        self.groupInfoTitle.hide()
        self.groupIcon.hide()

    def setPlayers(self, groupWidget=None):
        ''' Calls updatePlayerList '''

        # Clear the Widgets that were held in the listings
        for playerWidget in self.playerWidgets:
            playerWidget.destroy()
        self.playerWidgets = []

        # Make a player widget for each player
        # TODO: Edit this stuff when avIds come from players
        if groupWidget:
            leaderId = groupWidget.getLeaderId()
            playerNames = groupWidget.getMemberNames()
            playerIds = groupWidget.getMemberIds()
            for playerName in playerNames:
                playerId = playerIds[playerNames.index(playerName)]
                isLeader = playerId == leaderId
                self.playerWidgets.append(
                    GroupTrackerPlayer(parent=self,
                                       avId=playerId,
                                       name=playerName,
                                       isLeader=isLeader))

        self.updatePlayerList()

    def reconsiderGroupInfo(self, groupWidget):
        ''' If someone is viewing this info and it was updated, we also want to update the info being viewed '''
        if self.playerWidgets is None or self.playerList['items'] == []:
            return  # No Info is being viewed at the moment since you cant have an empty group

        # We have to update if this group's leader is the leader in the playerlist being viewed right now
        leaderId = groupWidget.getLeaderId()

        # Check all the players in the playerList being viewed for the same leader
        for playerWidget in self.playerWidgets:
            if playerWidget.getLeader():
                if leaderId == playerWidget.getId():
                    self.updateGroupInfo(groupWidget)
                    return False

        return True

    def setGroups(self, groups):
        ''' Calls updateGroupList '''

        # Clear our Group Widgets
        for group in self.groupWidgets:
            group.destroy()
        self.groupWidgets = []

        wantReconsiderInfo = True

        # Create a new group widget for each group
        for group in groups:
            if not group[GroupTrackerGlobals.SHOW] or len(
                    group[GroupTrackerGlobals.MEMBER_IDS]) == 0:
                continue  # We are using this to see if this group is dead or if someone doesnt want it up
            leaderId = 0
            for i, g in base.cr.globalGroupTracker.leader2Group.items():
                if g == group:
                    leaderId = i
            if not leaderId:
                continue

            leaderName = group[GroupTrackerGlobals.LEADER_NAME]
            shardName = group[GroupTrackerGlobals.SHARD_NAME]
            category = group[GroupTrackerGlobals.CATEGORY]
            memberIds = group[GroupTrackerGlobals.MEMBER_IDS]
            memberNames = group[GroupTrackerGlobals.MEMBER_NAMES]

            groupWidget = GroupTrackerGroup(parent=self,
                                            leaderId=leaderId,
                                            leaderName=leaderName,
                                            shardName=shardName,
                                            category=category,
                                            memberIds=memberIds,
                                            memberNames=memberNames)
            groupWidget.bind(DGG.WITHIN,
                             self.updateGroupInfoEventHandle,
                             extraArgs=[groupWidget])
            self.groupWidgets.append(groupWidget)
            if wantReconsiderInfo:
                wantReconsiderInfo = self.reconsiderGroupInfo(groupWidget)

        # Edge case where a group that was removed, info might remain on the screen if it didn't exist any more
        if wantReconsiderInfo:
            self.clearGroupInfo()

        # There are no groups, hide the information
        if len(self.groupWidgets) == 0:
            self.displayNoGroups()
        self.updateGroupList()

    def updateGroupList(self):
        self.statusMessage.hide()
        if self.scrollList is None:
            return

        # Clear the Group Listing
        for item in self.scrollList['items']:
            if item:
                self.scrollList.removeItem(item, refresh=True)
        self.scrollList['items'] = []

        # Re-populate the Group Listing
        for groupWidget in self.groupWidgets:
            self.scrollList.addItem(groupWidget, refresh=True)

        if len(self.groupWidgets) == 0:
            self.displayNoGroups()

    def updatePlayerList(self):
        if self.playerList is None:
            return

        # Clear the Player Listing
        for item in self.playerList['items']:
            if item:
                self.playerList.removeItem(item)
        self.playerList['items'] = []

        # Re-Populate the List
        for playerWidget in self.playerWidgets:
            self.playerList.addItem(playerWidget)

    def toggleWantGroup(self):
        if settings.get('grouptracker', False):
            settings['grouptracker'] = False
            base.cr.globalGroupTracker.showMe(False)
        else:
            settings['grouptracker'] = True
            base.cr.globalGroupTracker.showMe(True)

        base.localAvatar.wantGroupTracker()

        base.localAvatar.wantGroupTracker(
        )  # Updates the ai toon so the boarding group AI could know what he wants
        self.updateWantGroupButton()

    def updateWantGroupButton(self):
        if settings.get('grouptracker', False):
            self.wantGroupToggle['text'] = 'Hide Me'
        else:
            self.wantGroupToggle['text'] = 'Show Me'

    def doNothing(self):
        pass
예제 #19
0
class CalendarGuiMonth(DirectFrame):
    notify = directNotify.newCategory("CalendarGuiMonth")

    def __init__(
        self,
        parent,
        startingDateTime,
        scale=1.0,
        pos=(0, 0, -0.1),
        dayClickCallback=None,
        onlyFutureDaysClickable=False,
        onlyFutureMonthsClickable=False,
    ):
        self.startDate = startingDateTime
        self.curDate = startingDateTime
        self.dayClickCallback = dayClickCallback
        self.onlyFutureDaysClickable = onlyFutureDaysClickable
        self.onlyFutureMonthsClickable = onlyFutureMonthsClickable
        if self.onlyFutureDaysClickable:
            self.onlyFutureMonthsClickable = True
        DirectFrame.__init__(self, parent=parent, scale=scale, pos=pos)
        self.load()
        self.createGuiObjects()
        self.lastSelectedDate = None
        self.accept("clickedOnDay", self.clickedOnDay)

    def load(self):
        monthAsset = loader.loadModel("phase_4/models/parties/tt_m_gui_sbk_calendar")
        monthAsset.reparentTo(self)
        self.monthLocator = self.find("**/locator_month/locator_month")
        self.weekDayLocators = []
        for weekday in ("sun", "mon", "tue", "wed", "thu", "fri", "sat"):
            weekDayLoc = self.find("**/loc_%s" % weekday)
            self.weekDayLocators.append(weekDayLoc)

        self.dayLocators = []
        for row in xrange(6):
            oneWeek = []
            for col in xrange(7):
                newDayLoc = self.find("**/loc_box_%s_%s" % (row, col))
                oneWeek.append(newDayLoc)

            self.dayLocators.append(oneWeek)

        self.monthLeftLocator = self.find("**/locator_month_arrowL")
        self.monthRightLocator = self.find("**/locator_month_arrowR")
        self.filterLocator = self.find("**/locator_filter")
        self.filterLocatorArrowUp = self.find("**/locator_filter_arrowTop")
        self.filterLocatorArrowDown = self.find("**/locator_filter_arrowBottom")
        self.yearLocator = self.attachNewNode("yearLocator")
        self.yearLocator.setPos(self.monthLocator, 0, 0, -0.03)

    def createGuiObjects(self):
        self.monthLabel = DirectLabel(
            parent=self.monthLocator,
            relief=None,
            text=TTLocalizer.Months[self.startDate.month],
            text_scale=0.075,
            text_font=ToontownGlobals.getMinnieFont(),
            text_fg=(40 / 255.0, 140 / 255.0, 246 / 255.0, 1.0),
        )
        self.yearLabel = DirectLabel(
            parent=self.yearLocator,
            relief=None,
            text=str(self.startDate.year),
            text_scale=0.03,
            text_font=ToontownGlobals.getMinnieFont(),
            text_fg=(140 / 255.0, 140 / 255.0, 246 / 255.0, 1.0),
        )
        self.weekdayLabels = []
        for posIndex in xrange(7):
            adjustedNameIndex = (posIndex - 1) % 7
            self.weekdayLabels.append(
                DirectLabel(
                    parent=self.weekDayLocators[posIndex],
                    relief=None,
                    text=TTLocalizer.DayNamesAbbrev[adjustedNameIndex],
                    text_font=ToontownGlobals.getInterfaceFont(),
                    text_fg=(255 / 255.0, 146 / 255.0, 113 / 255.0, 1.0),
                    text_scale=0.05,
                )
            )

        self.createGuiDays()
        arrowUp = self.find("**/month_arrowR_up")
        arrowDown = self.find("**/month_arrowR_down")
        arrowHover = self.find("**/month_arrowR_hover")
        self.monthLeftArrow = DirectButton(
            parent=self.monthLeftLocator,
            relief=None,
            image=(arrowUp, arrowDown, arrowHover, arrowUp),
            image3_color=(1, 1, 1, 0.5),
            scale=(-1.0, 1.0, 1.0),
            command=self.__doMonthLeft,
        )
        if self.onlyFutureMonthsClickable:
            self.monthLeftArrow.hide()
        self.monthRightArrow = DirectButton(
            parent=self.monthRightLocator,
            relief=None,
            image=(arrowUp, arrowDown, arrowHover, arrowUp),
            image3_color=(1, 1, 1, 0.5),
            command=self.__doMonthRight,
        )

        def makeLabel(itemName, itemNum, *extraArgs):
            return DirectLabel(text=itemName, frameColor=(0, 0, 0, 0), text_scale=0.04)

        gui = loader.loadModel("phase_4/models/parties/tt_m_gui_sbk_calendar_box")
        arrowUp = gui.find("**/downScroll_up")
        arrowDown = gui.find("**/downScroll_down")
        arrowHover = gui.find("**/downScroll_hover")
        filterLocatorUpPos = self.filterLocatorArrowUp.getPos(self.filterLocator)
        filterLocatorDownPos = self.filterLocatorArrowDown.getPos(self.filterLocator)
        self.filterList = DirectScrolledList(
            parent=self.filterLocator,
            relief=None,
            pos=(0, 0, 0),
            image=None,
            text_scale=0.025,
            incButton_image=(arrowUp, arrowDown, arrowHover, arrowUp),
            incButton_relief=None,
            incButton_pos=filterLocatorDownPos,
            incButton_image3_color=(1, 1, 1, 0.2),
            incButtonCallback=self.filterChanged,
            decButton_image=(arrowUp, arrowDown, arrowHover, arrowUp),
            decButton_relief=None,
            decButton_pos=filterLocatorUpPos,
            decButton_scale=(1, 1, -1),
            decButton_image3_color=(1, 1, 1, 0.2),
            decButtonCallback=self.filterChanged,
            numItemsVisible=1,
            itemMakeFunction=makeLabel,
            items=[
                TTLocalizer.CalendarShowAll,
                TTLocalizer.CalendarShowOnlyHolidays,
                TTLocalizer.CalendarShowOnlyParties,
            ],
            itemFrame_frameSize=(-0.2, 0.2, -0.02, 0.05),
            itemFrame_frameColor=(0, 0, 0, 0),
        )
        gui.removeNode()

    def getTopLeftDate(self):
        firstOfTheMonth = self.curDate.replace(day=1)
        daysAwayFromSunday = (firstOfTheMonth.weekday() - 6) % 7
        topLeftDate = firstOfTheMonth + timedelta(days=-daysAwayFromSunday)
        return topLeftDate

    def createGuiDays(self):
        topLeftDate = self.getTopLeftDate()
        curDate = topLeftDate
        self.guiDays = []
        for row in self.dayLocators:
            for oneLocator in row:
                self.guiDays.append(
                    CalendarGuiDay(
                        oneLocator, curDate, self.curDate, self.dayClickCallback, self.onlyFutureDaysClickable
                    )
                )
                curDate += timedelta(days=1)

    def changeDateForGuiDays(self):
        topLeftDate = self.getTopLeftDate()
        guiDayDate = topLeftDate
        for guiDay in self.guiDays:
            guiDay.changeDate(self.curDate, guiDayDate)
            guiDayDate += timedelta(days=1)

    def changeMonth(self, monthChange):
        if monthChange != 0:
            newMonth = self.curDate.month + monthChange
            newYear = self.curDate.year
            while newMonth > 12:
                newYear += 1
                newMonth -= 12

            while newMonth < 1:
                if newYear - 1 > 2002:
                    newMonth += 12
                    newYear -= 1
                else:
                    newMonth += 1

            self.curDate = datetime(
                newYear,
                newMonth,
                1,
                self.curDate.time().hour,
                self.curDate.time().minute,
                self.curDate.time().second,
                self.curDate.time().microsecond,
                self.curDate.tzinfo,
            )
        self.monthLabel["text"] = (TTLocalizer.Months[self.curDate.month],)
        self.yearLabel["text"] = (str(self.curDate.year),)
        startTime = globalClock.getRealTime()
        self.changeDateForGuiDays()
        endTime = globalClock.getRealTime()
        self.notify.debug("changeDate took %f seconds" % (endTime - startTime))
        self.updateSelectedDate()
        if monthChange != 0:
            if self.onlyFutureMonthsClickable and newMonth == self.startDate.month and newYear == self.startDate.year:
                self.monthLeftArrow.hide()

    def __doMonthLeft(self):
        self.changeMonth(-1)

    def __doMonthRight(self):
        self.monthLeftArrow.show()
        self.changeMonth(1)

    def destroy(self):
        self.ignoreAll()
        self.dayClickCallback = None
        self.monthLeftArrow.destroy()
        self.monthRightArrow.destroy()
        for day in self.guiDays:
            if day is not None:
                day.destroy()
            day = None

        self.filterList.destroy()
        DirectFrame.destroy(self)

    def clickedOnDay(self, dayDate):
        self.lastSelectedDate = dayDate
        self.updateSelectedDate()

    def updateSelectedDate(self):
        if self.lastSelectedDate:
            for oneGuiDay in self.guiDays:
                oneGuiDay.updateSelected(oneGuiDay.myDate.date() == self.lastSelectedDate)

    def clearSelectedDay(self):
        for oneGuiDay in self.guiDays:
            oneGuiDay.updateSelected(False)

    def filterChanged(self):
        newFilter = self.filterList.getSelectedIndex()
        for guiDay in self.guiDays:
            guiDay.changeFilter(newFilter)
class CalendarGuiMonth(DirectFrame):
    notify = directNotify.newCategory('CalendarGuiMonth')

    def __init__(self, parent, startingDateTime, scale = 1.0, pos = (0, 0, -0.1), dayClickCallback = None, onlyFutureDaysClickable = False, onlyFutureMonthsClickable = False):
        self.startDate = startingDateTime
        self.curDate = startingDateTime
        self.dayClickCallback = dayClickCallback
        self.onlyFutureDaysClickable = onlyFutureDaysClickable
        self.onlyFutureMonthsClickable = onlyFutureMonthsClickable
        if self.onlyFutureDaysClickable:
            self.onlyFutureMonthsClickable = True
        DirectFrame.__init__(self, parent=parent, scale=scale, pos=pos)
        self.showMarkers = config.GetBool('show-calendar-markers', 0)
        self.load()
        self.createGuiObjects()
        self.lastSelectedDate = None
        self.accept('clickedOnDay', self.clickedOnDay)

    def createDummyLocators(self):
        self.monthLocator = self.attachNewNode('monthLocator')
        self.monthLocator.setZ(0.6)
        self.weekDayLocators = []
        for i in xrange(7):
            self.weekDayLocators.append(self.attachNewNode('weekDayLocator-%d' % i))
            self.weekDayLocators[i].setZ(0.5)
            self.weekDayLocators[i].setX(i * 0.24 + -0.75)

        dayTopLeftX = -0.8
        dayTopLeftZ = 0.4
        self.dayLocators = []
        for row in xrange(6):
            oneWeek = []
            for col in xrange(7):
                newDayLoc = self.attachNewNode('dayLocator-row-%d-col-%d' % (row, col))
                newDayLoc.setX(col * 0.24 + dayTopLeftX)
                newDayLoc.setZ(row * -0.18 + dayTopLeftZ)
                oneWeek.append(newDayLoc)

            self.dayLocators.append(oneWeek)

        self.monthLeftLocator = self.attachNewNode('monthLeft')
        self.monthLeftLocator.setPos(-0.3, 0, 0.65)
        self.monthRightLocator = self.attachNewNode('monthRight')
        self.monthRightLocator.setPos(0.3, 0, 0.65)

    def attachMarker(self, parent, scale = 0.01, color = (1, 0, 0)):
        if self.showMarkers:
            marker = loader.loadModel('phase_3/models/misc/sphere')
            marker.reparentTo(parent)
            marker.setScale(scale)
            marker.setColor(*color)

    def load(self):
        monthAsset = loader.loadModel('phase_4/models/parties/tt_m_gui_sbk_calendar')
        monthAsset.reparentTo(self)
        self.monthLocator = self.find('**/locator_month/locator_month')
        self.attachMarker(self.monthLocator)
        self.weekDayLocators = []
        for weekday in ('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'):
            weekDayLoc = self.find('**/loc_%s' % weekday)
            self.weekDayLocators.append(weekDayLoc)
            self.attachMarker(weekDayLoc)

        self.dayLocators = []
        for row in xrange(6):
            oneWeek = []
            for col in xrange(7):
                newDayLoc = self.find('**/loc_box_%s_%s' % (row, col))
                oneWeek.append(newDayLoc)

            self.dayLocators.append(oneWeek)

        self.monthLeftLocator = self.find('**/locator_month_arrowL')
        self.monthRightLocator = self.find('**/locator_month_arrowR')
        self.filterLocator = self.find('**/locator_filter')
        self.filterLocatorArrowUp = self.find('**/locator_filter_arrowTop')
        self.filterLocatorArrowDown = self.find('**/locator_filter_arrowBottom')
        self.yearLocator = self.attachNewNode('yearLocator')
        self.yearLocator.setPos(self.monthLocator, 0, 0, -0.03)

    def createGuiObjects(self):
        self.monthLabel = DirectLabel(parent=self.monthLocator, relief=None, text=TTLocalizer.Months[self.startDate.month], text_scale=0.075, text_font=ToontownGlobals.getMinnieFont(), text_fg=(40 / 255.0,
         140 / 255.0,
         246 / 255.0,
         1.0))
        self.yearLabel = DirectLabel(parent=self.yearLocator, relief=None, text=str(self.startDate.year), text_scale=0.03, text_font=ToontownGlobals.getMinnieFont(), text_fg=(140 / 255.0,
         140 / 255.0,
         246 / 255.0,
         1.0))
        self.weekdayLabels = []
        for posIndex in xrange(7):
            adjustedNameIndex = (posIndex - 1) % 7
            self.weekdayLabels.append(DirectLabel(parent=self.weekDayLocators[posIndex], relief=None, text=TTLocalizer.DayNamesAbbrev[adjustedNameIndex], text_font=ToontownGlobals.getInterfaceFont(), text_fg=(255 / 255.0,
             146 / 255.0,
             113 / 255.0,
             1.0), text_scale=0.05))

        self.createGuiDays()
        arrowUp = self.find('**/month_arrowR_up')
        arrowDown = self.find('**/month_arrowR_down')
        arrowHover = self.find('**/month_arrowR_hover')
        self.monthLeftArrow = DirectButton(parent=self.monthLeftLocator, relief=None, image=(arrowUp,
         arrowDown,
         arrowHover,
         arrowUp), image3_color=Vec4(1, 1, 1, 0.5), scale=(-1.0, 1.0, 1.0), command=self.__doMonthLeft)
        if self.onlyFutureMonthsClickable:
            self.monthLeftArrow.hide()
        self.monthRightArrow = DirectButton(parent=self.monthRightLocator, relief=None, image=(arrowUp,
         arrowDown,
         arrowHover,
         arrowUp), image3_color=Vec4(1, 1, 1, 0.5), command=self.__doMonthRight)

        def makeLabel(itemName, itemNum, *extraArgs):
            return DirectLabel(text=itemName, frameColor=(0, 0, 0, 0), text_scale=0.04)

        gui = loader.loadModel('phase_4/models/parties/tt_m_gui_sbk_calendar_box')
        arrowUp = gui.find('**/downScroll_up')
        arrowDown = gui.find('**/downScroll_down')
        arrowHover = gui.find('**/downScroll_hover')
        filterLocatorUpPos = self.filterLocatorArrowUp.getPos(self.filterLocator)
        filterLocatorDownPos = self.filterLocatorArrowDown.getPos(self.filterLocator)
        self.filterList = DirectScrolledList(parent=self.filterLocator, relief=None, pos=(0, 0, 0), image=None, text_scale=0.025, incButton_image=(arrowUp,
         arrowDown,
         arrowHover,
         arrowUp), incButton_relief=None, incButton_pos=filterLocatorDownPos, incButton_image3_color=Vec4(1, 1, 1, 0.2), incButtonCallback=self.filterChanged, decButton_image=(arrowUp,
         arrowDown,
         arrowHover,
         arrowUp), decButton_relief=None, decButton_pos=filterLocatorUpPos, decButton_scale=(1, 1, -1), decButton_image3_color=Vec4(1, 1, 1, 0.2), decButtonCallback=self.filterChanged, numItemsVisible=1, itemMakeFunction=makeLabel, items=[TTLocalizer.CalendarShowAll, TTLocalizer.CalendarShowOnlyHolidays, TTLocalizer.CalendarShowOnlyParties], itemFrame_frameSize=(-0.2, 0.2, -0.02, 0.05), itemFrame_frameColor=(0, 0, 0, 0))
        gui.removeNode()

    def getTopLeftDate(self):
        firstOfTheMonth = self.curDate.replace(day=1)
        daysAwayFromSunday = (firstOfTheMonth.weekday() - 6) % 7
        topLeftDate = firstOfTheMonth + timedelta(days=-daysAwayFromSunday)
        return topLeftDate

    def createGuiDays(self):
        topLeftDate = self.getTopLeftDate()
        curDate = topLeftDate
        self.guiDays = []
        for row in self.dayLocators:
            for oneLocator in row:
                self.guiDays.append(CalendarGuiDay(oneLocator, curDate, self.curDate, self.dayClickCallback, self.onlyFutureDaysClickable))
                curDate += timedelta(days=1)

    def changeDateForGuiDays(self):
        topLeftDate = self.getTopLeftDate()
        guiDayDate = topLeftDate
        for guiDay in self.guiDays:
            guiDay.changeDate(self.curDate, guiDayDate)
            guiDayDate += timedelta(days=1)

    def changeMonth(self, monthChange):
        if monthChange != 0:
            newMonth = self.curDate.month + monthChange
            newYear = self.curDate.year
            while newMonth > 12:
                newYear += 1
                newMonth -= 12

            while newMonth < 1:
                if newYear - 1 > 1899:
                    newMonth += 12
                    newYear -= 1
                else:
                    newMonth += 1

            self.curDate = datetime(newYear, newMonth, 1, self.curDate.time().hour, self.curDate.time().minute, self.curDate.time().second, self.curDate.time().microsecond, self.curDate.tzinfo)
        self.monthLabel['text'] = (TTLocalizer.Months[self.curDate.month],)
        self.yearLabel['text'] = (str(self.curDate.year),)
        startTime = globalClock.getRealTime()
        self.changeDateForGuiDays()
        endTime = globalClock.getRealTime()
        self.notify.debug('changeDate took %f seconds' % (endTime - startTime))
        self.updateSelectedDate()
        if monthChange != 0:
            if self.onlyFutureMonthsClickable and newMonth == self.startDate.month and newYear == self.startDate.year:
                self.monthLeftArrow.hide()

    def __doMonthLeft(self):
        self.changeMonth(-1)

    def __doMonthRight(self):
        self.monthLeftArrow.show()
        self.changeMonth(1)

    def destroy(self):
        self.ignoreAll()
        self.dayClickCallback = None
        self.monthLeftArrow.destroy()
        self.monthRightArrow.destroy()
        for day in self.guiDays:
            if day is not None:
                day.destroy()
            day = None

        self.filterList.destroy()
        DirectFrame.destroy(self)

    def clickedOnDay(self, dayDate):
        self.lastSelectedDate = dayDate
        self.updateSelectedDate()

    def updateSelectedDate(self):
        if self.lastSelectedDate:
            for oneGuiDay in self.guiDays:
                if oneGuiDay.myDate.date() == self.lastSelectedDate:
                    oneGuiDay.updateSelected(True)
                else:
                    oneGuiDay.updateSelected(False)

    def clearSelectedDay(self):
        for oneGuiDay in self.guiDays:
            oneGuiDay.updateSelected(False)

    def filterChanged(self):
        newFilter = self.filterList.getSelectedIndex()
        for guiDay in self.guiDays:
            guiDay.changeFilter(newFilter)
class GloveShopGui:

    def __init__(self):
        self.index = 0
        self.id = time.time()
        self.lastGlove = base.localAvatar.style.gloveColor
        self.timer = ToontownTimer.ToontownTimer()
        self.timer.reparentTo(aspect2d)
        self.timer.posInTopRightCorner()
        self.timer.countdown(GloveNPCGlobals.TIMER_SECONDS, self.__exit, [GloveNPCGlobals.TIMER_END])
        self.setupButtons()
        self.bindButtons()
        self.__updateIndex(0)

    def setupButtons(self):
        gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_mainGui')
        arrowImage = (gui.find('**/tt_t_gui_mat_shuffleArrowUp'), gui.find('**/tt_t_gui_mat_shuffleArrowDown'))
        buttonImage = (gui.find('**/tt_t_gui_mat_shuffleUp'), gui.find('**/tt_t_gui_mat_shuffleDown'))

        self.title = DirectLabel(aspect2d, relief=None, text=TTLocalizer.GloveGuiTitle,
                     text_fg=(0, 1, 0, 1), text_scale=0.15, text_font=ToontownGlobals.getSignFont(),
                     pos=(0, 0, -0.30), text_shadow=(1, 1, 1, 1))

        self.notice = DirectLabel(aspect2d, relief=None, text='', text_fg=(1, 0, 0, 1), text_scale=0.11,
                      text_font=ToontownGlobals.getSignFont(), pos=(0, 0, -0.45), text_shadow=(1, 1, 1, 1))

        self.color = DirectLabel(aspect2d, relief=None, text='', text_scale=0.11, text_font=ToontownGlobals.getSignFont(),
                     pos=(0, 0, -0.70), text_shadow=(1, 1, 1, 1))

        self.buyButton = DirectButton(aspect2d, relief=None, image=buttonImage, text=TTLocalizer.GloveGuiBuy,
                         text_font=ToontownGlobals.getInterfaceFont(), text_scale=0.11, text_pos=(0, -0.02),
                         pos=(-0.60, 0, -0.90), text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), command=self.__exit, extraArgs=[GloveNPCGlobals.CHANGE])

        self.cancelButton = DirectButton(aspect2d, relief=None, image=buttonImage, text=TTLocalizer.lCancel,
                            text_font=ToontownGlobals.getInterfaceFont(), text_scale=0.11, text_pos=(0, -0.02),
                            pos=(0.60, 0, -0.90), text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), command=self.__exit, extraArgs=[GloveNPCGlobals.USER_CANCEL])

        self.downArrow = DirectButton(aspect2d, relief=None, image=arrowImage, pos=(-0.60, 0, -0.66))
        self.upArrow = DirectButton(aspect2d, relief=None, image=arrowImage, pos=(0.60, 0, -0.66), scale=-1)

        gui.removeNode()

    def bindButtons(self):
        self.downArrow.bind(DGG.B1PRESS, self.__taskUpdate, extraArgs=[-1])
        self.downArrow.bind(DGG.B1RELEASE, self.__taskDone)
        self.upArrow.bind(DGG.B1PRESS, self.__taskUpdate, extraArgs=[1])
        self.upArrow.bind(DGG.B1RELEASE, self.__taskDone)

    def destroy(self):
        if self.timer:
            self.timer.destroy()

        if not hasattr(self, 'title'):
            return

        # TODO: DirectDialog-ify
        self.title.destroy()
        self.notice.destroy()
        self.color.destroy()
        self.buyButton.destroy()
        self.cancelButton.destroy()
        self.downArrow.destroy()
        self.upArrow.destroy()
        del self.title
        del self.notice
        del self.color
        del self.buyButton
        del self.cancelButton
        del self.downArrow
        del self.upArrow

        taskMgr.remove('runGloveCounter-%s' % self.id)

    def setClientGlove(self, color):
        dna = base.localAvatar.style

        dna.gloveColor = color
        base.localAvatar.setDNA(dna)

    def __exit(self, state):
        self.destroy()
        self.setClientGlove(self.lastGlove)
        messenger.send('gloveShopDone', [state, self.index if state == GloveNPCGlobals.CHANGE else 0])

    def __updateIndex(self, offset):
        self.index += offset
        hitLimit = 0

        if self.index <= 0:
            self.downArrow['state'] = DGG.DISABLED
            hitLimit = 1
        else:
            self.downArrow['state'] = DGG.NORMAL

        if (self.index + 1) >= len(TTLocalizer.NumToColor):
            self.upArrow['state'] = DGG.DISABLED
            hitLimit = 1
        else:
            self.upArrow['state'] = DGG.NORMAL

        if self.lastGlove == self.index:
            self.buyButton['state'] = DGG.DISABLED
            self.notice['text'] = TTLocalizer.GloveGuiSameColor
        else:
            self.buyButton['state'] = DGG.NORMAL
            self.notice['text'] = TTLocalizer.GloveGuiNotice % ToontownGlobals.GloveCost

        self.color['text'] = TTLocalizer.NumToColor[self.index]
        self.color['text_fg'] = ToonDNA.allColorsList[self.index]
        self.setClientGlove(self.index)
        return hitLimit

    def __runTask(self, task):
        if task.time - task.prevTime < task.delayTime:
            return Task.cont
        else:
            task.delayTime = max(0.05, task.delayTime * 0.75)
            task.prevTime = task.time
            hitLimit = self.__updateIndex(task.delta)

            return Task.done if hitLimit else Task.cont

    def __taskDone(self, event):
        messenger.send('wakeup')
        taskMgr.remove('runGloveCounter-%s' % self.id)

    def __taskUpdate(self, delta, event):
        messenger.send('wakeup')

        task = Task(self.__runTask)
        task.delayTime = 0.4
        task.prevTime = 0.0
        task.delta = delta
        hitLimit = self.__updateIndex(delta)

        if not hitLimit:
            taskMgr.add(task, 'runGloveCounter-%s' % self.id)
예제 #22
0
파일: obj_animals.py 프로젝트: sccn/SNAP
    def run(self):
        self.implicit_markers = False
        base.win.setClearColor((0, 0, 0, 1))
        
        self.marker(0)  # Send one event to trigger the whole event sending process
        
        if self.training:
            self.stimuli_order = self.stimuli_order[:16]
            self.n_blocks = 1
            self.n_runs = 1
        
        if self.av_type == 'auditory':
            self.file_list = ['studies/obj_animals/stimuli/' + k.strip() + '_f.wav' for k in self.stimuli]
            for f in self.file_list:
                self.precache_sound(f)
        self.precache_sound('buzz.wav')
        self.precache_sound('beep.wav')
            
        # Define text properties
        tp_gray = TextProperties()
        tp_gray.setTextColor(0.5, 0.5, 0.5, 1)
        tpMgr = TextPropertiesManager.getGlobalPtr()
        tpMgr.setProperties("gray", tp_gray)
        
        # Show instructions
        if self.training:
            if self.av_type == 'visual':
                verb = 'see'
            else:
                verb = 'hear'
            self.write('This is a word association experiment.\nYou will complete several trials in this block.\n\n' + 
                       '\1gray\1[Press Space to continue]\2', fg=(1, 1, 1, 1), duration='space', align='left', pos=(-0.5, 0), scale=0.05)
            self.write('The experiment consists of two conditions.\nIn each trial, ' + 
                       'you will be prompted to perform\none of these two tasks:\n' +
                       '(1) touch a button on the screen,\n' + 
                       '(2) press the space bar.\n\n\1gray\1[Press Space to continue]\2', fg=(1, 1, 1, 1), duration='space', align='left', pos=(-0.5, 0), scale=0.05)
            self.write('In each trial, you will ' + verb + ' a word.\nWhen the word is an animal,\n' + 
                       'touch the button on the screen.\n\n\1gray\1[Press Space to continue]\2', fg=(1, 1, 1, 1), duration='space', align='left', pos=(-0.5, 0), scale=0.05)
            self.write('When the word is an object,\npress the space bar.\n\n\1gray\1[Press Space to continue]\2', fg=(1, 1, 1, 1), duration='space', align='left', pos=(-0.5, 0), scale=0.05)
            self.write('You will hear a beep for correct answers.\nYou will hear a buzz for incorrect answers.\n\n\1gray\1[Press Space to continue]\2', fg=(1, 1, 1, 1), duration='space', align='left', pos=(-0.5, 0), scale=0.05)
        self.write('When you are ready,\npress the space bar to begin.' + 
                   '\n\n\1gray\1[Press Space to continue]\2', fg=(1, 1, 1, 1), duration='space', align='left', pos=(-0.5, 0), scale=0.05)

        t = time.localtime()
        t_str = '-'.join([str(k) for k in [t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec]])
        f = open('studies/obj_animals/log/' + t_str + '.txt', 'w')
        f.write('Stimulus No.\tStimulus\tCategory\tButton position\tScore\n')
        self.sleep(5)
        
        counter = 0  # Needed for breaks between blocks
       
        for k in self.stimuli_order:

            # Short break
            if not self.training and counter in xrange(len(self.stimuli_order)/self.n_blocks/2, len(self.stimuli_order), len(self.stimuli_order)/self.n_blocks/2):
                self.write('Time for a short break.\n\n' + 
                          '\1gray\1[Press Space to continue]\2', fg=(1, 1, 1, 1), duration='space', align='left', pos=(-0.5, 0), scale=0.05)
                self.sleep(2)
            
            counter += 1
            
            # I have to calculate button positions in case the window size changed
            ar = base.getAspectRatio()
            button_frame = (-ar/9, ar/9, -1.0/4, 1.0/4)
            buttons = []
            for k1 in xrange(2, 7):
                    for k2 in xrange(4):
                        buttons.append((-ar + ar / 9 + k1 * ar / 4.5, 0, 1 - 1.0 / 4 - k2 / 2.0))
            # Delete middle buttons
            del buttons[5:7]
            del buttons[7:9]
            del buttons[9:11] 
            
            choice = random.randint(0, len(buttons) - 1)
            button = buttons[choice]
            f.write(str(k) + '\t' + self.stimuli[k].strip() + '\t' + self.conditions[self.target[k]] + '\t' + str(choice) + '\t')
            
            # Visual or auditory presentation
            if self.av_type == 'auditory':
                self.sound(self.file_list[k], volume=0.5)
                self.sleep(0.2)
                self.write('+', duration=self.isi-self.pause, block=False, scale=0.15, fg=(1, 1, 1, 1))  
            elif self.av_type == 'visual':
                self.sleep(0.2)
                self.write(self.stimuli[k], duration=self.isi-self.pause, block=False, scale=0.15, fg=(1, 1, 1, 1))
                
            self.marker(k + 10000)
            btn = DirectButton(frameSize=button_frame, pos=button, frameColor=(0.75, 0, 0, 1), borderWidth=(0.01, 0.01),
                               rolloverSound=None, clickSound=None, command=messenger.send, extraArgs=('button_pressed',))
          
            latencies = self.waitfor_multiple(['button_pressed', 'space'], self.isi)
            if not latencies:
                response = 'none'
                wait_time = self.pause
                self.sound('buzz.wav', volume=0.5)
            else:
                response = latencies[0]
                wait_time = self.pause + self.isi - latencies[1]
                if self.target[k] == 1 and response == 'button_pressed':  # Check if values in dictionary are not empty
                    self.score += int(100 * (self.isi - latencies[1]) / self.isi)
                    self.sound('beep.wav', volume=0.5)
                elif self.target[k] == 0 and response == 'space':
                    self.score += int(10 * (self.isi - latencies[1]) / self.isi)
                    self.sound('beep.wav', volume=0.5)
                elif (self.target[k] == 1 and response == 'space') or (self.target[k] == 0 and response == 'button_pressed'):
                    self.score -= 5
                    if self.score < 0:
                        self.score = 0
                    self.sound('buzz.wav', volume=0.5)
                 
            f.write(str(self.score) + '\n')
            try:
                btn.destroy()
            except:
                pass
            self.sleep(wait_time - 0.2)
                
        f.close()    
        if not self.training:    
            self.write('You successfully completed\none run of the experiment.\n\nThank you!', duration=5, align='left', pos=(-0.5, 0), scale=0.05, fg=(1, 1, 1, 1))
예제 #23
0
class BackpackGUI(DirectFrame):
    notify = directNotify.newCategory('BackpackGUI')
    InLoadoutColor = Vec4(1, 0.6, 0.5, 1)
    DefaultColor = Vec4(0, 0.6, 1, 1)
    DisabledColor = Vec4(0.5, 0.5, 0.5, 1)

    def __init__(self):
        DirectFrame.__init__(self)
        self.trackByName = {}
        self.gagButtonByName = {}
        self.editButton = None
        self.fsm = ClassicFSM.ClassicFSM('BackpackGUI', [State.State('off', self.enterOff, self.exitOff), State.State('idle', self.enterIdle, self.exitIdle), State.State('edit', self.enterEditGags, self.exitEditGags)], 'off', 'off')
        self.fsm.enterInitialState()
        self.editFSM = ClassicFSM.ClassicFSM('BPGUIEdit', [State.State('off', self.enterOff, self.exitOff), State.State('add', self.enterAddGags, self.exitAddGags), State.State('remove', self.enterRemoveGags, self.exitRemoveGags)], 'off', 'off')
        self.editFSM.enterInitialState()
        self.gm = GagManager.GagManager()
        return

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def __addGagToLoadout(self, gagName):
        gagId = GagGlobals.gagIdByName[gagName]
        self.newLoadout.append(gagId)
        self.__updateButtons_add()

    def __removeGagFromLoadout(self, gagName):
        gagId = GagGlobals.gagIdByName[gagName]
        self.newLoadout.remove(gagId)
        self.__updateButtons_remove()

    def __updateButtons_add(self):
        for gagName, button in self.gagButtonByName.items():
            if self.isInLoadoutNew(gagName):
                button['state'] = DGG.DISABLED
                button['image_color'] = self.InLoadoutColor
            elif len(self.newLoadout) == 4:
                button['state'] = DGG.DISABLED
                button['image_color'] = self.DisabledColor
            else:
                button['state'] = DGG.NORMAL
                button['command'] = self.__addGagToLoadout
                button['extraArgs'] = [gagName]
                button['image_color'] = self.DefaultColor

    def __updateButtons_remove(self):
        for gagName, button in self.gagButtonByName.items():
            if self.isInLoadoutNew(gagName):
                button['state'] = DGG.NORMAL
                button['command'] = self.__removeGagFromLoadout
                button['extraArgs'] = [gagName]
                button['image_color'] = self.InLoadoutColor
            else:
                button['state'] = DGG.DISABLED
                button['image_color'] = self.DisabledColor

    def enterAddGags(self):
        self.switchButton['text'] = 'Remove Gags'
        self.switchButton['command'] = self.editFSM.request
        self.switchButton['extraArgs'] = ['remove']
        self.__updateButtons_add()

    def exitAddGags(self):
        pass

    def enterRemoveGags(self):
        self.switchButton['text'] = 'Add Gags'
        self.switchButton['command'] = self.editFSM.request
        self.switchButton['extraArgs'] = ['add']
        self.__updateButtons_remove()

    def exitRemoveGags(self):
        pass

    def enterEditGags(self):
        self.initialLoadout = []
        for instance in base.localAvatar.backpack.getLoadout():
            self.initialLoadout.append(instance.getID())

        self.newLoadout = list(self.initialLoadout)
        self.editButton['text'] = 'Stop Editing'
        self.editButton['command'] = self.fsm.request
        self.editButton['extraArgs'] = ['idle']
        self.switchButton = DirectButton(relief=None, image=CIGlobals.getDefaultBtnGeom(), text='Add Gags', text_scale=0.045, text_pos=(0, -0.01), pos=(0.5, 0, -0.4))
        self.editFSM.request('add')
        return

    def exitEditGags(self):
        self.switchButton.destroy()
        del self.switchButton
        if len(self.newLoadout) == 4:
            base.localAvatar.sendUpdate('requestSetLoadout', [self.newLoadout])
        del self.newLoadout
        del self.initialLoadout

    def isInLoadoutNew(self, gagName):
        gagId = GagGlobals.gagIdByName[gagName]
        return gagId in self.newLoadout

    def isInLoadoutLive(self, gagName):
        for instance in base.localAvatar.backpack.getLoadout():
            if instance.getName() == gagName:
                return True

        return False

    def enterIdle(self):
        self.editButton['text'] = 'Edit Loadout'
        self.editButton['command'] = self.fsm.request
        self.editButton['extraArgs'] = ['edit']
        for gagName, button in self.gagButtonByName.items():
            button['state'] = DGG.DISABLED
            if self.isInLoadoutLive(gagName):
                button['image_color'] = self.InLoadoutColor
            else:
                button['image_color'] = self.DefaultColor

    def exitIdle(self):
        pass

    def __makeTrack(self, trackName):
        gui = loader.loadModel('phase_3.5/models/gui/inventory_gui.bam')
        color = GagGlobals.TrackColorByName[trackName]
        track = gui.find('**/InventoryRow')
        track.setColor(*color)
        frame = DirectFrame(parent=self)
        frame.setZ(TrackZValueByName[trackName])
        frame['image'] = track
        trackTitle = OnscreenText(text=trackName, parent=frame, pos=(-0.63, -0.01, 0), scale=0.06)
        self.trackByName[trackName] = frame

    def __makeGagButton(self, gagName, trackName):
        gui = loader.loadModel('phase_3.5/models/gui/inventory_gui.bam')
        icons = loader.loadModel('phase_3.5/models/gui/inventory_icons.bam')
        icon = icons.find(GagGlobals.InventoryIconByName[gagName])
        index = GagGlobals.TrackGagNamesByTrackName[trackName].index(gagName)
        xValue = GagButtonXValues[index]
        button = DirectButton(relief=None, image=(gui.find('**/InventoryButtonUp'),
         gui.find('**/InventoryButtonDown'),
         gui.find('**/InventoryButtonRollover'),
         gui.find('**/InventoryButtonFlat')), geom=icon, geom_scale=0.6, parent=self.trackByName[trackName])
        button.setX(xValue)
        self.gagButtonByName[gagName] = button
        return

    def createGUI(self):
        for i in xrange(len(GagGlobals.TrackNameById)):
            trackName = GagGlobals.TrackNameById[i]
            self.__makeTrack(trackName)
            for j in xrange(len(GagGlobals.TrackGagNamesByTrackName[trackName])):
                gagName = GagGlobals.TrackGagNamesByTrackName[trackName][j]
                gagId = GagGlobals.gagIdByName[gagName]
                if gagId in base.localAvatar.getBackpackAmmo()[0]:
                    self.__makeGagButton(gagName, trackName)

        self.editButton = DirectButton(relief=None, image=CIGlobals.getDefaultBtnGeom(), text='Edit Loadout', text_scale=0.045, text_pos=(0, -0.01), pos=(-0.5, 0, -0.4))
        self.fsm.request('idle')
        return

    def deleteGUI(self):
        self.editFSM.requestFinalState()
        self.fsm.requestFinalState()
        for button in self.gagButtonByName.values():
            button.destroy()

        self.gagButtonByName = None
        for track in self.trackByName.values():
            track.destroy()

        self.trackByName = None
        self.editButton.destroy()
        self.editButton = None
        self.gm = None
        del self.editFSM
        del self.fsm
        return
예제 #24
0
class DistributedPieTurretManager(DistributedObject):
    notify = directNotify.newCategory("DistributedPieTurretManager")

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.myTurret = None
        self.guiFrame = None
        self.guiLabel = None
        self.guiBar = None
        self.guiBg = None
        self.turretGag = None
        return

    def announceGenerate(self):
        DistributedObject.announceGenerate(self)
        base.taskMgr.add(self.__pollMyBattle, "__pollMyBattle")

    def disable(self):
        base.taskMgr.remove("DPTM.pollTurret")
        base.taskMgr.remove("__pollMyBattle")
        if hasattr(self, "makeTurretBtn"):
            self.makeTurretBtn.destroy()
            del self.makeTurretBtn
        self.destroyGui()
        self.myTurret = None
        if base.localAvatar.getMyBattle():
            base.localAvatar.getMyBattle().setTurretManager(None)
        DistributedObject.disable(self)
        return

    def __pollTurret(self, turretId, task):
        turret = self.cr.doId2do.get(turretId)
        if turret != None:
            self.myTurret = turret
            self.turretGag = None
            self.makeGui()
            return Task.done
        else:
            return Task.cont

    def setGag(self, upgradeId):
        self.turretGag = upgradeId

    def d_requestPlace(self, posHpr):
        self.sendUpdate("requestPlace", [posHpr])

    def turretPlaced(self, turretId):
        turret = self.cr.doId2do.get(turretId)
        turret.b_setGag(self.turretGag)
        self.turretGag = None
        base.taskMgr.add(self.__pollTurret, "DPTM.pollTurret", extraArgs=[turretId], appendTask=True)
        return

    def yourTurretIsDead(self):
        base.taskMgr.remove("DPTM.pollTurret")
        self.destroyGui()
        self.myTurret = None
        if base.localAvatar.getPUInventory()[0] > 0:
            self.createTurretButton()
        return

    def makeGui(self):
        self.destroyGui()
        self.guiFrame = DirectFrame(parent=base.a2dBottomRight, pos=(-0.55, 0, 0.15))
        self.guiBg = OnscreenImage(image="phase_4/maps/turret_gui_bg.png", scale=(0.15, 0, 0.075), parent=self.guiFrame)
        self.guiBg.setTransparency(True)
        self.guiLabel = DirectLabel(
            text="Turret",
            text_fg=(1, 0, 0, 1),
            relief=None,
            text_scale=0.05,
            text_font=loader.loadFont("phase_3/models/fonts/ImpressBT.ttf"),
            pos=(0, 0, 0.025),
            parent=self.guiFrame,
        )
        self.guiBar = DirectWaitBar(
            range=self.myTurret.getMaxHealth(),
            value=self.myTurret.getHealth(),
            scale=0.125,
            parent=self.guiFrame,
            pos=(0, 0, -0.01),
        )
        return

    def createTurretButton(self):
        self.makeTurretBtn = DirectButton(
            relief=None,
            geom=CIGlobals.getDefaultBtnGeom(),
            text="Turret",
            text_scale=0.055,
            command=self.handleMakeTurretBtn,
            pos=(-0.47, 0, 0.1),
            geom_scale=(0.5, 1.0, 1.0),
            text_pos=(0, -0.01),
            parent=base.a2dBottomRight,
        )
        return

    def handleMakeTurretBtn(self):
        self.makeTurretBtn.destroy()
        del self.makeTurretBtn
        x, y, z = base.localAvatar.getPos()
        h, p, r = base.localAvatar.getHpr()
        self.d_requestPlace([x, y, z, h, p, r])
        base.localAvatar.sendUpdate("usedPU", [0])

    def __pollMyBattle(self, task):
        if base.localAvatar.getMyBattle():
            base.localAvatar.getMyBattle().setTurretManager(self)
            if base.localAvatar.getPUInventory()[0] > 0:
                self.createTurretButton()
            return Task.done
        return Task.cont

    def destroyGui(self):
        if self.guiBar:
            self.guiBar.destroy()
            self.guiBar = None
        if self.guiLabel:
            self.guiLabel.destroy()
            self.guiLabel = None
        if self.guiBg:
            self.guiBg.destroy()
            self.guiBg = None
        if self.guiFrame:
            self.guiFrame.destroy()
            self.guiFrame = None
        return

    def updateTurretGui(self):
        if self.guiBar:
            self.guiBar.update(self.myTurret.getHealth())
class JellybeanRewardGui(DirectFrame):
    notify = directNotify.newCategory('JellybeanRewardGui')
    PreCountdownDelay = 1.0
    CountDownRate = 0.2
    JarLabelTextColor = (0.95, 0.95, 0.0, 1.0)
    JarLabelMaxedTextColor = (1.0, 0.0, 0.0, 1.0)

    def __init__(self, doneEvent):
        self.doneEvent = doneEvent
        DirectFrame.__init__(self)
        self.reparentTo(aspect2d)
        self.setPos(0.0, 0.0, 0.16)
        self.stash()
        publicPartyGui = loader.loadModel('phase_4/models/parties/publicPartyGUI')
        self.frame = DirectFrame(parent=self, geom=publicPartyGui.find('**/activities_background'), geom_pos=(-0.8, 0.0, 0.2), geom_scale=2.0, relief=None)
        self.earnedLabel = DirectLabel(parent=self, relief=None, text=str(0), text_align=TextNode.ACenter, text_pos=(0.0, -0.07), text_scale=0.2, text_fg=(0.95, 0.95, 0.0, 1.0), text_font=ToontownGlobals.getSignFont(), textMayChange=True, image=DirectGuiGlobals.getDefaultDialogGeom(), image_scale=(0.33, 1.0, 0.33), pos=(-0.3, 0.0, 0.2), scale=0.9)
        purchaseModels = loader.loadModel('phase_4/models/gui/purchase_gui')
        jarImage = purchaseModels.find('**/Jar')
        self.jarLabel = DirectLabel(parent=self, relief=None, text=str(0), text_align=TextNode.ACenter, text_pos=(0.0, -0.07), text_scale=0.2, text_fg=JellybeanRewardGui.JarLabelTextColor, text_font=ToontownGlobals.getSignFont(), textMayChange=True, image=jarImage, scale=0.7, pos=(0.3, 0.0, 0.17))
        purchaseModels.removeNode()
        del purchaseModels
        jarImage.removeNode()
        del jarImage
        self.messageLabel = DirectLabel(parent=self, relief=None, text='', text_align=TextNode.ALeft, text_wordwrap=16.0, text_scale=0.07, pos=(-0.52, 0.0, -0.1), textMayChange=True)
        self.doubledJellybeanLabel = DirectLabel(parent=self, relief=None, text=TTLocalizer.PartyRewardDoubledJellybean, text_align=TextNode.ACenter, text_wordwrap=12.0, text_scale=0.09, text_fg=(1.0, 0.125, 0.125, 1.0), pos=(0.0, 0.0, -0.465), textMayChange=False)
        self.doubledJellybeanLabel.hide()
        self.closeButton = DirectButton(parent=self, relief=None, text=TTLocalizer.PartyJellybeanRewardOK, text_align=TextNode.ACenter, text_scale=0.065, text_pos=(0.0, -0.625), geom=(publicPartyGui.find('**/startButton_up'),
         publicPartyGui.find('**/startButton_down'),
         publicPartyGui.find('**/startButton_rollover'),
         publicPartyGui.find('**/startButton_inactive')), geom_pos=(-0.39, 0.0, 0.125), command=self._close)
        publicPartyGui.removeNode()
        del publicPartyGui
        self.countSound = base.loadSfx('phase_13/audio/sfx/tick_counter_short.mp3')
        self.overMaxSound = base.loadSfx('phase_13/audio/sfx/tick_counter_overflow.mp3')
        return

    def showReward(self, earnedAmount, jarAmount, message):
        JellybeanRewardGui.notify.debug('showReward( earnedAmount=%d, jarAmount=%d, ...)' % (earnedAmount, jarAmount))
        self.earnedCount = earnedAmount
        self.earnedLabel['text'] = str(self.earnedCount)
        self.jarCount = jarAmount
        self.jarMax = base.localAvatar.getMaxMoney()
        self.jarLabel['text'] = str(self.jarCount)
        self.jarLabel['text_fg'] = JellybeanRewardGui.JarLabelTextColor
        self.messageLabel['text'] = message
        if base.cr.newsManager.isHolidayRunning(ToontownGlobals.JELLYBEAN_DAY) or base.cr.newsManager.isHolidayRunning(ToontownGlobals.JELLYBEAN_PARTIES_HOLIDAY) or base.cr.newsManager.isHolidayRunning(ToontownGlobals.JELLYBEAN_PARTIES_HOLIDAY_MONTH):
            self.doubledJellybeanLabel.show()
        else:
            self.doubledJellybeanLabel.hide()
        self.unstash()
        taskMgr.doMethodLater(JellybeanRewardGui.PreCountdownDelay, self.transferOneJellybean, 'JellybeanRewardGuiTransferOneJellybean', extraArgs=[])

    def transferOneJellybean(self):
        if self.earnedCount == 0:
            return
        self.earnedCount -= 1
        self.earnedLabel['text'] = str(self.earnedCount)
        self.jarCount += 1
        if self.jarCount <= self.jarMax:
            self.jarLabel['text'] = str(self.jarCount)
        elif self.jarCount > self.jarMax:
            self.jarLabel['text_fg'] = JellybeanRewardGui.JarLabelMaxedTextColor
        if self.jarCount <= self.jarMax:
            base.playSfx(self.countSound)
        else:
            base.playSfx(self.overMaxSound)
        taskMgr.doMethodLater(JellybeanRewardGui.CountDownRate, self.transferOneJellybean, 'JellybeanRewardGuiTransferOneJellybean', extraArgs=[])

    def _close(self):
        taskMgr.remove('JellybeanRewardGuiTransferOneJellybean')
        self.stash()
        messenger.send(self.doneEvent)

    def destroy(self):
        taskMgr.remove('JellybeanRewardGuiTransferOneJellybean')
        del self.countSound
        del self.overMaxSound
        self.frame.destroy()
        self.earnedLabel.destroy()
        self.jarLabel.destroy()
        self.messageLabel.destroy()
        self.closeButton.destroy()
        DirectFrame.destroy(self)
예제 #26
0
class Game(DirectObject):
    def __init__(self):

        self.setAI()

        self.keyMap = {"left": 0, "right": 0, "forward": 0, "backward": 0, "cam-left": 0, "cam-right": 0}
        base.win.setClearColor(Vec4(0, 0, 0, 1))

        # the menu
        self.loadAudio()
        self.showMenu()

        # keyboard and mouse events
        self.accept("escape", sys.exit)
        self.accept("w", self.setKey, ["forward", 1])
        self.accept("a", self.setKey, ["left", 1])
        self.accept("s", self.setKey, ["backward", 1])
        self.accept("d", self.setKey, ["right", 1])
        self.accept("w-up", self.setKey, ["forward", 0])
        self.accept("a-up", self.setKey, ["left", 0])
        self.accept("s-up", self.setKey, ["backward", 0])
        self.accept("d-up", self.setKey, ["right", 0])
        self.accept("arrow_left", self.setKey, ["cam-left", 1])
        self.accept("arrow_left-up", self.setKey, ["cam-left", 0])
        self.accept("arrow_right", self.setKey, ["cam-right", 1])
        self.accept("arrow_right-up", self.setKey, ["cam-right", 0])

        # create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(0.3, 0.3, 0.3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))

    def loadAudio(self):
        self.startAudio = base.loader.loadSfx("../assets/audio/start.mp3")
        self.gameAudio = base.loader.loadSfx("../assets/audio/game.mp3")
        self.winAudio = base.loader.loadSfx("../assets/audio/win.mp3")
        self.loseAudio = base.loader.loadSfx("../assets/audio/lose.mp3")

    def createPresents(self):
        self.speedPill = loader.loadModel("../assets/models/capsule/capsule")
        self.speedPill.reparentTo(render)
        self.speedPill.setScale(0.025)
        self.speedPill.setPos(-43.9744, 32.031, 0.6)

        self.speedPillb = loader.loadModel("../assets/models/capsule/capsule")
        self.speedPillb.reparentTo(render)
        self.speedPillb.setScale(0.025)
        self.speedPillb.setPos(-57.7858, -61.5068, 3.80818)

        self.banana = loader.loadModel("../assets/models/banana/banana")
        self.banana.reparentTo(render)
        self.banana.setScale(3)
        self.banana.setPos(-72.484, -7.14435, 5.05246)

        self.sphinx = loader.loadModel("../assets/models/sphinx/sphinx")
        self.sphinx.reparentTo(render)
        self.sphinx.setScale(0.0025)
        self.sphinx.setPos(-48.0702, -39.4669, 0.5)

    def createMilesAI(self):
        startPos = self.env.find("**/start_point").getPos()

        # load miles actor
        self.miles1 = Actor(
            "../assets/models/miles/tails",
            {
                "board": "../assets/models/miles/tails-board",
                "win": "../assets/models/miles/tails-win",
                "fwboard": "../assets/models/miles/tails-fallingwboard",
                "fwoboard": "../assets/models/miles/tails-fallingwoboard",
            },
        )

        self.miles2 = Actor(
            "../assets/models/miles/tails",
            {
                "board": "../assets/models/miles/tails-board",
                "win": "../assets/models/miles/tails-win",
                "fwboard": "../assets/models/miles/tails-fallingwboard",
                "fwoboard": "../assets/models/miles/tails-fallingwoboard",
            },
        )

        self.miles = [self.miles1, self.miles2]

        self.miles1.reparentTo(render)
        self.miles1.setScale(0.05)
        self.miles1.setPlayRate(3, "run")
        self.miles1.loop("board")
        self.miles1.setPos(startPos[0] + 5, startPos[1] - 20, startPos[2])

        self.miles1GroundRay = CollisionRay()
        self.miles1GroundRay.setOrigin(0, 0, 1000)
        self.miles1GroundRay.setDirection(0, 0, -1)
        self.miles1GroundCol = CollisionNode("miles1Ray")
        self.miles1GroundCol.addSolid(self.miles1GroundRay)
        self.miles1GroundCol.setFromCollideMask(BitMask32.bit(0))
        self.miles1GroundCol.setIntoCollideMask(BitMask32.allOff())
        self.miles1GroundColNp = self.miles1.attachNewNode(self.miles1GroundCol)
        self.miles1GroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.miles1GroundColNp, self.miles1GroundHandler)

        # AI code for miles1
        self.miles1AI = AICharacter("miles1", self.miles1, 100, 1, 7)
        self.AIworld.addAiChar(self.miles1AI)
        self.miles1AIbehaviors = self.miles1AI.getAiBehaviors()

        # pursue behavior
        self.miles1AIbehaviors.pursue(self.sonic)

        taskMgr.add(self.moveMiles1AI, "moveMiles1AI")

        self.miles2.reparentTo(render)
        self.miles2.setScale(0.05)
        self.miles2.setPlayRate(3, "run")
        self.miles2.loop("win")
        self.miles2.setPos(startPos[0] - 5, startPos[1] - 20, startPos[2])

        self.miles2GroundRay = CollisionRay()
        self.miles2GroundRay.setOrigin(0, 0, 1000)
        self.miles2GroundRay.setDirection(0, 0, -1)
        self.miles2GroundCol = CollisionNode("miles2Ray")
        self.miles2GroundCol.addSolid(self.miles2GroundRay)
        self.miles2GroundCol.setFromCollideMask(BitMask32.bit(0))
        self.miles2GroundCol.setIntoCollideMask(BitMask32.allOff())
        self.miles2GroundColNp = self.miles2.attachNewNode(self.miles2GroundCol)
        self.miles2GroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.miles2GroundColNp, self.miles2GroundHandler)

        self.miles2AI = AICharacter("miles2", self.miles2, 100, 1, 7)
        self.AIworld.addAiChar(self.miles2AI)
        self.miles2AIbehaviors = self.miles2AI.getAiBehaviors()

        # puruse behavior
        self.miles2AIbehaviors.pursue(self.sonic)

        taskMgr.add(self.moveMiles2AI, "moveMiles2AI")

    def createTrexAI(self):
        startPos = self.env.find("**/start_point").getPos()

        # Load the trex actor and loop its animation
        self.trex = Actor(
            "../assets/models/trex/trex",
            {"run": "../assets/models/trex/trex-run", "eat": "../assets/models/trex/trex-eat"},
        )
        self.trex.reparentTo(render)
        self.trex.setScale(0.25)
        self.trex.setPlayRate(3, "run")
        self.trex.loop("run")
        self.trex.setPos(startPos[0], startPos[-1] - 20, startPos[2])

        self.trexGroundRay = CollisionRay()
        self.trexGroundRay.setOrigin(0, 0, 1000)
        self.trexGroundRay.setDirection(0, 0, -1)
        self.trexGroundCol = CollisionNode("trexRay")
        self.trexGroundCol.addSolid(self.trexGroundRay)
        self.trexGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.trexGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.trexGroundColNp = self.trex.attachNewNode(self.trexGroundCol)
        self.trexGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.trexGroundColNp, self.trexGroundHandler)

        # self.pusher.addCollider(self.trexGroundColNp, self.sonic)

        # AI code for trex
        self.trexAI = AICharacter("trex", self.trex, 100, 1, 7)
        self.AIworld.addAiChar(self.trexAI)
        self.trexAIbehaviors = self.trexAI.getAiBehaviors()

        # pursue behavior
        # self.trexAIbehaviors.pursue(self.sonic)

        self.trexAIbehaviors.pursue(self.sonic)

        taskMgr.add(self.moveTrexAI, "moveTrexAI")

    # to create the AI world
    def setAI(self):
        self.AIworld = AIWorld(render)
        taskMgr.add(self.AIUpdate, "AIUpdate")

    def AIUpdate(self, task):
        self.AIworld.update()
        return task.cont

    def moveMiles1AI(self, task):
        startpos = self.miles1.getPos()

        entries = []
        for i in range(self.miles1GroundHandler.getNumEntries()):
            entry = self.miles1GroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ()))

        if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"):
            miles1Z = entries[0].getSurfacePoint(render).getZ()
            miles1Y = entries[0].getSurfacePoint(render).getY()
            miles1X = entries[0].getSurfacePoint(render).getX()

            self.miles1.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.miles1.setPos(startpos)

        return task.cont

    def moveMiles2AI(self, task):
        startpos = self.miles2.getPos()

        entries = []
        for i in range(self.miles2GroundHandler.getNumEntries()):
            entry = self.miles2GroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ()))

        if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"):
            miles2Z = entries[0].getSurfacePoint(render).getZ()
            miles2Y = entries[0].getSurfacePoint(render).getY()
            miles2X = entries[0].getSurfacePoint(render).getX()

            self.miles2.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.miles2.setPos(startpos)

        return task.cont

    def moveTrexAI(self, task):

        startpos = self.trex.getPos()

        entries = []
        for i in range(self.trexGroundHandler.getNumEntries()):
            entry = self.trexGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ()))

        if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"):
            trexZ = entries[0].getSurfacePoint(render).getZ()
            trexY = entries[0].getSurfacePoint(render).getY()
            trexX = entries[0].getSurfacePoint(render).getX()

            self.trex.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.trex.setPos(startpos)

        return task.cont

    def setKey(self, action, value):
        self.keyMap[action] = value

    def move(self, task):

        base.camera.lookAt(self.sonic)
        if self.keyMap["cam-left"] != 0:
            base.camera.setX(base.camera, -30 * globalClock.getDt())
        if self.keyMap["cam-right"] != 0:
            base.camera.setX(base.camera, +30 * globalClock.getDt())

        startpos = self.sonic.getPos()

        if self.keyMap["left"] != 0:
            self.sonic.setH(self.sonic.getH() + 300 * globalClock.getDt())
        if self.keyMap["right"] != 0:
            self.sonic.setH(self.sonic.getH() - 300 * globalClock.getDt())
        if self.keyMap["forward"] != 0:
            self.sonic.setY(self.sonic, -100 * globalClock.getDt() * SPEED)
        if self.keyMap["backward"] != 0:
            self.sonic.setY(self.sonic, 100 * globalClock.getDt() * SPEED)

        # If sonic is moving, loop the run animation
        # If he is standing still, stop the animation
        if (
            (self.keyMap["forward"] != 0)
            or (self.keyMap["left"] != 0)
            or (self.keyMap["right"] != 0)
            or (self.keyMap["backward"] != 0)
        ):
            if self.isMoving is False:
                self.sonic.loop("board")
                self.isMoving = True
        else:
            if self.isMoving:
                self.sonic.stop()
                self.sonic.pose("fwboard", 5)
                self.isMoving = False

        # If the camera is too far from sonic, move it closer
        # If the camera is too close to sonic, move it farther

        camvec = self.sonic.getPos() - base.camera.getPos()
        camvec.setZ(0)
        camdist = camvec.length()
        camvec.normalize()
        if camdist > 10.0:
            base.camera.setPos(base.camera.getPos() + (camvec * (camdist - 10)))
            camdist = 10.0
        if camdist < 5.0:
            base.camera.setPos(base.camera.getPos() - (camvec * (5 - camdist)))
            camdist = 5.0

        # now check for collisions

        self.cTrav.traverse(render)

        entries = []
        for i in range(self.sonicGroundHandler.getNumEntries()):
            entry = self.sonicGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ()))

        if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.sonic.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.sonic.setPos(startpos)

        # keep the camera at one foot avoce the terrian
        # or two feet above sonic, whichever is greater

        entries = []
        for i in range(self.camGroundHandler.getNumEntries()):
            entry = self.camGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x, y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ()))

        if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"):
            base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0)

        if base.camera.getZ() < self.sonic.getZ() + 2.0:
            base.camera.setZ(self.sonic.getZ() + 2.0)

        # The camera should look in sonic's direction,
        # but it should also try to stay horizontal, so look at
        # a floater which hovers above sonic's head

        self.floater.setPos(self.sonic.getPos())
        self.floater.setZ(self.sonic.getZ() + 2.0)
        base.camera.lookAt(self.floater)

        # Update the camera based on mouse movement
        md = base.win.getPointer(0)
        x = md.getX()
        y = md.getY()
        if base.win.movePointer(0, base.win.getXSize() / 2, base.win.getYSize() / 2):
            base.camera.setX(base.camera, (x - base.win.getXSize() / 2) * globalClock.getDt() * 0.1)

        # timer countdown
        global TIME
        TIME = TOTAL_TIME - int(task.time)

        self.time_text.setText("Time Remaining :: %i" % TIME)

        return task.cont

    def checkWin(self, task):
        delta = self.sonic.getDistance(self.flag)
        if delta < 25:
            self.winText = OnscreenText(
                text="You Win!", style=1, fg=(1, 1, 1, 1), pos=(0, 0), align=TextNode.ACenter, scale=0.4
            )
            self.resetBtn = DirectButton(
                text=("Restart", "Restart", "Restart"), scale=0.1, command=self.resetGame, pos=(0, 0, -0.7)
            )

            taskMgr.remove("moveTask")
            if self.gameAudio.status() == self.gameAudio.PLAYING:
                self.gameAudio.stop()
                self.winAudio.play()
            return task.done
        return task.cont

    def checkTime(self, task):
        time_left = TIME
        if time_left == 0:
            taskMgr.remove("moveTask")
            self.gameOverText = OnscreenText(
                text="Game Over!", style=1, fg=(1, 1, 1, 1), pos=(0, 0), align=TextNode.ACenter, scale=0.4
            )
            self.resetBtn = DirectButton(
                text=("Restart", "Restart", "Restart"), scale=0.1, command=self.resetGame, pos=(0, 0, -0.7)
            )
            return task.done

        return task.cont

    def checkGameOver(self, task):
        health_left = HEALTH
        if 1 <= health_left <= 10:
            global SPEED
            SPEED = 0.5
        if health_left <= 0:
            taskMgr.remove("moveTask")
            self.gameOverText = OnscreenText(
                text="Game Over!", style=1, fg=(1, 1, 1, 1), pos=(0, 0), align=TextNode.ACenter, scale=0.4
            )
            self.resetBtn = DirectButton(
                text=("Restart", "Restart", "Restart"), scale=0.1, command=self.resetGame, pos=(0, 0, -0.7)
            )

            if self.gameAudio.status() == self.gameAudio.PLAYING:
                self.gameAudio.stop()
                self.loseAudio.play()
            return task.done
        return task.cont

    def resetGame(self):
        # re-add the move task
        taskMgr.add(self.move, "moveTask")

        # remove GUI elements
        if hasattr(game, "gameOverText"):
            self.gameOverText.destroy()
        if hasattr(game, "resetBtn"):
            self.resetBtn.destroy()
        if hasattr(game, "winText"):
            self.winText.destroy()

        if (self.winAudio.status() == self.winAudio.PLAYING) or (self.loseAudio.status() == self.loseAudio.PLAYING):
            self.winAudio.stop()
            self.loseAudio.stop()
            self.gameAudio.play()

        # reset position
        self.sonic.setPos(self.START)

        # reset time count
        global TIME, TOTAL_TIME
        TIME = 120
        TOTAL_TIME = 120

    def showMenu(self):
        # TODO: add more controls text
        self.startAudio.play()
        self.gameNameText = OnscreenText(
            text="Run, Baby, Run", style=1, fg=(1, 1, 1, 1), pos=(0, 0.5), align=TextNode.ACenter, scale=0.3
        )
        text = """
        Controls
        ===============
        [W] - Move Forward
        [A] - Move Left
        [S] - Move Backwards
        [D] - Move Right
        [<-] - Rotate Camera (Left)
        [->] - Rotate Camera (Right)

        Camera Movements are also controlled by mouse
        """
        self.controlsText = OnscreenText(
            text=text, style=1, fg=(1, 1, 1, 1), pos=(0, 0), align=TextNode.ACenter, scale=0.05
        )
        self.startBtn = DirectButton(
            text=("Start", "Start", "Start"), scale=0.1, command=self.startGame, pos=(0, 0, -0.7)
        )

    def checkConditions(self, task):
        trexDelta = self.sonic.getDistance(self.trex)
        miles1Delta = self.sonic.getDistance(self.miles1)
        miles2Delta = self.sonic.getDistance(self.miles2)
        if trexDelta <= 5 or miles1Delta <= 15 or miles2Delta <= 15:
            global HEALTH
            HEALTH = HEALTH - 1
            if HEALTH < 0:
                HEALTH = 0
            self.health_text.setText("Health :: %i" % HEALTH)

        return task.cont

    def checkSpeed(self, task):
        speedDelta = self.sonic.getDistance(self.speedPill)
        if speedDelta <= 30:
            global SPEED
            SPEED = SPEED + 1
            self.speedPill.removeNode()
            return task.done
        return task.cont

    def checkSpeed2(self, task):
        speedDelta2 = self.sonic.getDistance(self.speedPillb)
        if speedDelta2 <= 3720:
            global SPEED
            SPEED = SPEED + 1
            self.speedPillb.removeNode()
            return task.done
        return task.cont

    def checkHealthBoost(self, task):
        healthDelta = self.sonic.getDistance(self.banana)
        if healthDelta <= 3:
            global HEALTH
            HEALTH = HEALTH + 10
            if HEALTH > 100:
                HEALTH = 100
            self.banana.removeNode()
            self.health_text.setText("Health :: %i" % HEALTH)
            return task.done
        return task.cont

    def checkTimeAdd(self, task):
        timeAddDelta = self.sonic.getDistance(self.sphinx)
        if timeAddDelta <= 507:
            global TOTAL_TIME
            TOTAL_TIME = TOTAL_TIME + 10
            self.time_text.setText("Time Remaining :: %i" % TOTAL_TIME)
            self.sphinx.removeNode()
            return task.done
        return task.cont

    def startGame(self):
        # remove menu main elements
        if hasattr(game, "startBtn"):
            self.startBtn.destroy()
        if hasattr(game, "gameNameText"):
            self.gameNameText.destroy()
        if hasattr(game, "controlsText"):
            self.controlsText.destroy()
        if self.startAudio.status() == self.startAudio.PLAYING:
            self.startAudio.stop()
            self.gameAudio.play()

        # HUD information (time, health)
        self.time_text = addInstruction((-1.2, 0.9), "Time Reamining :: %i" % TIME)
        self.health_text = addInstruction((0.9, 0.9), "Health :: %i" % HEALTH)

        # the environment
        self.env = loader.loadModel("../assets/models/world")
        self.env.reparentTo(render)
        self.env.setPos(0, 0, 0)

        # the flag(destination)
        self.flag = loader.loadModel("../assets/models/flag/flag")
        self.flag.reparentTo(render)
        self.flag.setScale(0.1)
        self.flag.setPos(0, 0, 5)
        self.DESTINATION = self.flag.getPos()

        # main character(sonic)
        self.START = self.env.find("**/start_point").getPos()
        self.sonic = Actor(
            "../assets/models/sonic/sonic",
            {
                "run": "../assets/models/sonic/sonic-run",
                "win": "../assets/models/sonic/sonic-win",
                "board": "../assets/models/sonic/sonic-board",
                "fwboard": "../assets/models/sonic/sonic-fallingwboard",
                "fwoboard": "../assets/models/sonic/sonic-fallingwoboard",
            },
        )
        self.sonic.reparentTo(render)
        self.sonic.setScale(0.05)
        self.sonic.setPos(self.START)

        # create a floater object to be used as a temporary
        # variable in a variety of calculations
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        taskMgr.add(self.move, "moveTask")

        # varible to keep track of moving state
        self.isMoving = False

        # variable to keep track of speed boost
        self.speedBoost = False

        # variable to keep track of invulnerability
        self.invul = False

        # setup the camera
        base.disableMouse()
        base.camera.setPos(self.sonic.getX(), self.sonic.getY() + 10, 2)

        self.cTrav = CollisionTraverser()
        # self.pusher = CollisionHandlerPusher()

        self.sonicGroundRay = CollisionRay()
        self.sonicGroundRay.setOrigin(0, 0, 1000)
        self.sonicGroundRay.setDirection(0, 0, -1)
        self.sonicGroundCol = CollisionNode("sonicRay")
        self.sonicGroundCol.addSolid(self.sonicGroundRay)
        # self.sonicGroundCol.addSolid(CollisionSphere(0, 0, 1.5, 1.5))
        self.sonicGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.sonicGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.sonicGroundColNp = self.sonic.attachNewNode(self.sonicGroundCol)
        self.sonicGroundHandler = CollisionHandlerQueue()
        self.sonicPusher = CollisionHandlerPusher()
        self.sonicPusher.addInPattern("%fn-into-%in")
        self.cTrav.addCollider(self.sonicGroundColNp, self.sonicGroundHandler)
        # self.cTrav.addCollider(self.sonicGroundColNp, self.sonicPusher)
        # self.sonicPusher.addCollider(self.sonicGroundColNp, self.sonic)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0, 0, 1000)
        self.camGroundRay.setDirection(0, 0, -1)
        self.camGroundCol = CollisionNode("camRay")
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # see the collision rays
        # self.sonicGroundColNp.show()
        # self.camGroundColNp.show()

        # visual representation of the collisions occuring
        # self.cTrav.showCollisions(render)

        # create AI characters
        self.createTrexAI()
        self.createMilesAI()

        # place the presents
        self.createPresents()

        # check winning condition
        taskMgr.add(self.checkWin, "checkWin")

        # check time conditions
        taskMgr.add(self.checkTime, "checkTime")

        # check health conditions
        taskMgr.add(self.checkGameOver, "checkGameOver")

        # check other conditions
        taskMgr.add(self.checkConditions, "checkConditions")

        taskMgr.add(self.checkSpeed, "checkSpeed")
        taskMgr.add(self.checkSpeed2, "checkSpeed2")
        taskMgr.add(self.checkHealthBoost, "checkHealthBoost")
        taskMgr.add(self.checkTimeAdd, "checkTimeAdd")
예제 #27
0
class FriendsList(DirectFrame):
    notify = DirectNotifyGlobal.directNotify.newCategory('FriendsList')

    def __init__(self):
        DirectFrame.__init__(self, parent=base.a2dTopRight, pos=(-0.25, 0.0, -0.46))
        gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        self['image'] = gui.find('**/FriendsBox_Open')
        self.headingText = OnscreenText(text='', parent=self, pos=(0.01, 0.2), fg=(0.1, 0.1, 0.4, 1.0), scale=0.04)
        self.frameForNames = DirectScrolledList(frameSize=(0.0, 0.35, 0, 0.35), incButton_geom=(gui.find('**/FndsLst_ScrollUp'),
         gui.find('**/FndsLst_ScrollDN'),
         gui.find('**/FndsLst_ScrollUp_Rllvr'),
         gui.find('**/FndsLst_ScrollUp')), incButton_relief=None, incButton_hpr=(0, 0, 180), incButton_pos=(0.17, 0, -0.04), decButton_geom=(gui.find('**/FndsLst_ScrollUp'),
         gui.find('**/FndsLst_ScrollDN'),
         gui.find('**/FndsLst_ScrollUp_Rllvr'),
         gui.find('**/FndsLst_ScrollUp')), decButton_relief=None, decButton_pos=(0.17, 0, 0.395), pos=(-0.1625, 0.0, -0.27), parent=self, numItemsVisible=9, forceHeight=0.04, itemFrame_frameSize=(-0.15, 0.15, 0, -0.35), itemFrame_pos=(0, 0, 0.3275), itemFrame_relief=None, relief=None)
        self.fwdBtn = DirectButton(geom=(gui.find('**/Horiz_Arrow_UP'),
         gui.find('**/Horiz_Arrow_DN'),
         gui.find('**/Horiz_Arrow_Rllvr'),
         gui.find('**/Horiz_Arrow_UP')), relief=None, parent=self, pos=(0.17, 0.0, -0.38), command=self.doState)
        self.backBtn = DirectButton(geom=(gui.find('**/Horiz_Arrow_UP'),
         gui.find('**/Horiz_Arrow_DN'),
         gui.find('**/Horiz_Arrow_Rllvr'),
         gui.find('**/Horiz_Arrow_UP')), relief=None, parent=self, pos=(-0.15, 0.0, -0.38), hpr=(180, 0, 0), command=self.doState)
        self.closeBtn = DirectButton(geom=CIGlobals.getCancelBtnGeom(), relief=None, parent=self, command=self.exitClicked)
        self.closeBtn.setPos(0.015, 0.0, -0.375)
        gui.removeNode()
        del gui
        self.hide()
        self.friends = {}
        self.onlineFriends = {}
        self.fsm = ClassicFSM.ClassicFSM('FriendsList', [State.State('off', self.enterOff, self.exitOff), State.State('onlineFriendsList', self.enterOnlineFriendsList, self.exitOnlineFriendsList), State.State('allFriendsList', self.enterAllFriendsList, self.exitAllFriendsList)], 'off', 'off')
        self.fsm.enterInitialState()
        self.accept('gotFriendsList', self.handleFriendsList)
        return

    def destroy(self):
        self.ignore('gotFriendsList')
        self.fsm.requestFinalState()
        del self.fsm
        self.headingText.destroy()
        del self.headingText
        self.frameForNames.destroy()
        del self.frameForNames
        self.fwdBtn.destroy()
        del self.fwdBtn
        self.backBtn.destroy()
        del self.backBtn
        self.closeBtn.destroy()
        del self.closeBtn
        del self.friends
        del self.onlineFriends
        DirectFrame.destroy(self)

    def doState(self, state):
        self.fsm.request(state)

    def exitClicked(self):
        self.fsm.request('off')
        base.localAvatar.showFriendButton()

    def setButtons(self, fwd = None, back = None):
        if fwd:
            self.fwdBtn['extraArgs'] = [fwd]
            self.fwdBtn['state'] = DGG.NORMAL
        else:
            self.fwdBtn['extraArgs'] = []
            self.fwdBtn['state'] = DGG.DISABLED
        if back:
            self.backBtn['extraArgs'] = [back]
            self.backBtn['state'] = DGG.NORMAL
        else:
            self.backBtn['extraArgs'] = []
            self.backBtn['state'] = DGG.DISABLED

    def handleFriendsList(self, friendIdArray, nameArray, flags):
        self.friends = {}
        self.onlineFriends = {}
        for i in xrange(len(friendIdArray)):
            avatarId = friendIdArray[i]
            name = nameArray[i]
            self.friends[avatarId] = name
            if flags[i] == 1:
                self.onlineFriends[avatarId] = name

    def enterOff(self):
        self.hide()

    def exitOff(self):
        self.show()

    def addFriend(self, name, avatarId):
        self.frameForNames.addItem(DirectButton(text=name, extraArgs=[avatarId], command=self.friendClicked, scale=0.035, relief=None, text1_bg=textDownColor, text2_bg=textRolloverColor, text_align=TextNode.ALeft))
        return

    def friendClicked(self, avatarId):
        self.fsm.request('off')
        base.localAvatar.panel.makePanel(avatarId)

    def resetAll(self):
        self.headingText.setText('')
        self.frameForNames.removeAndDestroyAllItems()
        self.setButtons(None, None)
        return

    def sortListItems(self):
        self.frameForNames['items'].sort(key=lambda x: x['text'])
        self.frameForNames.refresh()

    def enterAllFriendsList(self):
        self.headingText.setText('All\nFriends')
        for friendId, name in self.friends.items():
            self.addFriend(name, friendId)

        self.sortListItems()
        self.setButtons(None, 'onlineFriendsList')
        return

    def exitAllFriendsList(self):
        self.resetAll()

    def enterOnlineFriendsList(self):
        self.headingText.setText('Online\nFriends')
        for friendId, name in self.onlineFriends.items():
            self.addFriend(name, friendId)

        self.sortListItems()
        self.setButtons('allFriendsList', None)
        return

    def exitOnlineFriendsList(self):
        self.resetAll()
예제 #28
0
class EventsPage(ShtikerPage.ShtikerPage):
    notify = DirectNotifyGlobal.directNotify.newCategory('EventsPage')

    def __init__(self):
        ShtikerPage.ShtikerPage.__init__(self)
        self.mode = EventsPage_Calendar
        self.setMode(self.mode)
        self.noTeleport = config.GetBool('Parties-page-disable', 0)
        self.isPrivate = True
        self.hostedPartyInfo = None
        return

    def load(self):
        self.scrollButtonGui = loader.loadModel('phase_3.5/models/gui/friendslist_gui')
        self.hostingGui = loader.loadModel('phase_4/models/parties/schtickerbookHostingGUI')
        self.invitationGui = loader.loadModel('phase_4/models/parties/schtickerbookInvitationGUI')
        self.activityIconsModel = loader.loadModel('phase_4/models/parties/eventSignIcons')
        self.decorationModels = loader.loadModel('phase_4/models/parties/partyDecorations')
        self.loadTabs()
        self.loadHostingTab()
        self.loadInvitationsTab()
        self.loadCalendarTab()
        self.titleLabel = DirectLabel(parent=self, relief=None, text=TTLocalizer.EventsPageHostTabTitle, text_scale=TTLocalizer.EPtitleLabel, textMayChange=True, pos=self.hostingGui.find('**/myNextParty_text_locator').getPos())
        return

    def loadTabs(self):
        normalColor = (1.0, 1.0, 1.0, 1.0)
        clickColor = (0.8, 0.8, 0.0, 1.0)
        rolloverColor = (0.15, 0.82, 1.0, 1.0)
        diabledColor = (1.0, 0.98, 0.15, 1.0)
        gui = loader.loadModel('phase_3.5/models/gui/fishingBook')
        self.hostTab = DirectButton(parent=self, relief=None, text=TTLocalizer.EventsPageHostTabName, text_scale=TTLocalizer.EPhostTab, text_align=TextNode.ACenter, text_pos=(0.12, 0.0), image=gui.find('**/tabs/polySurface1'), image_pos=(0.55, 1, -0.91), image_hpr=(0, 0, -90), image_scale=(0.033, 0.033, 0.035), image_color=normalColor, image1_color=clickColor, image2_color=rolloverColor, image3_color=diabledColor, text_fg=Vec4(0.2, 0.1, 0, 1), command=self.setMode, extraArgs=[EventsPage_Host], pos=(-0.13, 0, 0.775))
        self.invitedTab = DirectButton(parent=self, relief=None, text=TTLocalizer.EventsPageInvitedTabName, text_scale=TTLocalizer.EPinvitedTab, text_pos=(0.12, 0.0), text_align=TextNode.ACenter, image=gui.find('**/tabs/polySurface2'), image_pos=(0.12, 1, -0.91), image_hpr=(0, 0, -90), image_scale=(0.033, 0.033, 0.035), image_color=normalColor, image1_color=clickColor, image2_color=rolloverColor, image3_color=diabledColor, text_fg=Vec4(0.2, 0.1, 0, 1), command=self.setMode, extraArgs=[EventsPage_Invited], pos=(0.28, 0, 0.775))
        self.calendarTab = DirectButton(parent=self, relief=None, text=TTLocalizer.EventsPageCalendarTabName, text_scale=TTLocalizer.EPcalendarTab, text_pos=(0.12, 0.0), text_align=TextNode.ACenter, image=gui.find('**/tabs/polySurface2'), image_pos=(0.12, 1, -0.91), image_hpr=(0, 0, -90), image_scale=(0.033, 0.033, 0.035), image_color=normalColor, image1_color=clickColor, image2_color=rolloverColor, image3_color=diabledColor, text_fg=Vec4(0.2, 0.1, 0, 1), command=self.setMode, extraArgs=[EventsPage_Calendar], pos=(-0.55, 0, 0.775))
        return

    def loadHostingTab(self):
        self.hostedPartyDisplay = self.attachNewNode('Hosting')
        self.hostedPartyDisplay.setPos(0.0, 0.0, 0.04)
        self.hostingBackgroundFlat = DirectFrame(parent=self.hostedPartyDisplay, relief=None, geom=self.hostingGui.find('**/background_flat'))
        self.hostingGuestList, self.hostingGuestLabel = self.createListAndLabel(self.hostedPartyDisplay, self.hostingGui, 'guests', 7)
        self.hostingActivityList, self.hostingActivityLabel = self.createListAndLabel(self.hostedPartyDisplay, self.hostingGui, 'activities', 1)
        self.hostingDecorationList, self.hostingDecorationLabel = self.createListAndLabel(self.hostedPartyDisplay, self.hostingGui, 'decorations', 1)
        self.hostingDateLabel = DirectLabel(parent=self.hostedPartyDisplay, relief=None, text='', scale=TTLocalizer.EPhostingDateLabel, text_align=TextNode.ACenter, text_wordwrap=10, textMayChange=True, pos=self.hostingGui.find('**/date_locator').getPos())
        pos = self.hostingGui.find('**/cancel_text_locator').getPos()
        self.hostingCancelButton = DirectButton(parent=self.hostedPartyDisplay, relief=None, geom=(self.hostingGui.find('**/cancelPartyButton_up'),
         self.hostingGui.find('**/cancelPartyButton_down'),
         self.hostingGui.find('**/cancelPartyButton_rollover'),
         self.hostingGui.find('**/cancelPartyButton_inactive')), text=TTLocalizer.EventsPageHostTabCancelButton, text_scale=TTLocalizer.EPhostingCancelButton, text_pos=(pos[0], pos[2]), command=self.__doCancelParty)
        pos = self.hostingGui.find('**/startParty_text_locator').getPos()
        self.partyGoButton = DirectButton(parent=self.hostedPartyDisplay, relief=None, geom=(self.hostingGui.find('**/startPartyButton_up'),
         self.hostingGui.find('**/startPartyButton_down'),
         self.hostingGui.find('**/startPartyButton_rollover'),
         self.hostingGui.find('**/startPartyButton_inactive')), text=TTLocalizer.EventsPageGoButton, text_scale=TTLocalizer.EPpartyGoButton, text_pos=(pos[0], pos[2]), textMayChange=True, command=self._startParty)
        self.publicPrivateLabel = DirectLabel(parent=self.hostedPartyDisplay, relief=None, text=TTLocalizer.EventsPageHostTabPublicPrivateLabel, text_scale=TTLocalizer.EPpublicPrivateLabel, text_align=TextNode.ACenter, pos=self.hostingGui.find('**/thisPartyIs_text_locator').getPos())
        pos = self.hostingGui.find('**/public_text_locator').getPos()
        checkedImage = self.hostingGui.find('**/checked_button')
        uncheckedImage = self.hostingGui.find('**/unchecked_button')
        self.publicButton = DirectCheckButton(parent=self.hostedPartyDisplay, relief=None, scale=0.1, boxBorder=0.08, boxImage=(uncheckedImage, checkedImage, None), boxImageScale=10, boxRelief=None, text=TTLocalizer.EventsPageHostTabToggleToPublic, text_align=TextNode.ALeft, text_scale=TTLocalizer.EPpublicButton, pos=pos, command=self.__changePublicPrivate, indicator_pos=(-0.7, 0, 0.2))
        pos = self.hostingGui.find('**/private_text_locator').getPos()
        self.privateButton = DirectCheckButton(parent=self.hostedPartyDisplay, relief=None, scale=0.1, boxBorder=0.08, boxImage=(uncheckedImage, checkedImage, None), boxImageScale=10, boxRelief=None, text=TTLocalizer.EventsPageHostTabToggleToPrivate, text_align=TextNode.ALeft, text_scale=TTLocalizer.EPprivateButton, pos=pos, command=self.__changePublicPrivate, indicator_pos=(-0.7, 0, 0.2))
        self.confirmCancelPartyEvent = 'confirmCancelPartyEvent'
        self.accept(self.confirmCancelPartyEvent, self.confirmCancelOfParty)
        self.confirmCancelPartyGui = TTDialog.TTGlobalDialog(dialogName=self.uniqueName('confirmCancelPartyGui'), doneEvent=self.confirmCancelPartyEvent, message=TTLocalizer.EventsPageConfirmCancel % int(PartyGlobals.PartyRefundPercentage * 100.0), style=TTDialog.YesNo, okButtonText=OTPLocalizer.DialogYes, cancelButtonText=OTPLocalizer.DialogNo)
        self.confirmCancelPartyGui.doneStatus = ''
        self.confirmCancelPartyGui.hide()
        self.confirmTooLatePartyEvent = 'confirmTooLatePartyEvent'
        self.accept(self.confirmTooLatePartyEvent, self.confirmTooLateParty)
        self.confirmTooLatePartyGui = TTDialog.TTGlobalDialog(dialogName=self.uniqueName('confirmTooLatePartyGui'), doneEvent=self.confirmTooLatePartyEvent, message=TTLocalizer.EventsPageTooLateToStart, style=TTDialog.Acknowledge)
        self.confirmTooLatePartyGui.hide()
        self.confirmPublicPrivateChangeEvent = 'confirmPublicPrivateChangeEvent'
        self.accept(self.confirmPublicPrivateChangeEvent, self.confirmPublicPrivateChange)
        self.confirmPublicPrivateGui = TTDialog.TTGlobalDialog(dialogName=self.uniqueName('confirmPublicPrivateGui'), doneEvent=self.confirmPublicPrivateChangeEvent, message=TTLocalizer.EventsPagePublicPrivateNoGo, style=TTDialog.Acknowledge)
        self.confirmPublicPrivateGui.hide()
        self.cancelPartyResultGuiEvent = 'cancelPartyResultGuiEvent'
        self.accept(self.cancelPartyResultGuiEvent, self.cancelPartyResultGuiCommand)
        self.cancelPartyResultGui = TTDialog.TTGlobalDialog(dialogName=self.uniqueName('cancelPartyResultGui'), doneEvent=self.cancelPartyResultGuiEvent, message=TTLocalizer.EventsPageCancelPartyResultOk % 0, style=TTDialog.Acknowledge)
        self.cancelPartyResultGui.doneStatus = ''
        self.cancelPartyResultGui.hide()
        self.__setPublicPrivateButton()
        return

    def loadInvitationsTab(self):
        self.invitationDisplay = self.attachNewNode('invitations')
        self.invitationDisplay.setPos(0.0, 0.0, 0.04)
        self.invitationBackgroundFlat = DirectFrame(parent=self.invitationDisplay, relief=None, geom=self.invitationGui.find('**/background_flat'))
        self.invitationPartiesFlat = DirectFrame(parent=self.invitationDisplay, relief=None, geom=self.invitationGui.find('**/parties_background'))
        self.invitationActivtiesFlat = DirectFrame(parent=self.invitationDisplay, relief=None, geom=self.invitationGui.find('**/activities_background'))
        self.invitationPartyList, self.invitationPartyLabel = self.createListAndLabel(self.invitationDisplay, self.invitationGui, 'parties', 7, 'ButtonDown', 'ButtonUp', 'Text_locator')
        self.invitationActivityList, self.invitationActivityLabel = self.createListAndLabel(self.invitationDisplay, self.invitationGui, 'activities', 1, 'ButtonDown', 'ButtonUp', 'Text_locator')
        pos = self.invitationGui.find('**/startText_locator').getPos()
        self.invitePartyGoButton = DirectButton(parent=self.invitationDisplay, relief=None, geom=(self.invitationGui.find('**/startButton_up'),
         self.invitationGui.find('**/startButton_down'),
         self.invitationGui.find('**/startButton_rollover'),
         self.invitationGui.find('**/startButton_inactive')), text=TTLocalizer.EventsPageInviteGoButton, text_scale=TTLocalizer.EPinvitePartyGoButton, text_pos=(pos[0], pos[2]), textMayChange=True, command=self._inviteStartParty)
        self.invitationDateTimeLabel = DirectLabel(parent=self.invitationDisplay, relief=None, text='', textMayChange=True, text_scale=0.07, pos=(0, 0, -0.65))
        return

    def loadCalendarTab(self):
        self.calendarDisplay = self.attachNewNode('calendar')
        self.toontownTimeLabel = DirectLabel(parent=self.calendarDisplay, pos=(0.175, 0, -0.69), text_align=TextNode.ARight, relief=None, text=TTLocalizer.EventsPageToontownTimeIs, text_scale=0.065, text_font=ToontownGlobals.getMinnieFont(), text_fg=(255 / 255.0,
         146 / 255.0,
         113 / 255.0,
         1), textMayChange=0)
        self.calendarGuiMonth = None # To be set upon tab's first opening.
        pos = (0.35, 0, -0.69)
        self.toontownTimeGui = ServerTimeGui(self.calendarDisplay, pos)
        return

    def getGuestItem(self, name, inviteStatus):
        label = DirectLabel(relief=None, text=name, text_scale=0.045, text_align=TextNode.ALeft, textMayChange=True)
        dot = DirectFrame(relief=None, geom=self.hostingGui.find('**/questionMark'), pos=(0.5, 0.0, 0.01))
        if inviteStatus == PartyGlobals.InviteStatus.Accepted:
            dot['geom'] = (self.hostingGui.find('**/checkmark'),)
        elif inviteStatus == PartyGlobals.InviteStatus.Rejected:
            dot['geom'] = (self.hostingGui.find('**/x'),)
        PartyUtils.truncateTextOfLabelBasedOnWidth(label, name, PartyGlobals.EventsPageGuestNameMaxWidth)
        dot.reparentTo(label)
        return label

    def getActivityItem(self, activityBase, count = 1):
        activityName = TTLocalizer.PartyActivityNameDict[activityBase.activityId]['generic']
        if count == 1:
            textForActivity = activityName
        else:
            textForActivity = '%s x %d' % (activityName, count)
        iconString = PartyGlobals.ActivityIds.getString(activityBase.activityId)
        geom = getPartyActivityIcon(self.activityIconsModel, iconString)
        label = DirectLabel(relief=None, geom=geom, geom_scale=0.38, geom_pos=Vec3(0.0, 0.0, -0.17), text=textForActivity, text_scale=TTLocalizer.EPactivityItemLabel, text_align=TextNode.ACenter, text_pos=(-0.01, -0.43), text_wordwrap=7.0)
        return label

    def getDecorationItem(self, decorBase, count = 1):
        decorationName = TTLocalizer.PartyDecorationNameDict[decorBase.decorId]['editor']
        if count == 1:
            textForDecoration = decorationName
        else:
            textForDecoration = decorationName + ' x ' + str(count)
        assetName = PartyGlobals.DecorationIds.getString(decorBase.decorId)
        label = DirectLabel(relief=None, geom=self.decorationModels.find('**/partyDecoration_%s' % assetName), text=textForDecoration, text_scale=TTLocalizer.EPdecorationItemLabel, text_align=TextNode.ACenter, text_pos=(-0.01, -0.43), text_wordwrap=7.0)
        label['geom_scale'] = (2.6, 0.01, 0.05)
        label['geom_pos'] = (0.0, 0.0, -0.33)
        return label

    def getToonNameFromAvId(self, avId):
        result = TTLocalizer.EventsPageUnknownToon
        sender = base.cr.identifyAvatar(avId)
        if sender:
            result = sender.getName()
        return result

    def loadInvitations(self):
        EventsPage.notify.debug('loadInvitations')
        self.selectedInvitationItem = None
        self.invitationPartyList.removeAndDestroyAllItems()
        self.invitationActivityList.removeAndDestroyAllItems()
        self.invitePartyGoButton['state'] = DirectGuiGlobals.DISABLED
        for partyInfo in base.localAvatar.partiesInvitedTo:
            if partyInfo.status == PartyGlobals.PartyStatus.Cancelled or partyInfo.status == PartyGlobals.PartyStatus.Finished:
                continue
            inviteInfo = None
            for inviteInfo in base.localAvatar.invites:
                if partyInfo.partyId == inviteInfo.partyId:
                    break

            if inviteInfo is None:
                EventsPage.notify.error('No invitation info for party id %d' % partyInfo.partyId)
                return
            if inviteInfo.status == PartyGlobals.InviteStatus.NotRead:
                continue
            hostName = self.getToonNameFromAvId(partyInfo.hostId)
            item = DirectButton(relief=None, text=hostName, text_align=TextNode.ALeft, text_bg=Vec4(0.0, 0.0, 0.0, 0.0), text_scale=0.045, textMayChange=True, command=self.invitePartyClicked)
            PartyUtils.truncateTextOfLabelBasedOnWidth(item, hostName, PartyGlobals.EventsPageHostNameMaxWidth)
            item['extraArgs'] = [item]
            item.setPythonTag('activityIds', partyInfo.getActivityIds())
            item.setPythonTag('partyStatus', partyInfo.status)
            item.setPythonTag('hostId', partyInfo.hostId)
            item.setPythonTag('startTime', partyInfo.startTime)
            self.invitationPartyList.addItem(item)

        return

    def invitePartyClicked(self, item):
        if item.getPythonTag('partyStatus') == PartyGlobals.PartyStatus.Started:
            self.invitePartyGoButton['state'] = DirectGuiGlobals.NORMAL
        else:
            self.invitePartyGoButton['state'] = DirectGuiGlobals.DISABLED
        if self.selectedInvitationItem is not None:
            self.selectedInvitationItem['state'] = DirectGuiGlobals.NORMAL
            self.selectedInvitationItem['text_bg'] = Vec4(0.0, 0.0, 0.0, 0.0)
        self.selectedInvitationItem = item
        self.selectedInvitationItem['state'] = DirectGuiGlobals.DISABLED
        self.selectedInvitationItem['text_bg'] = Vec4(1.0, 1.0, 0.0, 1.0)
        self.fillInviteActivityList(item.getPythonTag('activityIds'))
        startTime = item.getPythonTag('startTime')
        self.invitationDateTimeLabel['text'] = TTLocalizer.EventsPageInvitedTabTime % (PartyUtils.formatDate(startTime.year, startTime.month, startTime.day), PartyUtils.formatTime(startTime.hour, startTime.minute))
        return

    def fillInviteActivityList(self, activityIds):
        self.invitationActivityList.removeAndDestroyAllItems()
        countDict = {}
        for actId in activityIds:
            if actId not in countDict:
                countDict[actId] = 1
            else:
                countDict[actId] += 1

        for activityId in countDict:
            if countDict[activityId] == 1:
                textOfActivity = TTLocalizer.PartyActivityNameDict[activityId]['generic']
            else:
                textOfActivity = TTLocalizer.PartyActivityNameDict[activityId]['generic'] + ' x ' + str(countDict[activityId])
            geom = getPartyActivityIcon(self.activityIconsModel, PartyGlobals.ActivityIds.getString(activityId))
            item = DirectLabel(relief=None, text=textOfActivity, text_align=TextNode.ACenter, text_scale=0.05, text_pos=(0.0, -0.15), geom_scale=0.3, geom_pos=Vec3(0.0, 0.0, 0.07), geom=geom)
            self.invitationActivityList.addItem(item)

        return

    def _inviteStartParty(self):
        if self.selectedInvitationItem is None:
            self.invitePartyGoButton['state'] = DirectGuiGlobals.DISABLED
            return
        self.doneStatus = {'mode': 'startparty',
         'firstStart': False,
         'hostId': self.selectedInvitationItem.getPythonTag('hostId')}
        messenger.send(self.doneEvent)
        return

    def loadHostedPartyInfo(self):
        self.unloadGuests()
        self.unloadActivities()
        self.unloadDecorations()
        self.hostedPartyInfo = None
        self.confirmCancelPartyGui.doneStatus = ''
        self.confirmCancelPartyGui.hide()
        self.cancelPartyResultGui.doneStatus = ''
        self.cancelPartyResultGui.hide()
        if base.localAvatar.hostedParties is not None and len(base.localAvatar.hostedParties) > 0:
            for partyInfo in base.localAvatar.hostedParties:
                if partyInfo.status == PartyGlobals.PartyStatus.Pending or partyInfo.status == PartyGlobals.PartyStatus.CanStart or partyInfo.status == PartyGlobals.PartyStatus.NeverStarted or partyInfo.status == PartyGlobals.PartyStatus.Started:
                    self.hostedPartyInfo = partyInfo
                    self.loadGuests()
                    self.loadActivities()
                    self.loadDecorations()
                    self.hostingDateLabel['text'] = TTLocalizer.EventsPageHostTabDateTimeLabel % (PartyUtils.formatDate(partyInfo.startTime.year, partyInfo.startTime.month, partyInfo.startTime.day), PartyUtils.formatTime(partyInfo.startTime.hour, partyInfo.startTime.minute))
                    self.isPrivate = partyInfo.isPrivate
                    self.__setPublicPrivateButton()
                    if partyInfo.status == PartyGlobals.PartyStatus.CanStart:
                        self.partyGoButton['state'] = DirectGuiGlobals.NORMAL
                        self.partyGoButton['text'] = (TTLocalizer.EventsPageGoButton,)
                    elif partyInfo.status == PartyGlobals.PartyStatus.Started:
                        place = base.cr.playGame.getPlace()
                        if isinstance(place, Party):
                            if hasattr(base, 'distributedParty'):
                                if base.distributedParty.partyInfo.hostId == base.localAvatar.doId:
                                    self.partyGoButton['state'] = DirectGuiGlobals.DISABLED
                                else:
                                    self.partyGoButton['state'] = DirectGuiGlobals.NORMAL
                            else:
                                self.partyGoButton['state'] = DirectGuiGlobals.NORMAL
                                self.notify.warning('base.distributedParty is not defined when base.cr.playGame.getPlace is party. This should never happen.')
                        else:
                            self.partyGoButton['state'] = DirectGuiGlobals.NORMAL
                        self.partyGoButton['text'] = (TTLocalizer.EventsPageGoBackButton,)
                    else:
                        self.partyGoButton['text'] = (TTLocalizer.EventsPageGoButton,)
                        self.partyGoButton['state'] = DirectGuiGlobals.DISABLED
                    if partyInfo.status not in (PartyGlobals.PartyStatus.Pending, PartyGlobals.PartyStatus.CanStart):
                        self.hostingCancelButton['state'] = DirectGuiGlobals.DISABLED
                    else:
                        self.hostingCancelButton['state'] = DirectGuiGlobals.NORMAL
                    self.hostingDateLabel.show()
                    self.hostedPartyDisplay.show()
                    return

        self.hostingDateLabel['text'] = TTLocalizer.EventsPageHostingTabNoParty
        self.hostingCancelButton['state'] = DirectGuiGlobals.DISABLED
        self.partyGoButton['state'] = DirectGuiGlobals.DISABLED
        self.publicButton['state'] = DirectGuiGlobals.DISABLED
        self.privateButton['state'] = DirectGuiGlobals.DISABLED
        self.hostedPartyDisplay.show()
        return

    def checkCanStartHostedParty(self):
        result = True
        if self.hostedPartyInfo.endTime < base.cr.toontownTimeManager.getCurServerDateTime() and self.hostedPartyInfo.status == PartyGlobals.PartyStatus.CanStart:
            result = False
            self.confirmTooLatePartyGui.show()
        return result

    def confirmTooLateParty(self):
        if hasattr(self, 'confirmTooLatePartyGui'):
            self.confirmTooLatePartyGui.hide()

    def confirmPublicPrivateChange(self):
        if hasattr(self, 'confirmPublicPrivateGui'):
            self.confirmPublicPrivateGui.hide()

    def _startParty(self):
        if not self.checkCanStartHostedParty():
            return
        if self.hostedPartyInfo.status == PartyGlobals.PartyStatus.CanStart:
            firstStart = True
        else:
            firstStart = False
        self.doneStatus = {'mode': 'startparty',
         'firstStart': firstStart,
         'hostId': None}
        messenger.send(self.doneEvent)
        return

    def loadGuests(self):
        for partyReplyInfoBase in base.localAvatar.partyReplyInfoBases:
            if partyReplyInfoBase.partyId == self.hostedPartyInfo.partyId:
                for singleReply in partyReplyInfoBase.replies:
                    toonName = self.getToonNameFromAvId(singleReply.inviteeId)
                    self.hostingGuestList.addItem(self.getGuestItem(toonName, singleReply.status))

    def loadActivities(self):
        countDict = {}
        for activityBase in self.hostedPartyInfo.activityList:
            if activityBase.activityId not in countDict:
                countDict[activityBase.activityId] = 1
            else:
                countDict[activityBase.activityId] += 1

        idsUsed = []
        for activityBase in self.hostedPartyInfo.activityList:
            if activityBase.activityId not in idsUsed:
                idsUsed.append(activityBase.activityId)
                count = countDict[activityBase.activityId]
                self.hostingActivityList.addItem(self.getActivityItem(activityBase, count))

    def loadDecorations(self):
        countDict = {}
        for decorBase in self.hostedPartyInfo.decors:
            if decorBase.decorId not in countDict:
                countDict[decorBase.decorId] = 1
            else:
                countDict[decorBase.decorId] += 1

        idsUsed = []
        for decorBase in self.hostedPartyInfo.decors:
            if decorBase.decorId not in idsUsed:
                count = countDict[decorBase.decorId]
                self.hostingDecorationList.addItem(self.getDecorationItem(decorBase, count))
                idsUsed.append(decorBase.decorId)

    def unloadGuests(self):
        self.hostingGuestList.removeAndDestroyAllItems()

    def unloadActivities(self):
        self.hostingActivityList.removeAndDestroyAllItems()

    def unloadDecorations(self):
        self.hostingDecorationList.removeAndDestroyAllItems()

    def unload(self):
        self.scrollButtonGui.removeNode()
        self.hostingGui.removeNode()
        self.invitationGui.removeNode()
        self.activityIconsModel.removeNode()
        self.decorationModels.removeNode()
        del self.titleLabel
        self.hostingGuestList.removeAndDestroyAllItems()
        self.hostingGuestList.destroy()
        del self.hostingGuestList
        self.hostingActivityList.removeAndDestroyAllItems()
        self.hostingActivityList.destroy()
        del self.hostingActivityList
        self.hostingDecorationList.removeAndDestroyAllItems()
        self.hostingDecorationList.destroy()
        del self.hostingDecorationList
        self.invitationPartyList.removeAndDestroyAllItems()
        self.invitationPartyList.destroy()
        del self.invitationPartyList
        self.invitationActivityList.removeAndDestroyAllItems()
        self.invitationActivityList.destroy()
        del self.invitationActivityList
        self.confirmCancelPartyGui.cleanup()
        del self.confirmCancelPartyGui
        self.confirmTooLatePartyGui.cleanup()
        del self.confirmTooLatePartyGui
        self.confirmPublicPrivateGui.cleanup()
        del self.confirmPublicPrivateGui
        self.ignore('changePartyPrivateResponseReceived')
        taskMgr.remove('changePartyPrivateResponseReceivedTimeOut')
        self.cancelPartyResultGui.cleanup()
        del self.cancelPartyResultGui
        self.ignore(self.confirmCancelPartyEvent)
        self.ignore(self.cancelPartyResultGuiEvent)
        self.avatar = None
        self.hostingCancelButton.destroy()
        del self.hostingCancelButton
        self.partyGoButton.destroy()
        del self.partyGoButton
        self.publicButton.destroy()
        del self.publicButton
        self.privateButton.destroy()
        del self.privateButton
        self.invitePartyGoButton.destroy()
        del self.invitePartyGoButton
        self.hostTab.destroy()
        self.invitedTab.destroy()
        self.calendarTab.destroy()
        if self.calendarGuiMonth:
            self.calendarGuiMonth.destroy()
        self.toontownTimeGui.destroy()
        taskMgr.remove('EventsPageUpdateTask-doLater')
        ShtikerPage.ShtikerPage.unload(self)
        return

    def enter(self):
        self.updatePage()
        ShtikerPage.ShtikerPage.enter(self)

    def exit(self):
        ShtikerPage.ShtikerPage.exit(self)
        self.unloadGuests()
        self.unloadActivities()
        self.unloadDecorations()

    def __handleConfirm(self):
        self.ignore('confirmDone')
        self.confirm.cleanup()
        del self.confirm

    def createListAndLabel(self, parent, gui, typeString, itemsVisible, downString = 'DownArrow', upString = 'UpArrow', textString = '_text_locator'):
        list = DirectScrolledList(parent=parent, relief=None, incButton_image=(gui.find('**/%s%s_up' % (typeString, downString)),
         gui.find('**/%s%s_down' % (typeString, downString)),
         gui.find('**/%s%s_rollover' % (typeString, downString)),
         gui.find('**/%s%s_inactive' % (typeString, downString))), incButton_relief=None, decButton_image=(gui.find('**/%s%s_up' % (typeString, upString)),
         gui.find('**/%s%s_down' % (typeString, upString)),
         gui.find('**/%s%s_rollover' % (typeString, upString)),
         gui.find('**/%s%s_inactive' % (typeString, upString))), decButton_relief=None, itemFrame_pos=gui.find('**/%s_locator' % typeString).getPos(), itemFrame_relief=None, numItemsVisible=itemsVisible, forceHeight=0.07)
        strings = {'guests': TTLocalizer.EventsPageHostingTabGuestListTitle,
         'activities': TTLocalizer.EventsPageHostingTabActivityListTitle,
         'decorations': TTLocalizer.EventsPageHostingTabDecorationsListTitle,
         'parties': TTLocalizer.EventsPageHostingTabPartiesListTitle}
        label = DirectLabel(parent=parent, relief=None, text=strings[typeString], text_scale=TTLocalizer.EPcreateListAndLabel, pos=gui.find('**/%s%s' % (typeString, textString)).getPos())
        return (list, label)

    def setMode(self, mode, updateAnyways = 0):
        messenger.send('wakeup')
        if updateAnyways == False:
            if self.mode == mode:
                return
            else:
                self.mode = mode
        self.show()
        self.updatePage()

    def getMode(self):
        return self.mode

    def updatePage(self):
        if self.mode == EventsPage_Host:
            self.hostTab['state'] = DirectGuiGlobals.DISABLED
            self.invitedTab['state'] = DirectGuiGlobals.NORMAL
            self.calendarTab['state'] = DirectGuiGlobals.NORMAL
            self.invitationDisplay.hide()
            self.hostedPartyDisplay.show()
            self.calendarDisplay.hide()
            self.loadHostedPartyInfo()
            if self.hostedPartyInfo is None:
                self.titleLabel['text'] = TTLocalizer.EventsPageHostTabTitleNoParties
            else:
                self.titleLabel['text'] = TTLocalizer.EventsPageHostTabTitle
        elif self.mode == EventsPage_Invited:
            self.titleLabel['text'] = TTLocalizer.EventsPageInvitedTabTitle
            self.hostTab['state'] = DirectGuiGlobals.NORMAL
            self.invitedTab['state'] = DirectGuiGlobals.DISABLED
            self.calendarTab['state'] = DirectGuiGlobals.NORMAL
            self.hostedPartyDisplay.hide()
            self.invitationDisplay.show()
            self.calendarDisplay.hide()
            self.loadInvitations()
        elif self.mode == EventsPage_Calendar:
            self.titleLabel['text'] = ''
            self.hostTab['state'] = DirectGuiGlobals.NORMAL
            self.invitedTab['state'] = DirectGuiGlobals.NORMAL
            self.calendarTab['state'] = DirectGuiGlobals.DISABLED
            self.hostedPartyDisplay.hide()
            self.invitationDisplay.hide()
            self.calendarDisplay.show()
            if not self.calendarGuiMonth:
                curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
                self.calendarGuiMonth = CalendarGuiMonth(self.calendarDisplay, curServerDate, onlyFutureMonthsClickable=True)
            self.calendarGuiMonth.changeMonth(0)
        return

    def __setPublicPrivateButton(self):
        if self.isPrivate:
            self.privateButton['indicatorValue'] = True
            self.publicButton['indicatorValue'] = False
            self.privateButton['state'] = DirectGuiGlobals.DISABLED
            self.publicButton['state'] = DirectGuiGlobals.NORMAL
        else:
            self.privateButton['indicatorValue'] = False
            self.publicButton['indicatorValue'] = True
            self.privateButton['state'] = DirectGuiGlobals.NORMAL
            self.publicButton['state'] = DirectGuiGlobals.DISABLED

    def __changePublicPrivate(self, indicator):
        self.__setPublicPrivateButton()
        self.confirmPublicPrivateGui['text'] = TTLocalizer.EventsPagePublicPrivateChange
        self.confirmPublicPrivateGui.buttonList[0].hide()
        self.confirmPublicPrivateGui.show()
        base.cr.partyManager.sendChangePrivateRequest(self.hostedPartyInfo.partyId, not self.isPrivate)
        self.accept('changePartyPrivateResponseReceived', self.changePartyPrivateResponseReceived)
        taskMgr.doMethodLater(5.0, self.changePartyPrivateResponseReceived, 'changePartyPrivateResponseReceivedTimeOut', [0, 0, PartyGlobals.ChangePartyFieldErrorCode.DatabaseError])

    def changePartyPrivateResponseReceived(self, partyId, newPrivateStatus, errorCode):
        EventsPage.notify.debug('changePartyPrivateResponseReceived called with partyId = %d, newPrivateStatus = %d, errorCode = %d' % (partyId, newPrivateStatus, errorCode))
        taskMgr.remove('changePartyPrivateResponseReceivedTimeOut')
        self.ignore('changePartyPrivateResponseReceived')
        if errorCode == PartyGlobals.ChangePartyFieldErrorCode.AllOk:
            self.isPrivate = newPrivateStatus
            self.confirmPublicPrivateGui.hide()
        else:
            self.confirmPublicPrivateGui.buttonList[0].show()
            if errorCode == PartyGlobals.ChangePartyFieldErrorCode.AlreadyStarted:
                self.confirmPublicPrivateGui['text'] = TTLocalizer.EventsPagePublicPrivateAlreadyStarted
            else:
                self.confirmPublicPrivateGui['text'] = TTLocalizer.EventsPagePublicPrivateNoGo
        self.__setPublicPrivateButton()

    def __doCancelParty(self):
        if self.hostedPartyInfo:
            if self.hostedPartyInfo.status == PartyGlobals.PartyStatus.Pending or self.hostedPartyInfo.status == PartyGlobals.PartyStatus.CanStart or self.hostedPartyInfo.status == PartyGlobals.PartyStatus.NeverStarted:
                self.hostingCancelButton['state'] = DirectGuiGlobals.DISABLED
                self.confirmCancelPartyGui.show()

    def confirmCancelOfParty(self):
        self.confirmCancelPartyGui.hide()
        if self.confirmCancelPartyGui.doneStatus == 'ok':
            base.cr.partyManager.sendChangePartyStatusRequest(self.hostedPartyInfo.partyId, PartyGlobals.PartyStatus.Cancelled)
            self.accept('changePartyStatusResponseReceived', self.changePartyStatusResponseReceived)
        else:
            self.hostingCancelButton['state'] = DirectGuiGlobals.NORMAL

    def changePartyStatusResponseReceived(self, partyId, newPartyStatus, errorCode, beansRefunded):
        EventsPage.notify.debug('changePartyStatusResponseReceived called with partyId = %d, newPartyStatus = %d, errorCode = %d' % (partyId, newPartyStatus, errorCode))
        if errorCode == PartyGlobals.ChangePartyFieldErrorCode.AllOk:
            if newPartyStatus == PartyGlobals.PartyStatus.Cancelled:
                self.loadHostedPartyInfo()
                self.cancelPartyResultGui['text'] = TTLocalizer.EventsPageCancelPartyResultOk % beansRefunded
                self.cancelPartyResultGui.show()
        elif errorCode == PartyGlobals.ChangePartyFieldErrorCode.AlreadyRefunded and newPartyStatus == PartyGlobals.PartyStatus.NeverStarted:
            self.loadHostedPartyInfo()
            self.cancelPartyResultGui['text'] = TTLocalizer.EventsPageCancelPartyAlreadyRefunded
            self.cancelPartyResultGui.show()
        else:
            self.cancelPartyResultGui['text'] = TTLocalizer.EventsPageCancelPartyResultError
            self.cancelPartyResultGui.show()
            self.hostingCancelButton['state'] = DirectGuiGlobals.NORMAL

    def cancelPartyResultGuiCommand(self):
        self.cancelPartyResultGui.hide()

    def updateToontownTime(self):
        self.toontownTimeGui.updateTime()
class FriendsList(DirectFrame):
    notify = DirectNotifyGlobal.directNotify.newCategory("FriendsList")

    GRAYED_OUT_COLOR = (128.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0, 1.0)
    NORMAL_COLOR = (1.0, 1.0, 1.0, 1.0)

    def __init__(self):
        DirectFrame.__init__(self,
                             parent=base.a2dTopRight,
                             pos=(-0.2235, 0.0, -0.457))
        gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        self['image'] = gui.find('**/FriendsBox_Open')

        self.headingText = OnscreenText(text="",
                                        parent=self,
                                        pos=(0.01, 0.2),
                                        fg=(0.1, 0.1, 0.4, 1.0),
                                        scale=0.04)

        self.frameForNames = DirectScrolledList(
            frameSize=(0.0, 0.35, 0, 0.35),
            incButton_geom=(gui.find('**/FndsLst_ScrollUp'),
                            gui.find('**/FndsLst_ScrollDN'),
                            gui.find('**/FndsLst_ScrollUp_Rllvr'),
                            gui.find('**/FndsLst_ScrollUp')),
            incButton_relief=None,
            incButton_hpr=(0, 0, 180),
            incButton_pos=(0.17, 0, -0.04),
            decButton_geom=(gui.find('**/FndsLst_ScrollUp'),
                            gui.find('**/FndsLst_ScrollDN'),
                            gui.find('**/FndsLst_ScrollUp_Rllvr'),
                            gui.find('**/FndsLst_ScrollUp')),
            decButton_relief=None,
            decButton_pos=(0.17, 0, 0.395),
            pos=(-0.1625, 0.0, -0.27),
            parent=self,
            numItemsVisible=9,
            forceHeight=0.04,
            itemFrame_frameSize=(-0.15, 0.15, 0, -0.35),
            itemFrame_pos=(0, 0, 0.3275),
            itemFrame_relief=None,
            relief=None)

        self.fwdBtn = CIGlobals.makeDirectionalBtn(1,
                                                   self, (0.17, 0.0, -0.38),
                                                   command=self.doState)
        self.backBtn = CIGlobals.makeDirectionalBtn(0,
                                                    self, (-0.15, 0.0, -0.38),
                                                    command=self.doState)

        self.closeBtn = DirectButton(geom=CIGlobals.getCancelBtnGeom(),
                                     relief=None,
                                     parent=self,
                                     command=self.exitClicked)
        self.closeBtn.setPos(0.015, 0.0, -0.375)

        gui.removeNode()
        del gui

        self.hide()

        self.friends = {}
        self.onlineFriends = {}

        self.fsm = ClassicFSM.ClassicFSM('FriendsList', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('onlineFriendsList', self.enterOnlineFriendsList,
                        self.exitOnlineFriendsList),
            State.State('allFriendsList', self.enterAllFriendsList,
                        self.exitAllFriendsList)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.accept('gotFriendsList', self.handleFriendsList)

    def destroy(self):
        self.ignore('gotFriendsList')
        self.fsm.requestFinalState()
        del self.fsm
        self.headingText.destroy()
        del self.headingText
        self.frameForNames.destroy()
        del self.frameForNames
        self.fwdBtn.destroy()
        del self.fwdBtn
        self.backBtn.destroy()
        del self.backBtn
        self.closeBtn.destroy()
        del self.closeBtn
        del self.friends
        del self.onlineFriends
        DirectFrame.destroy(self)

    def doState(self, state):
        self.fsm.request(state)

    def exitClicked(self):
        self.fsm.request('off')
        base.localAvatar.showFriendButton()

    def setButtons(self, fwd=None, back=None):
        if fwd:
            self.fwdBtn['extraArgs'] = [fwd]
            self.fwdBtn['state'] = DGG.NORMAL
            self.fwdBtn.setColorScale(self.NORMAL_COLOR)
        else:
            self.fwdBtn['extraArgs'] = []
            self.fwdBtn['state'] = DGG.DISABLED
            self.fwdBtn.setColorScale(self.GRAYED_OUT_COLOR)

        if back:
            self.backBtn['extraArgs'] = [back]
            self.backBtn['state'] = DGG.NORMAL
            self.backBtn.setColorScale(self.NORMAL_COLOR)
        else:
            self.backBtn['extraArgs'] = []
            self.backBtn['state'] = DGG.DISABLED
            self.backBtn.setColorScale(self.GRAYED_OUT_COLOR)

        if self.frameForNames.incButton['state'] == DGG.DISABLED:
            self.frameForNames.incButton.setColorScale(self.GRAYED_OUT_COLOR)
        else:
            self.frameForNames.incButton.setColorScale(self.NORMAL_COLOR)

        if self.frameForNames.decButton['state'] == DGG.DISABLED:
            self.frameForNames.decButton.setColorScale(self.GRAYED_OUT_COLOR)
        else:
            self.frameForNames.decButton.setColorScale(self.NORMAL_COLOR)

    def handleFriendsList(self, friendIdArray, nameArray, flags, accessLevels):
        self.friends = {}
        self.onlineFriends = {}
        for i in xrange(len(friendIdArray)):
            avatarId = friendIdArray[i]
            name = nameArray[i]
            accessLevel = accessLevels[i]
            self.friends[avatarId] = [name, accessLevel]
            if flags[i] == 1:
                # This friend is online
                self.onlineFriends[avatarId] = [name, accessLevel]

    def enterOff(self):
        self.hide()

    def exitOff(self):
        self.show()

    def addFriend(self, name, avatarId, accessLevel):
        text_fg = AdminCommands.Roles.get(
            accessLevel
        ).token.color if accessLevel > AdminCommands.NoAccess else (0, 0, 0, 1)
        self.frameForNames.addItem(
            DirectButton(text=name,
                         extraArgs=[avatarId],
                         command=self.friendClicked,
                         scale=0.035,
                         relief=None,
                         text_fg=text_fg,
                         text1_bg=textDownColor,
                         text2_bg=textRolloverColor,
                         text_align=TextNode.ALeft))

    def friendClicked(self, avatarId):
        base.localAvatar.panel.makePanel(avatarId)

    def maybeShowList(self):
        if self.isHidden() and self.fsm.getCurrentState().getName() != 'off':
            base.localAvatar.hideFriendButton()
            self.show()

    def resetAll(self):
        self.headingText.setText("")
        self.frameForNames.removeAndDestroyAllItems()
        self.setButtons(None, None)

    def sortListItems(self):
        self.frameForNames['items'].sort(key=lambda x: x['text'])
        self.frameForNames.refresh()

    def enterAllFriendsList(self):
        self.headingText.setText("ALL\nFRIENDS")
        for friendId, data in self.friends.items():
            name = data[0]
            accessLevel = data[1]
            self.addFriend(name, friendId, accessLevel)
        self.sortListItems()
        self.setButtons(None, 'onlineFriendsList')

    def exitAllFriendsList(self):
        self.resetAll()

    def enterOnlineFriendsList(self):
        self.headingText.setText("ONLINE\nFRIENDS")
        for friendId, data in self.onlineFriends.items():
            name = data[0]
            accessLevel = data[1]
            self.addFriend(name, friendId, accessLevel)
        self.sortListItems()
        self.setButtons('allFriendsList', None)

    def exitOnlineFriendsList(self):
        self.resetAll()
예제 #30
0
파일: obj_animals.py 프로젝트: s2t2/SNAP
    def run(self):
        self.implicit_markers = False
        base.win.setClearColor((0, 0, 0, 1))

        self.marker(
            0)  # Send one event to trigger the whole event sending process

        if self.training:
            self.stimuli_order = self.stimuli_order[:16]
            self.n_blocks = 1
            self.n_runs = 1

        if self.av_type == 'auditory':
            self.file_list = [
                'studies/obj_animals/stimuli/' + k.strip() + '_f.wav'
                for k in self.stimuli
            ]
            for f in self.file_list:
                self.precache_sound(f)
        self.precache_sound('buzz.wav')
        self.precache_sound('beep.wav')

        # Define text properties
        tp_gray = TextProperties()
        tp_gray.setTextColor(0.5, 0.5, 0.5, 1)
        tpMgr = TextPropertiesManager.getGlobalPtr()
        tpMgr.setProperties("gray", tp_gray)

        # Show instructions
        if self.training:
            if self.av_type == 'visual':
                verb = 'see'
            else:
                verb = 'hear'
            self.write(
                'This is a word association experiment.\nYou will complete several trials in this block.\n\n'
                + '\1gray\1[Press Space to continue]\2',
                fg=(1, 1, 1, 1),
                duration='space',
                align='left',
                pos=(-0.5, 0),
                scale=0.05)
            self.write(
                'The experiment consists of two conditions.\nIn each trial, ' +
                'you will be prompted to perform\none of these two tasks:\n' +
                '(1) touch a button on the screen,\n' +
                '(2) press the space bar.\n\n\1gray\1[Press Space to continue]\2',
                fg=(1, 1, 1, 1),
                duration='space',
                align='left',
                pos=(-0.5, 0),
                scale=0.05)
            self.write(
                'In each trial, you will ' + verb +
                ' a word.\nWhen the word is an animal,\n' +
                'touch the button on the screen.\n\n\1gray\1[Press Space to continue]\2',
                fg=(1, 1, 1, 1),
                duration='space',
                align='left',
                pos=(-0.5, 0),
                scale=0.05)
            self.write(
                'When the word is an object,\npress the space bar.\n\n\1gray\1[Press Space to continue]\2',
                fg=(1, 1, 1, 1),
                duration='space',
                align='left',
                pos=(-0.5, 0),
                scale=0.05)
            self.write(
                'You will hear a beep for correct answers.\nYou will hear a buzz for incorrect answers.\n\n\1gray\1[Press Space to continue]\2',
                fg=(1, 1, 1, 1),
                duration='space',
                align='left',
                pos=(-0.5, 0),
                scale=0.05)
        self.write('When you are ready,\npress the space bar to begin.' +
                   '\n\n\1gray\1[Press Space to continue]\2',
                   fg=(1, 1, 1, 1),
                   duration='space',
                   align='left',
                   pos=(-0.5, 0),
                   scale=0.05)

        t = time.localtime()
        t_str = '-'.join([
            str(k) for k in
            [t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec]
        ])
        f = open('studies/obj_animals/log/' + t_str + '.txt', 'w')
        f.write('Stimulus No.\tStimulus\tCategory\tButton position\tScore\n')
        self.sleep(5)

        counter = 0  # Needed for breaks between blocks

        for k in self.stimuli_order:

            # Short break
            if not self.training and counter in xrange(
                    len(self.stimuli_order) / self.n_blocks / 2,
                    len(self.stimuli_order),
                    len(self.stimuli_order) / self.n_blocks / 2):
                self.write('Time for a short break.\n\n' +
                           '\1gray\1[Press Space to continue]\2',
                           fg=(1, 1, 1, 1),
                           duration='space',
                           align='left',
                           pos=(-0.5, 0),
                           scale=0.05)
                self.sleep(2)

            counter += 1

            # I have to calculate button positions in case the window size changed
            ar = base.getAspectRatio()
            button_frame = (-ar / 9, ar / 9, -1.0 / 4, 1.0 / 4)
            buttons = []
            for k1 in xrange(2, 7):
                for k2 in xrange(4):
                    buttons.append((-ar + ar / 9 + k1 * ar / 4.5, 0,
                                    1 - 1.0 / 4 - k2 / 2.0))
            # Delete middle buttons
            del buttons[5:7]
            del buttons[7:9]
            del buttons[9:11]

            choice = random.randint(0, len(buttons) - 1)
            button = buttons[choice]
            f.write(
                str(k) + '\t' + self.stimuli[k].strip() + '\t' +
                self.conditions[self.target[k]] + '\t' + str(choice) + '\t')

            # Visual or auditory presentation
            if self.av_type == 'auditory':
                self.sound(self.file_list[k], volume=0.5)
                self.sleep(0.2)
                self.write('+',
                           duration=self.isi - self.pause,
                           block=False,
                           scale=0.15,
                           fg=(1, 1, 1, 1))
            elif self.av_type == 'visual':
                self.sleep(0.2)
                self.write(self.stimuli[k],
                           duration=self.isi - self.pause,
                           block=False,
                           scale=0.15,
                           fg=(1, 1, 1, 1))

            self.marker(k + 10000)
            btn = DirectButton(frameSize=button_frame,
                               pos=button,
                               frameColor=(0.75, 0, 0, 1),
                               borderWidth=(0.01, 0.01),
                               rolloverSound=None,
                               clickSound=None,
                               command=messenger.send,
                               extraArgs=('button_pressed', ))

            latencies = self.waitfor_multiple(['button_pressed', 'space'],
                                              self.isi)
            if not latencies:
                response = 'none'
                wait_time = self.pause
                self.sound('buzz.wav', volume=0.5)
            else:
                response = latencies[0]
                wait_time = self.pause + self.isi - latencies[1]
                if self.target[
                        k] == 1 and response == 'button_pressed':  # Check if values in dictionary are not empty
                    self.score += int(100 * (self.isi - latencies[1]) /
                                      self.isi)
                    self.sound('beep.wav', volume=0.5)
                elif self.target[k] == 0 and response == 'space':
                    self.score += int(10 * (self.isi - latencies[1]) /
                                      self.isi)
                    self.sound('beep.wav', volume=0.5)
                elif (self.target[k] == 1 and response == 'space') or (
                        self.target[k] == 0 and response == 'button_pressed'):
                    self.score -= 5
                    if self.score < 0:
                        self.score = 0
                    self.sound('buzz.wav', volume=0.5)

            f.write(str(self.score) + '\n')
            try:
                btn.destroy()
            except:
                pass
            self.sleep(wait_time - 0.2)

        f.close()
        if not self.training:
            self.write(
                'You successfully completed\none run of the experiment.\n\nThank you!',
                duration=5,
                align='left',
                pos=(-0.5, 0),
                scale=0.05,
                fg=(1, 1, 1, 1))
예제 #31
0
class BattleShop(Shop):
    notify = directNotify.newCategory("BattleShop")

    def __init__(self, distShop, doneEvent):
        Shop.__init__(self, distShop, doneEvent)
        self.upgradePrices = {
            0: 200  # Turret
        }
        self.maxPU = 1
        self.turret_btn = None
        self.turret_lbl = None

    def enter(self):
        Shop.enter(self)
        self.starting_turret = base.localAvatar.getPUInventory()[0]
        self.turret_btn = DirectButton(relief=None,
                                       geom=CIGlobals.getDefaultBtnGeom(),
                                       text="Turret",
                                       text_scale=0.055,
                                       command=self.purchasePU,
                                       extraArgs=[0])
        self.turret_lbl = DirectLabel(relief=None,
                                      scale=0.05,
                                      text="{0}/{1}".format(
                                          base.localAvatar.getPUInventory()[0],
                                          self.maxPU),
                                      pos=(0, 0, -0.1))

    def purchasePU(self, index):
        if base.localAvatar.getMoney() < self.upgradePrices[index]:
            self.handleNoMoney()
            return
        if base.localAvatar.getPUInventory()[index] < self.maxPU:
            base.localAvatar.setMoney(base.localAvatar.getMoney() -
                                      self.upgradePrices[index])
            base.localAvatar.getPUInventory()[index] = self.maxPU
        self.update()

    def update(self):
        Shop.update(self)
        self.turret_lbl['text'] = "{0}/{1}".format(
            base.localAvatar.getPUInventory()[0], self.maxPU)
        if base.localAvatar.getPUInventory()[0] >= self.maxPU:
            self.turret_btn['state'] = DGG.DISABLED

    def confirmPurchase(self):
        array = []
        array.append(base.localAvatar.getPUInventory()[0])
        if base.localAvatar.getPUInventory()[0] > 0:
            if not base.localAvatar.getMyBattle().getTurretManager().myTurret:
                base.localAvatar.getMyBattle().getTurretManager(
                ).createTurretButton()
        self.distShop.sendUpdate('confirmPurchase',
                                 [array, base.localAvatar.getMoney()])
        Shop.confirmPurchase(self)

    def cancelPurchase(self):
        base.localAvatar.setMoney(self.starting_money)
        base.localAvatar.getPUInventory()[0] = self.starting_turret
        Shop.cancelPurchase(self)

    def exit(self):
        Shop.exit(self)
        self.turret_btn.destroy()
        del self.turret_btn
        self.turret_lbl.destroy()
        del self.turret_lbl
        return
예제 #32
0
class DistributedBattleTrolley(DistributedObject):
    notify = directNotify.newCategory('DistributedBattleTrolley')
    STAND_POSITIONS = [Point3(-4.75, -5, 1.4),
     Point3(-4.75, -1.6, 1.4),
     Point3(-4.75, 1.6, 1.4),
     Point3(-4.75, 5, 1.4)]
    TROLLEY_NEUTRAL_POS = Point3(15.751, 14.1588, -0.984615)
    TROLLEY_GONE_POS = Point3(50, 14.1588, -0.984615)
    TROLLEY_ARRIVING_START_POS = Point3(-20, 14.1588, -0.984615)
    CAM_POS = Point3(-36.1269, 0.742999, 7.3503)
    CAM_HPR = Vec3(-90, -1.9966, 0)

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.fsm = ClassicFSM.ClassicFSM('DistributedBattleTrolley', [State.State('off', self.enterOff, self.exitOff),
         State.State('wait', self.enterWait, self.exitWait),
         State.State('waitCountdown', self.enterWaitCountdown, self.exitWaitCountdown),
         State.State('leaving', self.enterLeaving, self.exitLeaving),
         State.State('arriving', self.enterArriving, self.exitArriving)], 'off', 'off')
        self.fsm.enterInitialState()
        self.trolleyStation = None
        self.trolleyCar = None
        self.trolleyKey = None
        self.countdownText = None
        self.soundMoving = base.loadSfx('phase_4/audio/sfx/SZ_trolley_away.mp3')
        self.soundBell = base.loadSfx('phase_4/audio/sfx/SZ_trolley_bell.mp3')
        self.hoodIndex = 0
        self.localAvOnTrolley = False
        return

    def headOff(self, zoneId):
        hoodId = self.cr.playGame.hood.hoodId
        if hoodId == CIGlobals.ToontownCentral:
            hoodId = CIGlobals.BattleTTC
        requestStatus = {'zoneId': zoneId,
         'hoodId': hoodId,
         'where': 'playground',
         'avId': base.localAvatar.doId,
         'loader': 'safeZoneLoader',
         'shardId': None,
         'wantLaffMeter': 1,
         'how': 'teleportIn'}
        self.cr.playGame.getPlace().doneStatus = requestStatus
        messenger.send(self.cr.playGame.getPlace().doneEvent)
        base.localAvatar.reparentTo(render)
        base.localAvatar.setPos(0, 0, 0)
        base.localAvatar.setHpr(0, 0, 0)
        base.localAvatar.walkControls.setCollisionsActive(1)
        self.localAvOnTrolley = False
        return

    def setHoodIndex(self, zone):
        self.hoodIndex = zone

    def getToZone(self):
        return self.toZone

    def enterOff(self, ts = 0):
        pass

    def exitOff(self):
        pass

    def enterWait(self, ts = 0):
        self.trolleyCar.setPos(self.TROLLEY_NEUTRAL_POS)

    def exitWait(self):
        pass

    def enterWaitCountdown(self, ts = 0):
        self.trolleyCar.setPos(self.TROLLEY_NEUTRAL_POS)
        if self.countdownText:
            self.countdownTrack = Sequence()
            for i in range(10):
                self.countdownTrack.append(Func(self.countdownText.node().setText, str(10 - i)))
                self.countdownTrack.append(Wait(1.0))

            self.countdownTrack.start()

    def exitWaitCountdown(self):
        if hasattr(self, 'countdownTrack'):
            self.countdownTrack.finish()
            del self.countdownTrack
        if self.countdownText:
            self.countdownText.node().setText('')
        self.disableExitButton()

    def enterArriving(self, ts = 0):
        base.playSfx(self.soundMoving)
        self.moveTrack = LerpPosInterval(self.trolleyCar, duration=3.0, pos=self.TROLLEY_NEUTRAL_POS, startPos=self.TROLLEY_ARRIVING_START_POS, blendType='easeOut')
        self.moveTrack.start()

    def exitArriving(self):
        self.moveTrack.finish()
        self.acceptOnce('entertrolley_sphere', self.__handleTrolleyTrigger)
        del self.moveTrack

    def enterLeaving(self, ts = 0):
        base.playSfx(self.soundMoving)
        base.playSfx(self.soundBell)
        self.moveTrack = Parallel()
        self.moveTrack.append(LerpPosInterval(self.trolleyCar, duration=3.0, pos=self.TROLLEY_GONE_POS, startPos=self.TROLLEY_NEUTRAL_POS, blendType='easeIn'))
        if self.localAvOnTrolley == True:
            self.moveTrack.append(Sequence(Wait(2.0), Func(base.transitions.fadeOut)))
        self.moveTrack.start()
        self.ignore('entertrolley_sphere')

    def exitLeaving(self):
        self.moveTrack.finish()
        del self.moveTrack

    def setState(self, stateName, timestamp):
        ts = globalClockDelta.localElapsedTime(timestamp)
        self.fsm.request(stateName, [ts])

    def __handleTrolleyTrigger(self, entry):
        self.cr.playGame.getPlace().fsm.request('stop')
        base.localAvatar.disablePies()
        self.notify.info('Waiting for response from server to enter trolley')
        self.sendUpdate('requestBoard')
        base.localAvatar.walkControls.setCollisionsActive(0)

    def fillSlot(self, index, avId):
        toon = self.cr.doId2do.get(avId)
        toon.stopSmooth()
        if toon:
            toon.wrtReparentTo(self.trolleyCar)
            slotPos = self.STAND_POSITIONS[index]
            toon.headsUp(slotPos)
            track = Sequence(Func(toon.setAnimState, 'run'), LerpPosInterval(toon, duration=1.0, pos=slotPos, startPos=toon.getPos()), Func(toon.setAnimState, 'neutral'), Func(toon.setHpr, 90, 0, 0))
            track.start()
        if avId == base.localAvatar.doId:
            self.localAvOnTrolley = True
            base.localAvatar.stopSmartCamera()
            base.camera.wrtReparentTo(self.trolleyCar)
            camTrack = Sequence(Parallel(LerpPosInterval(base.camera, duration=0.5, pos=self.CAM_POS, startPos=base.camera.getPos(), blendType='easeOut'), LerpQuatInterval(base.camera, duration=0.5, hpr=self.CAM_HPR, startHpr=base.camera.getHpr(), blendType='easeOut')), Func(self.enableExitButton))
            camTrack.start()

    def enableExitButton(self):
        gui = loader.loadModel('phase_3.5/models/gui/inventory_gui.bam')
        up = gui.find('**/InventoryButtonUp')
        down = gui.find('**/InventoryButtonDown')
        rlvr = gui.find('**/InventoryButtonRollover')
        self.exitButton = DirectButton(image=(up, down, rlvr), relief=None, text='Exit', text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.8, image_scale=(11, 1, 11), pos=(0, 0, -0.8), scale=0.15, command=self.__handleExitButton, image_color=(1, 0, 0, 1))
        return

    def __handleExitButton(self):
        if self.fsm.getCurrentState().getName() == 'waitCountdown' and self.localAvOnTrolley == True:
            self.disableExitButton()
            self.sendUpdate('requestHopOff')

    def disableExitButton(self):
        if hasattr(self, 'exitButton'):
            self.exitButton.destroy()
            del self.exitButton

    def emptySlot(self, index, avId):
        toon = self.cr.doId2do.get(avId)
        toon.stopSmooth()
        currToonPos = toon.getPos(render)
        toon.wrtReparentTo(render)
        slotPos = self.STAND_POSITIONS[index]
        endPos = (-20, slotPos.getY(), 0.0)
        toon.setPos(self.trolleyCar, endPos)
        endPosWrtRender = toon.getPos(render)
        toon.setPos(currToonPos)
        toon.headsUp(self.trolleyCar, endPos)
        track = Sequence(Func(toon.setAnimState, 'run'), LerpPosInterval(toon, duration=1.0, pos=endPosWrtRender, startPos=currToonPos), Func(toon.setAnimState, 'neutral'), Func(toon.startSmooth))
        if avId == base.localAvatar.doId:
            self.localAvOnTrolley = False
            track.append(Func(self.__hoppedOffTrolley))
        track.start()

    def __hoppedOffTrolley(self):
        self.acceptOnce('entertrolley_sphere', self.__handleTrolleyTrigger)
        base.localAvatar.walkControls.setCollisionsActive(1)
        self.cr.playGame.getPlace().fsm.request('walk')

    def generate(self):
        DistributedObject.announceGenerate(self)
        self.trolleyStation = self.cr.playGame.hood.loader.geom.find('**/prop_trolley_station_DNARoot')
        self.trolleyCar = self.trolleyStation.find('**/trolley_car')
        self.trolleyKey = self.trolleyStation.find('**/key')
        tn = TextNode('trolleycountdowntext')
        tn.setFont(CIGlobals.getMickeyFont())
        tn.setTextColor(1, 0, 0, 1)
        self.countdownText = self.trolleyStation.attachNewNode(tn)
        self.countdownText.setScale(3.0)
        self.countdownText.setPos(14.58, 10.77, 11.17)
        self.acceptOnce('entertrolley_sphere', self.__handleTrolleyTrigger)

    def delete(self):
        self.trolleyStation = None
        self.trolleyKey = None
        self.soundMoving = None
        self.soundBell = None
        self.troleyCar = None
        self.ignore('entertrolley_sphere')
        DistributedObject.delete(self)
        return
예제 #33
0
class GloveShopGui:
    def __init__(self):
        self.index = 0
        self.id = time.time()
        self.lastGlove = base.localAvatar.style.gloveColor
        self.timer = ToontownTimer.ToontownTimer()
        self.timer.reparentTo(aspect2d)
        self.timer.posInTopRightCorner()
        self.timer.countdown(GloveNPCGlobals.TIMER_SECONDS, self.__exit,
                             [GloveNPCGlobals.TIMER_END])
        self.setupButtons()
        self.bindButtons()
        self.__updateIndex(0)

    def setupButtons(self):
        gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_mainGui')
        arrowImage = (gui.find('**/tt_t_gui_mat_shuffleArrowUp'),
                      gui.find('**/tt_t_gui_mat_shuffleArrowDown'))
        buttonImage = (gui.find('**/tt_t_gui_mat_shuffleUp'),
                       gui.find('**/tt_t_gui_mat_shuffleDown'))

        self.title = DirectLabel(aspect2d,
                                 relief=None,
                                 text=TTLocalizer.GloveGuiTitle,
                                 text_fg=(0, 1, 0, 1),
                                 text_scale=0.15,
                                 text_font=ToontownGlobals.getSignFont(),
                                 pos=(0, 0, -0.30),
                                 text_shadow=(1, 1, 1, 1))

        self.notice = DirectLabel(aspect2d,
                                  relief=None,
                                  text='',
                                  text_fg=(1, 0, 0, 1),
                                  text_scale=0.11,
                                  text_font=ToontownGlobals.getSignFont(),
                                  pos=(0, 0, -0.45),
                                  text_shadow=(1, 1, 1, 1))

        self.color = DirectLabel(aspect2d,
                                 relief=None,
                                 text='',
                                 text_scale=0.11,
                                 text_font=ToontownGlobals.getSignFont(),
                                 pos=(0, 0, -0.70),
                                 text_shadow=(1, 1, 1, 1))

        self.buyButton = DirectButton(
            aspect2d,
            relief=None,
            image=buttonImage,
            text=TTLocalizer.GloveGuiBuy,
            text_font=ToontownGlobals.getInterfaceFont(),
            text_scale=0.11,
            text_pos=(0, -0.02),
            pos=(-0.60, 0, -0.90),
            text_fg=(1, 1, 1, 1),
            text_shadow=(0, 0, 0, 1),
            command=self.__exit,
            extraArgs=[GloveNPCGlobals.CHANGE])

        self.cancelButton = DirectButton(
            aspect2d,
            relief=None,
            image=buttonImage,
            text=TTLocalizer.lCancel,
            text_font=ToontownGlobals.getInterfaceFont(),
            text_scale=0.11,
            text_pos=(0, -0.02),
            pos=(0.60, 0, -0.90),
            text_fg=(1, 1, 1, 1),
            text_shadow=(0, 0, 0, 1),
            command=self.__exit,
            extraArgs=[GloveNPCGlobals.USER_CANCEL])

        self.downArrow = DirectButton(aspect2d,
                                      relief=None,
                                      image=arrowImage,
                                      pos=(-0.60, 0, -0.66))
        self.upArrow = DirectButton(aspect2d,
                                    relief=None,
                                    image=arrowImage,
                                    pos=(0.60, 0, -0.66),
                                    scale=-1)

        gui.removeNode()

    def bindButtons(self):
        self.downArrow.bind(DGG.B1PRESS, self.__taskUpdate, extraArgs=[-1])
        self.downArrow.bind(DGG.B1RELEASE, self.__taskDone)
        self.upArrow.bind(DGG.B1PRESS, self.__taskUpdate, extraArgs=[1])
        self.upArrow.bind(DGG.B1RELEASE, self.__taskDone)

    def destroy(self):
        if self.timer:
            self.timer.destroy()

        if not hasattr(self, 'title'):
            return

        # TODO: DirectDialog-ify
        self.title.destroy()
        self.notice.destroy()
        self.color.destroy()
        self.buyButton.destroy()
        self.cancelButton.destroy()
        self.downArrow.destroy()
        self.upArrow.destroy()
        del self.title
        del self.notice
        del self.color
        del self.buyButton
        del self.cancelButton
        del self.downArrow
        del self.upArrow

        taskMgr.remove('runGloveCounter-%s' % self.id)

    def setClientGlove(self, color):
        dna = base.localAvatar.style

        dna.gloveColor = color
        base.localAvatar.setDNA(dna)

    def __exit(self, state):
        self.destroy()
        self.setClientGlove(self.lastGlove)
        messenger.send(
            'gloveShopDone',
            [state, self.index if state == GloveNPCGlobals.CHANGE else 0])

    def __updateIndex(self, offset):
        self.index += offset
        hitLimit = 0

        if self.index <= 0:
            self.downArrow['state'] = DGG.DISABLED
            hitLimit = 1
        else:
            self.downArrow['state'] = DGG.NORMAL

        if (self.index + 1) >= len(TTLocalizer.NumToColor):
            self.upArrow['state'] = DGG.DISABLED
            hitLimit = 1
        else:
            self.upArrow['state'] = DGG.NORMAL

        if self.lastGlove == self.index:
            self.buyButton['state'] = DGG.DISABLED
            self.notice['text'] = TTLocalizer.GloveGuiSameColor
        else:
            self.buyButton['state'] = DGG.NORMAL
            self.notice[
                'text'] = TTLocalizer.GloveGuiNotice % ToontownGlobals.GloveCost

        self.color['text'] = TTLocalizer.NumToColor[self.index]
        self.color['text_fg'] = ToonDNA.allColorsList[self.index]
        self.setClientGlove(self.index)
        return hitLimit

    def __runTask(self, task):
        if task.time - task.prevTime < task.delayTime:
            return Task.cont
        else:
            task.delayTime = max(0.05, task.delayTime * 0.75)
            task.prevTime = task.time
            hitLimit = self.__updateIndex(task.delta)

            return Task.done if hitLimit else Task.cont

    def __taskDone(self, event):
        messenger.send('wakeup')
        taskMgr.remove('runGloveCounter-%s' % self.id)

    def __taskUpdate(self, delta, event):
        messenger.send('wakeup')

        task = Task(self.__runTask)
        task.delayTime = 0.4
        task.prevTime = 0.0
        task.delta = delta
        hitLimit = self.__updateIndex(delta)

        if not hitLimit:
            taskMgr.add(task, 'runGloveCounter-%s' % self.id)
class CannonGui(DirectObject):
    notify = directNotify.newCategory('CannonGui')
    FIRE_KEY = 'control'
    UP_KEY = 'arrow_up'
    DOWN_KEY = 'arrow_down'
    LEFT_KEY = 'arrow_left'
    RIGHT_KEY = 'arrow_right'
    FIRE_PRESSED = 'cannongui_fire_pressed'

    def __init__(self):
        self.__loaded = False
        self.leftPressed = 0
        self.rightPressed = 0
        self.upPressed = 0
        self.downPressed = 0
        self.__aimPad = None
        self.__timerPad = None
        return

    def load(self):
        if self.__loaded:
            return
        self.__timerPad = PartyUtils.getNewToontownTimer()
        guiModel = 'phase_4/models/gui/cannon_game_gui'
        guiNode = loader.loadModel(guiModel)
        self.__aimPad = DirectFrame(image=guiNode.find('**/CannonFire_PAD'), relief=None, pos=(0.7, 0, -0.553333), scale=0.8)
        guiNode.removeNode()
        self.fireButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Fire_Btn_UP'), (guiModel, '**/Fire_Btn_DN'), (guiModel, '**/Fire_Btn_RLVR')), relief=None, pos=(0.0115741, 0, 0.00505051), scale=1.0, command=self.__firePressed)
        self.upButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0115741, 0, 0.221717))
        self.downButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.0136112, 0, -0.210101), image_hpr=(0, 0, 180))
        self.leftButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(-0.199352, 0, -0.000505269), image_hpr=(0, 0, -90))
        self.rightButton = DirectButton(parent=self.__aimPad, image=((guiModel, '**/Cannon_Arrow_UP'), (guiModel, '**/Cannon_Arrow_DN'), (guiModel, '**/Cannon_Arrow_RLVR')), relief=None, pos=(0.219167, 0, -0.00101024), image_hpr=(0, 0, 90))
        self.__aimPad.setColor(1, 1, 1, 0.9)

        def bindButton(button, upHandler, downHandler):
            button.bind(DGG.B1PRESS, lambda x, handler = upHandler: handler())
            button.bind(DGG.B1RELEASE, lambda x, handler = downHandler: handler())

        bindButton(self.upButton, self.__upPressed, self.__upReleased)
        bindButton(self.downButton, self.__downPressed, self.__downReleased)
        bindButton(self.leftButton, self.__leftPressed, self.__leftReleased)
        bindButton(self.rightButton, self.__rightPressed, self.__rightReleased)
        self.__loaded = True
        return

    def unload(self):
        self.ignoreAll()
        if not self.__loaded:
            return
        self.disable()
        self.upButton.unbind(DGG.B1PRESS)
        self.upButton.unbind(DGG.B1RELEASE)
        self.downButton.unbind(DGG.B1PRESS)
        self.downButton.unbind(DGG.B1RELEASE)
        self.leftButton.unbind(DGG.B1PRESS)
        self.leftButton.unbind(DGG.B1RELEASE)
        self.rightButton.unbind(DGG.B1PRESS)
        self.rightButton.unbind(DGG.B1RELEASE)
        self.fireButton.destroy()
        self.__aimPad.destroy()
        del self.__aimPad
        del self.fireButton
        del self.upButton
        del self.downButton
        del self.leftButton
        del self.rightButton
        self.__timerPad.destroy()
        del self.__timerPad
        self.__loaded = False

    def enable(self, timer = 0):
        self.__aimPad.show()
        base.setCellsAvailable([base.bottomCells[3], base.bottomCells[4]], 0)
        base.setCellsAvailable([base.rightCells[1]], 0)
        if timer > 0:
            self.__timerPad.setTime(timer)
            self.__timerPad.countdown(timer)
            self.__timerPad.show()
        self.enableKeys()

    def disable(self):
        self.__aimPad.hide()
        base.setCellsAvailable([base.bottomCells[3], base.bottomCells[4]], 1)
        base.setCellsAvailable([base.rightCells[1]], 1)
        self.__timerPad.hide()
        self.disableKeys()

    def enableKeys(self):
        self.enableAimKeys()
        self.enableFireKey()

    def disableKeys(self):
        self.__aimPad.hide()
        self.disableAimKeys()
        self.disableFireKey()

    def enableAimKeys(self):
        self.leftPressed = 0
        self.rightPressed = 0
        self.upPressed = 0
        self.downPressed = 0
        self.accept(self.UP_KEY, self.__upKeyPressed)
        self.accept(self.DOWN_KEY, self.__downKeyPressed)
        self.accept(self.LEFT_KEY, self.__leftKeyPressed)
        self.accept(self.RIGHT_KEY, self.__rightKeyPressed)

    def disableAimKeys(self):
        self.ignore(self.UP_KEY)
        self.ignore(self.DOWN_KEY)
        self.ignore(self.LEFT_KEY)
        self.ignore(self.RIGHT_KEY)
        messenger.send(self.UP_KEY + '-up')
        messenger.send(self.DOWN_KEY + '-up')
        messenger.send(self.LEFT_KEY + '-up')
        messenger.send(self.RIGHT_KEY + '-up')
        self.ignore(self.UP_KEY + '-up')
        self.ignore(self.DOWN_KEY + '-up')
        self.ignore(self.LEFT_KEY + '-up')
        self.ignore(self.RIGHT_KEY + '-up')

    def enableFireKey(self):
        self.accept(self.FIRE_KEY, self.__fireKeyPressed)

    def disableFireKey(self):
        self.ignore(self.FIRE_KEY)
        self.ignore(self.FIRE_KEY + '-up')

    def __fireKeyPressed(self):
        self.ignore(self.FIRE_KEY)
        self.accept(self.FIRE_KEY + '-up', self.__fireKeyReleased)
        self.__firePressed()

    def __upKeyPressed(self):
        self.ignore(self.UP_KEY)
        self.accept(self.UP_KEY + '-up', self.__upKeyReleased)
        self.__upPressed()

    def __downKeyPressed(self):
        self.ignore(self.DOWN_KEY)
        self.accept(self.DOWN_KEY + '-up', self.__downKeyReleased)
        self.__downPressed()

    def __leftKeyPressed(self):
        self.ignore(self.LEFT_KEY)
        self.accept(self.LEFT_KEY + '-up', self.__leftKeyReleased)
        self.__leftPressed()

    def __rightKeyPressed(self):
        self.ignore(self.RIGHT_KEY)
        self.accept(self.RIGHT_KEY + '-up', self.__rightKeyReleased)
        self.__rightPressed()

    def __fireKeyReleased(self):
        self.ignore(self.FIRE_KEY + '-up')
        self.accept(self.FIRE_KEY, self.__fireKeyPressed)

    def __leftKeyReleased(self):
        self.ignore(self.LEFT_KEY + '-up')
        self.accept(self.LEFT_KEY, self.__leftKeyPressed)
        self.__leftReleased()

    def __rightKeyReleased(self):
        self.ignore(self.RIGHT_KEY + '-up')
        self.accept(self.RIGHT_KEY, self.__rightKeyPressed)
        self.__rightReleased()

    def __upKeyReleased(self):
        self.ignore(self.UP_KEY + '-up')
        self.accept(self.UP_KEY, self.__upKeyPressed)
        self.__upReleased()

    def __downKeyReleased(self):
        self.ignore(self.DOWN_KEY + '-up')
        self.accept(self.DOWN_KEY, self.__downKeyPressed)
        self.__downReleased()

    def __upPressed(self):
        self.notify.debug('up pressed')
        self.upPressed = self.__enterControlActive(self.upPressed)

    def __downPressed(self):
        self.notify.debug('down pressed')
        self.downPressed = self.__enterControlActive(self.downPressed)

    def __leftPressed(self):
        self.notify.debug('left pressed')
        self.leftPressed = self.__enterControlActive(self.leftPressed)

    def __rightPressed(self):
        self.notify.debug('right pressed')
        self.rightPressed = self.__enterControlActive(self.rightPressed)

    def __upReleased(self):
        self.notify.debug('up released')
        self.upPressed = self.__exitControlActive(self.upPressed)

    def __downReleased(self):
        self.notify.debug('down released')
        self.downPressed = self.__exitControlActive(self.downPressed)

    def __leftReleased(self):
        self.notify.debug('left released')
        self.leftPressed = self.__exitControlActive(self.leftPressed)

    def __rightReleased(self):
        self.notify.debug('right released')
        self.rightPressed = self.__exitControlActive(self.rightPressed)

    def __firePressed(self):
        self.notify.debug('fire pressed')
        messenger.send(CannonGui.FIRE_PRESSED)

    def __enterControlActive(self, control):
        return control + 1

    def __exitControlActive(self, control):
        return max(0, control - 1)
class CalendarGuiDay(DirectFrame):
    notify = directNotify.newCategory('CalendarGuiDay')
    ScrollListTextSize = 0.03

    def __init__(self, parent, myDate, startDate, dayClickCallback = None, onlyFutureDaysClickable = False):
        self.origParent = parent
        self.startDate = startDate
        self.myDate = myDate
        self.dayClickCallback = dayClickCallback
        self.onlyFutureDaysClickable = onlyFutureDaysClickable
        DirectFrame.__init__(self, parent=parent)
        self.timedEvents = []
        self.partiesInvitedToToday = []
        self.hostedPartiesToday = []
        self.yearlyHolidaysToday = []
        self.showMarkers = base.config.GetBool('show-calendar-markers', 0)
        self.filter = ToontownGlobals.CalendarFilterShowAll
        self.load()
        self.createGuiObjects()
        self.update()

    def createDummyLocators(self):
        self.dayButtonLocator = self.attachNewNode('dayButtonLocator')
        self.dayButtonLocator.setX(0.1)
        self.dayButtonLocator.setZ(-0.05)
        self.numberLocator = self.attachNewNode('numberLocator')
        self.numberLocator.setX(0.09)
        self.scrollLocator = self.attachNewNode('scrollLocator')
        self.selectedLocator = self.attachNewNode('selectedLocator')
        self.selectedLocator.setX(0.11)
        self.selectedLocator.setZ(-0.06)

    def load(self):
        dayAsset = loader.loadModel('phase_4/models/parties/tt_m_gui_sbk_calendar_box')
        dayAsset.reparentTo(self)
        self.dayButtonLocator = self.find('**/loc_origin')
        self.numberLocator = self.find('**/loc_number')
        self.scrollLocator = self.find('**/loc_topLeftList')
        self.selectedLocator = self.find('**/loc_origin')
        self.todayBox = self.find('**/boxToday')
        self.todayBox.hide()
        self.selectedFrame = self.find('**/boxHover')
        self.selectedFrame.hide()
        self.defaultBox = self.find('**/boxBlank')
        self.scrollBottomRightLocator = self.find('**/loc_bottomRightList')
        self.scrollDownLocator = self.find('**/loc_scrollDown')
        self.attachMarker(self.scrollDownLocator)
        self.scrollUpLocator = self.find('**/loc_scrollUp')
        self.attachMarker(self.scrollUpLocator)

    def attachMarker(self, parent, scale = 0.005, color = (1, 0, 0)):
        if self.showMarkers:
            marker = loader.loadModel('phase_3/models/misc/sphere')
            marker.reparentTo(parent)
            marker.setScale(scale)
            marker.setColor(*color)

    def createGuiObjects(self):
        self.dayButton = DirectButton(parent=self.dayButtonLocator, image=self.selectedFrame, relief=None, command=self.__clickedOnDay, pressEffect=1, rolloverSound=None, clickSound=None)
        self.numberWidget = DirectLabel(parent=self.numberLocator, relief=None, text=str(self.myDate.day), text_scale=0.04, text_align=TextNode.ACenter, text_font=ToontownGlobals.getInterfaceFont(), text_fg=Vec4(110 / 255.0, 126 / 255.0, 255 / 255.0, 1))
        self.attachMarker(self.numberLocator)
        self.listXorigin = 0
        self.listFrameSizeX = self.scrollBottomRightLocator.getX() - self.scrollLocator.getX()
        self.scrollHeight = self.scrollLocator.getZ() - self.scrollBottomRightLocator.getZ()
        self.listZorigin = self.scrollBottomRightLocator.getZ()
        self.listFrameSizeZ = self.scrollLocator.getZ() - self.scrollBottomRightLocator.getZ()
        self.arrowButtonXScale = 1
        self.arrowButtonZScale = 1
        self.itemFrameXorigin = 0
        self.itemFrameZorigin = 0
        self.buttonXstart = self.itemFrameXorigin + 0.21
        self.gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui')
        buttonOffSet = -0.01
        incButtonPos = (0.0, 0, 0)
        decButtonPos = (0.0, 0, 0)
        itemFrameMinZ = self.listZorigin
        itemFrameMaxZ = self.listZorigin + self.listFrameSizeZ
        arrowUp = self.find('**/downScroll_up')
        arrowDown = self.find('**/downScroll_down')
        arrowHover = self.find('**/downScroll_hover')
        self.scrollList = DirectScrolledList(parent=self.scrollLocator, relief=None, pos=(0, 0, 0), incButton_image=(arrowUp,
         arrowDown,
         arrowHover,
         arrowUp), incButton_relief=None, incButton_scale=(self.arrowButtonXScale, 1, self.arrowButtonZScale), incButton_pos=incButtonPos, incButton_image3_color=(1, 1, 1, 0.2), decButton_image=(arrowUp,
         arrowDown,
         arrowHover,
         arrowUp), decButton_relief=None, decButton_scale=(self.arrowButtonXScale, 1, -self.arrowButtonZScale), decButton_pos=decButtonPos, decButton_image3_color=(1, 1, 1, 0.2), itemFrame_pos=(self.itemFrameXorigin, 0, -0.03), numItemsVisible=4, incButtonCallback=self.scrollButtonPressed, decButtonCallback=self.scrollButtonPressed)
        itemFrameParent = self.scrollList.itemFrame.getParent()
        self.scrollList.incButton.reparentTo(self.scrollDownLocator)
        self.scrollList.decButton.reparentTo(self.scrollUpLocator)
        arrowUp.removeNode()
        arrowDown.removeNode()
        arrowHover.removeNode()
        clipper = PlaneNode('clipper')
        clipper.setPlane(Plane((-1, 0, 0), (0.23, 0, 0)))
        clipNP = self.scrollList.component('itemFrame').attachNewNode(clipper)
        self.scrollList.component('itemFrame').setClipPlane(clipNP)
        return

    def scrollButtonPressed(self):
        self.__clickedOnDay()

    def adjustForMonth(self):
        curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
        if self.onlyFutureDaysClickable:
            if self.myDate.year < curServerDate.year or self.myDate.year == curServerDate.year and self.myDate.month < curServerDate.month or self.myDate.year == curServerDate.year and self.myDate.month == curServerDate.month and self.myDate.day < curServerDate.day:
                self.numberWidget.setColorScale(0.5, 0.5, 0.5, 0.5)
                self.numberWidget['state'] = DirectGuiGlobals.DISABLED
            else:
                self.numberWidget.setColorScale(1, 1, 1, 1)
        if self.myDate.month != self.startDate.month:
            self.setColorScale(0.75, 0.75, 0.75, 1.0)
            if self.dayClickCallback is not None:
                self.numberWidget['state'] = DirectGuiGlobals.DISABLED
        else:
            self.setColorScale(1, 1, 1, 1)
        if self.myDate.date() == curServerDate.date():
            self.defaultBox.hide()
            self.todayBox.show()
        else:
            self.defaultBox.show()
            self.todayBox.hide()
        return

    def destroy(self):
        if self.dayClickCallback is not None:
            self.numberWidget.destroy()
        self.dayClickCallback = None
        self.notify.debug('desroying %s' % self.myDate)
        try:
            for item in self.scrollList['items']:
                if hasattr(item, 'description') and item.description and hasattr(item.description, 'destroy'):
                    self.notify.debug('desroying description of item %s' % item)
                    item.unbind(DGG.ENTER)
                    item.unbind(DGG.EXIT)
                    item.description.destroy()

        except e:
            self.notify.debug('pass %s' % self.myDate)

        self.scrollList.removeAndDestroyAllItems()
        self.scrollList.destroy()
        self.dayButton.destroy()
        DirectFrame.destroy(self)

    def updateArrowButtons(self):
        numItems = 0
        try:
            numItems = len(self.scrollList['items'])
        except e:
            numItems = 0

        if numItems <= self.scrollList.numItemsVisible:
            self.scrollList.incButton.hide()
            self.scrollList.decButton.hide()
        else:
            self.scrollList.incButton.show()
            self.scrollList.decButton.show()

    def collectTimedEvents(self):

        if self.filter == ToontownGlobals.CalendarFilterShowAll or self.filter == ToontownGlobals.CalendarFilterShowOnlyParties:
            for party in localAvatar.partiesInvitedTo:
                if party.startTime.date() == self.myDate.date():
                    self.addPartyToScrollList(party)

            for party in localAvatar.hostedParties:
                if party.startTime.date() == self.myDate.date():
                    self.addPartyToScrollList(party)

        if self.filter == ToontownGlobals.CalendarFilterShowAll or self.filter == ToontownGlobals.CalendarFilterShowOnlyHolidays:
            for id, holiday in HolidayGlobals.Holidays.iteritems():
                title, description = TTLocalizer.HolidayNamesInCalendar[id]

                if 'weekDay' in holiday:
                    if self.myDate.weekday() == holiday['weekDay']:
                        self.addTitleAndDescToScrollList(title, description)
                elif 'startMonth' in holiday or 'startDay' in holiday:
                    startDate = HolidayGlobals.getStartDate(holiday, self.myDate)
                    endDate = HolidayGlobals.getEndDate(holiday, self.myDate)
                    if self.isDateMatch(self.myDate, startDate):
                        if self.isDateMatch(startDate, endDate):
                            description = '%s. %s' % (title, description)
                        else:
                            description = '%s. %s %s %s' % (title, description, TTLocalizer.CalendarEndsAt, endDate.strftime('%b %d'))
                        self.addTitleAndDescToScrollList(title, description)
                    elif self.isDateMatch(self.myDate, endDate):
                        title = '%s %s' % (TTLocalizer.CalendarEndOf, title)
                        description = '%s. %s %s' % (title, TTLocalizer.CalendarStartedOn, startDate.strftime('%b %d'))
                        self.addTitleAndDescToScrollList(title, description)

    def isDateMatch(self, date1, date2):
        return date1.day == date2.day and date1.month == date2.month

    def addTitleAndDescToScrollList(self, title, desc):
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        newItem = DirectButton(relief=None, text=title, text_scale=textSize, text_align=TextNode.ALeft, rolloverSound=None, clickSound=None, pressEffect=0, command=self.__clickedOnScrollItem)
        scrollItemHeight = newItem.getHeight()
        descUnderItemZAdjust = scrollItemHeight * descTextSize / textSize
        descUnderItemZAdjust = max(0.0534, descUnderItemZAdjust)
        descUnderItemZAdjust = -descUnderItemZAdjust
        descZAdjust = descUnderItemZAdjust
        newItem.description = DirectLabel(parent=newItem, pos=(0.115, 0, descZAdjust), text='', text_wordwrap=15, pad=(0.02, 0.02), text_scale=descTextSize, text_align=TextNode.ACenter, textMayChange=0)
        newItem.description.checkedHeight = False
        newItem.description.setBin('gui-popup', 0)
        newItem.description.hide()
        newItem.bind(DGG.ENTER, self.enteredTextItem, extraArgs=[newItem, desc, descUnderItemZAdjust])
        newItem.bind(DGG.EXIT, self.exitedTextItem, extraArgs=[newItem])
        self.scrollList.addItem(newItem)
        return

    def exitedTextItem(self, newItem, mousepos):
        newItem.description.hide()

    def enteredTextItem(self, newItem, descText, descUnderItemZAdjust, mousePos):
        if not newItem.description.checkedHeight:
            newItem.description.checkedHeight = True
            newItem.description['text'] = descText
            bounds = newItem.description.getBounds()
            descHeight = newItem.description.getHeight()
            scrollItemHeight = newItem.getHeight()
            descOverItemZAdjust = descHeight - scrollItemHeight / 2.0
            descZPos = self.getPos(aspect2d)[2] + descUnderItemZAdjust - descHeight
            if descZPos < -1.0:
                newItem.description.setZ(descOverItemZAdjust)
            descWidth = newItem.description.getWidth()
            brightFrame = loader.loadModel('phase_4/models/parties/tt_m_gui_sbk_calendar_popUp_bg')
            newItem.description['geom'] = brightFrame
            newItem.description['geom_scale'] = (descWidth, 1, descHeight)
            descGeomZ = (bounds[2] - bounds[3]) / 2.0
            descGeomZ += bounds[3]
            newItem.description['geom_pos'] = (0, 0, descGeomZ)
        newItem.description.show()

    def addPartyToScrollList(self, party):
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        partyTitle = myStrftime(party.startTime)
        partyTitle = partyTitle + ' ' + TTLocalizer.EventsPageCalendarTabParty
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        newItem = DirectButton(relief=None, text=partyTitle, text_scale=textSize, text_align=TextNode.ALeft, rolloverSound=None, clickSound=None, pressEffect=0, command=self.__clickedOnScrollItem)
        scrollItemHeight = newItem.getHeight()
        descUnderItemZAdjust = scrollItemHeight * descTextSize / textSize
        descUnderItemZAdjust = max(0.0534, descUnderItemZAdjust)
        descUnderItemZAdjust = -descUnderItemZAdjust
        descZAdjust = descUnderItemZAdjust
        self.scrollList.addItem(newItem)
        newItem.description = MiniInviteVisual(newItem, party)
        newItem.description.setBin('gui-popup', 0)
        newItem.description.hide()
        newItem.bind(DGG.ENTER, self.enteredTextItem, extraArgs=[newItem, newItem.description, descUnderItemZAdjust])
        newItem.bind(DGG.EXIT, self.exitedTextItem, extraArgs=[newItem])
        return

    def __clickedOnScrollItem(self):
        self.__clickedOnDay()

    def __clickedOnDay(self):
        acceptClick = True
        if self.onlyFutureDaysClickable:
            curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
            if self.myDate.date() < curServerDate.date():
                acceptClick = False
        if not acceptClick:
            return
        if self.dayClickCallback:
            self.dayClickCallback(self)
        self.notify.debug('we got clicked on %s' % self.myDate.date())
        messenger.send('clickedOnDay', [self.myDate.date()])

    def updateSelected(self, selected):
        multiplier = 1.1
        if selected:
            self.selectedFrame.show()
            self.setScale(multiplier)
            self.setPos(-0.01, 0, 0.01)
            grandParent = self.origParent.getParent()
            self.origParent.reparentTo(grandParent)
        else:
            self.selectedFrame.hide()
            self.setScale(1.0)
            self.setPos(0, 0, 0)

    def changeDate(self, startDate, myDate):
        self.startDate = startDate
        self.myDate = myDate
        self.scrollList.removeAndDestroyAllItems()
        self.update()

    def update(self):
        self.numberWidget['text'] = str(self.myDate.day)
        self.adjustForMonth()
        self.collectTimedEvents()
        self.updateArrowButtons()

    def changeFilter(self, filter):
        oldFilter = self.filter
        self.filter = filter
        if self.filter != oldFilter:
            self.scrollList.removeAndDestroyAllItems()
            self.update()
예제 #36
0
class MainMenu:

    def __init__(self):
        self.background = None
        self.newGameButton = None
        self.optionsButton = None
        self.exitButton = None

    def drawMainMenu(self):
        x = self.win.getXSize()
        y = self.win.getYSize()

        self.background = OnscreenImage(image='textures/main_menu.png')

        self.background.setSx(x / y)

        clickNewGameButton = lambda: self.push(Game())
        clickOptionsButton = lambda: self.push('Options')
        clickExitButton = lambda: sys.exit()

        def setButtonAttributes(button):
            button.setSx(.60)
            button.setSz(.26)
            button.setTransparency(TransparencyAttrib.MAlpha)

        maps = loader.loadModel('textures/continue_maps.egg')
        geom = (maps.find('**/continue'),
                maps.find('**/continue_click'),
                maps.find('**/continue_hover'))
        self.newGameButton = DirectButton(geom=geom, relief=None,
                                          command=clickNewGameButton)
        setButtonAttributes(self.newGameButton)
        self.newGameButton.setPos(0, 0, .6)

        maps = loader.loadModel('textures/options_maps.egg')
        geom = (maps.find('**/options'),
                maps.find('**/options_click'),
                maps.find('**/options_hover'))
        self.optionsButton = DirectButton(geom=geom, relief=None,
                                          command=clickOptionsButton)
        setButtonAttributes(self.optionsButton)
        self.optionsButton.setPos(0, 0, .36)

        maps = loader.loadModel('textures/exit_maps.egg')
        geom = (maps.find('**/exit'),
                maps.find('**/exit_click'),
                maps.find('**/exit_hover'))
        self.exitButton = DirectButton(geom=geom, relief=None,
                                       command=clickExitButton)
        setButtonAttributes(self.exitButton)
        self.exitButton.setPos(0, 0, .12)

        self.hasDrawnMainMenu = True

    def destroyMainMenu(self):
        self.background.destroy()
        self.newGameButton.destroy()
        self.optionsButton.destroy()
        self.exitButton.destroy()

        self.hasDrawnMainMenu = False
예제 #37
0
class CalendarGuiDay(DirectFrame):
    notify = directNotify.newCategory('CalendarGuiDay')
    ScrollListTextSize = 0.03

    def __init__(self, parent, myDate, startDate, dayClickCallback = None, onlyFutureDaysClickable = False):
        self.origParent = parent
        self.startDate = startDate
        self.myDate = myDate
        self.dayClickCallback = dayClickCallback
        self.onlyFutureDaysClickable = onlyFutureDaysClickable
        DirectFrame.__init__(self, parent=parent)
        self.timedEvents = []
        self.partiesInvitedToToday = []
        self.hostedPartiesToday = []
        self.yearlyHolidaysToday = []
        self.showMarkers = base.config.GetBool('show-calendar-markers', 0)
        self.filter = ToontownGlobals.CalendarFilterShowAll
        self.load()
        self.createGuiObjects()
        self.update()

    def createDummyLocators(self):
        self.dayButtonLocator = self.attachNewNode('dayButtonLocator')
        self.dayButtonLocator.setX(0.1)
        self.dayButtonLocator.setZ(-0.05)
        self.numberLocator = self.attachNewNode('numberLocator')
        self.numberLocator.setX(0.09)
        self.scrollLocator = self.attachNewNode('scrollLocator')
        self.selectedLocator = self.attachNewNode('selectedLocator')
        self.selectedLocator.setX(0.11)
        self.selectedLocator.setZ(-0.06)

    def load(self):
        dayAsset = loader.loadModel('phase_4/models/parties/tt_m_gui_sbk_calendar_box')
        dayAsset.reparentTo(self)
        self.dayButtonLocator = self.find('**/loc_origin')
        self.numberLocator = self.find('**/loc_number')
        self.scrollLocator = self.find('**/loc_topLeftList')
        self.selectedLocator = self.find('**/loc_origin')
        self.todayBox = self.find('**/boxToday')
        self.todayBox.hide()
        self.selectedFrame = self.find('**/boxHover')
        self.selectedFrame.hide()
        self.defaultBox = self.find('**/boxBlank')
        self.scrollBottomRightLocator = self.find('**/loc_bottomRightList')
        self.scrollDownLocator = self.find('**/loc_scrollDown')
        self.attachMarker(self.scrollDownLocator)
        self.scrollUpLocator = self.find('**/loc_scrollUp')
        self.attachMarker(self.scrollUpLocator)

    def attachMarker(self, parent, scale = 0.005, color = (1, 0, 0)):
        if self.showMarkers:
            marker = loader.loadModel('phase_3/models/misc/sphere')
            marker.reparentTo(parent)
            marker.setScale(scale)
            marker.setColor(*color)

    def createGuiObjects(self):
        self.dayButton = DirectButton(parent=self.dayButtonLocator, image=self.selectedFrame, relief=None, command=self.__clickedOnDay, pressEffect=1, rolloverSound=None, clickSound=None)
        self.numberWidget = DirectLabel(parent=self.numberLocator, relief=None, text=str(self.myDate.day), text_scale=0.04, text_align=TextNode.ACenter, text_font=ToontownGlobals.getInterfaceFont(), text_fg=Vec4(110 / 255.0, 126 / 255.0, 255 / 255.0, 1))
        self.attachMarker(self.numberLocator)
        self.listXorigin = 0
        self.listFrameSizeX = self.scrollBottomRightLocator.getX() - self.scrollLocator.getX()
        self.scrollHeight = self.scrollLocator.getZ() - self.scrollBottomRightLocator.getZ()
        self.listZorigin = self.scrollBottomRightLocator.getZ()
        self.listFrameSizeZ = self.scrollLocator.getZ() - self.scrollBottomRightLocator.getZ()
        self.arrowButtonXScale = 1
        self.arrowButtonZScale = 1
        self.itemFrameXorigin = 0
        self.itemFrameZorigin = 0
        self.buttonXstart = self.itemFrameXorigin + 0.21
        self.gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui')
        buttonOffSet = -0.01
        incButtonPos = (0.0, 0, 0)
        decButtonPos = (0.0, 0, 0)
        itemFrameMinZ = self.listZorigin
        itemFrameMaxZ = self.listZorigin + self.listFrameSizeZ
        arrowUp = self.find('**/downScroll_up')
        arrowDown = self.find('**/downScroll_down')
        arrowHover = self.find('**/downScroll_hover')
        self.scrollList = DirectScrolledList(parent=self.scrollLocator, relief=None, pos=(0, 0, 0), incButton_image=(arrowUp,
         arrowDown,
         arrowHover,
         arrowUp), incButton_relief=None, incButton_scale=(self.arrowButtonXScale, 1, self.arrowButtonZScale), incButton_pos=incButtonPos, incButton_image3_color=Vec4(1, 1, 1, 0.2), decButton_image=(arrowUp,
         arrowDown,
         arrowHover,
         arrowUp), decButton_relief=None, decButton_scale=(self.arrowButtonXScale, 1, -self.arrowButtonZScale), decButton_pos=decButtonPos, decButton_image3_color=Vec4(1, 1, 1, 0.2), itemFrame_pos=(self.itemFrameXorigin, 0, -0.03), numItemsVisible=4, incButtonCallback=self.scrollButtonPressed, decButtonCallback=self.scrollButtonPressed)
        itemFrameParent = self.scrollList.itemFrame.getParent()
        self.scrollList.incButton.reparentTo(self.scrollDownLocator)
        self.scrollList.decButton.reparentTo(self.scrollUpLocator)
        arrowUp.removeNode()
        arrowDown.removeNode()
        arrowHover.removeNode()
        clipper = PlaneNode('clipper')
        clipper.setPlane(Plane(Vec3(-1, 0, 0), Point3(0.23, 0, 0)))
        clipNP = self.scrollList.component('itemFrame').attachNewNode(clipper)
        self.scrollList.component('itemFrame').setClipPlane(clipNP)
        return

    def scrollButtonPressed(self):
        self.__clickedOnDay()

    def adjustForMonth(self):
        curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
        if self.onlyFutureDaysClickable:
            if self.myDate.year < curServerDate.year or self.myDate.year == curServerDate.year and self.myDate.month < curServerDate.month or self.myDate.year == curServerDate.year and self.myDate.month == curServerDate.month and self.myDate.day < curServerDate.day:
                self.numberWidget.setColorScale(0.5, 0.5, 0.5, 0.5)
                self.numberWidget['state'] = DirectGuiGlobals.DISABLED
            else:
                self.numberWidget.setColorScale(1, 1, 1, 1)
        if self.myDate.month != self.startDate.month:
            self.setColorScale(0.75, 0.75, 0.75, 1.0)
            if self.dayClickCallback is not None:
                self.numberWidget['state'] = DirectGuiGlobals.DISABLED
        else:
            self.setColorScale(1, 1, 1, 1)
        if self.myDate.date() == curServerDate.date():
            self.defaultBox.hide()
            self.todayBox.show()
        else:
            self.defaultBox.show()
            self.todayBox.hide()
        return

    def destroy(self):
        if self.dayClickCallback is not None:
            self.numberWidget.destroy()
        self.dayClickCallback = None
        self.notify.debug('desroying %s' % self.myDate)
        try:
            for item in self.scrollList['items']:
                if hasattr(item, 'description') and item.description and hasattr(item.description, 'destroy'):
                    self.notify.debug('desroying description of item %s' % item)
                    item.unbind(DGG.ENTER)
                    item.unbind(DGG.EXIT)
                    item.description.destroy()

        except e:
            self.notify.debug('pass %s' % self.myDate)

        self.scrollList.removeAndDestroyAllItems()
        self.scrollList.destroy()
        self.dayButton.destroy()
        DirectFrame.destroy(self)
        return

    def addWeeklyHolidays(self):
        if not self.filter == ToontownGlobals.CalendarFilterShowAll and not self.filter == ToontownGlobals.CalendarFilterShowOnlyHolidays:
            return
        if base.cr.newsManager:
            holidays = base.cr.newsManager.getHolidaysForWeekday(self.myDate.weekday())
            holidayName = ''
            holidayDesc = ''
            for holidayId in holidays:
                if holidayId in TTLocalizer.HolidayNamesInCalendar:
                    holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
                    holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
                else:
                    holidayName = TTLocalizer.UnknownHoliday % holidayId
                self.addTitleAndDescToScrollList(holidayName, holidayDesc)

            self.scrollList.refresh()
        if base.config.GetBool('calendar-test-items', 0):
            if self.myDate.date() + datetime.timedelta(days=-1) == base.cr.toontownTimeManager.getCurServerDateTime().date():
                testItems = ('1:00 AM Party', '2:00 AM CEO', '11:15 AM Party', '5:30 PM CJ', '11:00 PM Party', 'Really Really Long String')
                for text in testItems:
                    newItem = DirectLabel(relief=None, text=text, text_scale=self.ScrollListTextSize, text_align=TextNode.ALeft)
                    self.scrollList.addItem(newItem)

            if self.myDate.date() + datetime.timedelta(days=-2) == base.cr.toontownTimeManager.getCurServerDateTime().date():
                testItems = ('1:00 AM Party', '3:00 AM CFO', '11:00 AM Party')
                textSize = self.ScrollListTextSize
                for text in testItems:
                    newItem = DirectLabel(relief=None, text=text, text_scale=textSize, text_align=TextNode.ALeft)
                    self.scrollList.addItem(newItem)

    def updateArrowButtons(self):
        numItems = 0
        try:
            numItems = len(self.scrollList['items'])
        except e:
            numItems = 0

        if numItems <= self.scrollList.numItemsVisible:
            self.scrollList.incButton.hide()
            self.scrollList.decButton.hide()
        else:
            self.scrollList.incButton.show()
            self.scrollList.decButton.show()

    def collectTimedEvents(self):
        self.timedEvents = []
        if self.filter == ToontownGlobals.CalendarFilterShowAll or self.filter == ToontownGlobals.CalendarFilterShowOnlyParties:
            for party in localAvatar.partiesInvitedTo:
                if party.startTime.date() == self.myDate.date():
                    self.partiesInvitedToToday.append(party)
                    self.timedEvents.append((party.startTime.time(), party))

            for party in localAvatar.hostedParties:
                if party.startTime.date() == self.myDate.date():
                    self.hostedPartiesToday.append(party)
                    self.timedEvents.append((party.startTime.time(), party))

        if base.cr.newsManager and (self.filter == ToontownGlobals.CalendarFilterShowAll or self.filter == ToontownGlobals.CalendarFilterShowOnlyHolidays):
            yearlyHolidays = base.cr.newsManager.getYearlyHolidaysForDate(self.myDate)
            for holiday in yearlyHolidays:
                holidayId = holiday[1]
                holidayStart = holiday[2]
                holidayEnd = holiday[3]
                holidayType = holiday[0]
                if holidayStart[0] == self.myDate.month and holidayStart[1] == self.myDate.day:
                    myTime = datetime.time(holidayStart[2], holidayStart[3])
                elif holidayEnd[0] == self.myDate.month and holidayEnd[1] == self.myDate.day:
                    myTime = datetime.time(holidayEnd[2], holidayEnd[3])
                else:
                    self.notify.error('holiday is not today %s' % holiday)
                self.timedEvents.append((myTime, holiday))

            oncelyHolidays = base.cr.newsManager.getOncelyHolidaysForDate(self.myDate)
            for holiday in oncelyHolidays:
                holidayId = holiday[1]
                holidayStart = holiday[2]
                holidayEnd = holiday[3]
                holidayType = holiday[0]
                if holidayStart[0] == self.myDate.year and holidayStart[1] == self.myDate.month and holidayStart[2] == self.myDate.day:
                    myTime = datetime.time(holidayStart[3], holidayStart[4])
                elif holidayEnd[0] == self.myDate.year and holidayEnd[1] == self.myDate.month and holidayEnd[2] == self.myDate.day:
                    myTime = datetime.time(holidayEnd[3], holidayEnd[4])
                else:
                    self.notify.error('holiday is not today %s' % holiday)
                self.timedEvents.append((myTime, holiday))

            multipleStartHolidays = base.cr.newsManager.getMultipleStartHolidaysForDate(self.myDate)
            for holiday in multipleStartHolidays:
                holidayId = holiday[1]
                holidayStart = holiday[2]
                holidayEnd = holiday[3]
                holidayType = holiday[0]
                if holidayStart[0] == self.myDate.year and holidayStart[1] == self.myDate.month and holidayStart[2] == self.myDate.day:
                    myTime = datetime.time(holidayStart[3], holidayStart[4])
                elif holidayEnd[0] == self.myDate.year and holidayEnd[1] == self.myDate.month and holidayEnd[2] == self.myDate.day:
                    myTime = datetime.time(holidayEnd[3], holidayEnd[4])
                else:
                    self.notify.error('holiday is not today %s' % holiday)
                self.timedEvents.append((myTime, holiday))

            relativelyHolidays = base.cr.newsManager.getRelativelyHolidaysForDate(self.myDate)
            for holiday in relativelyHolidays:
                holidayId = holiday[1]
                holidayStart = holiday[2]
                holidayEnd = holiday[3]
                holidayType = holiday[0]
                if holidayStart[0] == self.myDate.month and holidayStart[1] == self.myDate.day:
                    myTime = datetime.time(holidayStart[2], holidayStart[3])
                elif holidayEnd[0] == self.myDate.month and holidayEnd[1] == self.myDate.day:
                    myTime = datetime.time(holidayEnd[2], holidayEnd[3])
                else:
                    self.notify.error('holiday is not today %s' % holiday)
                self.timedEvents.append((myTime, holiday))

        def timedEventCompare(te1, te2):
            if te1[0] < te2[0]:
                return -1
            elif te1[0] == te2[0]:
                return 0
            else:
                return 1

        self.timedEvents.sort(cmp=timedEventCompare)
        for timedEvent in self.timedEvents:
            if isinstance(timedEvent[1], PartyInfo):
                self.addPartyToScrollList(timedEvent[1])
            elif isinstance(timedEvent[1], tuple) and timedEvent[1][0] == NewsManager.YearlyHolidayType:
                self.addYearlyHolidayToScrollList(timedEvent[1])
            elif isinstance(timedEvent[1], tuple) and timedEvent[1][0] == NewsManager.OncelyHolidayType:
                self.addOncelyHolidayToScrollList(timedEvent[1])
            elif isinstance(timedEvent[1], tuple) and timedEvent[1][0] == NewsManager.OncelyMultipleStartHolidayType:
                self.addOncelyMultipleStartHolidayToScrollList(timedEvent[1])
            elif isinstance(timedEvent[1], tuple) and timedEvent[1][0] == NewsManager.RelativelyHolidayType:
                self.addRelativelyHolidayToScrollList(timedEvent[1])

    def addYearlyHolidayToScrollList(self, holiday):
        holidayId = holiday[1]
        holidayStart = holiday[2]
        holidayEnd = holiday[3]
        holidayType = holiday[0]
        holidayText = ''
        startTime = datetime.time(holidayStart[2], holidayStart[3])
        endTime = datetime.time(holidayEnd[2], holidayEnd[3])
        startDate = datetime.date(self.myDate.year, holidayStart[0], holidayStart[1])
        endDate = datetime.date(self.myDate.year, holidayEnd[0], holidayEnd[1])
        if endDate < startDate:
            endDate = datetime.date(endDate.year + 1, endDate.month, endDate.day)
        if holidayId in TTLocalizer.HolidayNamesInCalendar:
            holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
            holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
        else:
            holidayName = TTLocalizer.UnknownHoliday % holidayId
            holidayDesc = TTLocalizer.UnknownHoliday % holidayId
        if holidayStart[0] == holidayEnd[0] and holidayStart[1] == holidayEnd[1]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(endTime)
        elif self.myDate.month == holidayStart[0] and self.myDate.day == holidayStart[1]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc = holidayName + '. ' + holidayDesc
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(endTime)
        elif self.myDate.month == holidayEnd[0] and self.myDate.day == holidayEnd[1]:
            holidayText = myStrftime(endTime)
            holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
            holidayDesc = TTLocalizer.CalendarEndOf + holidayName
            holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(startTime)
        else:
            self.notify.error('unhandled case')
        self.addTitleAndDescToScrollList(holidayText, holidayDesc)

    def addOncelyHolidayToScrollList(self, holiday):
        holidayId = holiday[1]
        holidayStart = holiday[2]
        holidayEnd = holiday[3]
        holidayType = holiday[0]
        holidayText = ''
        startTime = datetime.time(holidayStart[3], holidayStart[4])
        endTime = datetime.time(holidayEnd[3], holidayEnd[4])
        startDate = datetime.date(holidayStart[0], holidayStart[1], holidayStart[2])
        endDate = datetime.date(holidayStart[0], holidayEnd[1], holidayEnd[2])
        if endDate < startDate:
            endDate = datetime.date(endDate.year + 1, endDate.month, endDate.day)
        if holidayId in TTLocalizer.HolidayNamesInCalendar:
            holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
            holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
        else:
            holidayName = TTLocalizer.UnknownHoliday % holidayId
            holidayDesc = ''
        if holidayStart[1] == holidayEnd[1] and holidayStart[2] == holidayEnd[2]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc = holidayName + '. ' + holidayDesc
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(endTime)
        elif self.myDate.year == holidayStart[0] and self.myDate.month == holidayStart[1] and self.myDate.day == holidayStart[2]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc = holidayName + '. ' + holidayDesc
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(endTime)
        elif self.myDate.year == holidayEnd[0] and self.myDate.month == holidayEnd[1] and self.myDate.day == holidayEnd[2]:
            holidayText = myStrftime(endTime)
            holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
            holidayDesc = TTLocalizer.CalendarEndOf + holidayName
            holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(startTime)
        else:
            self.notify.error('unhandled case')
        self.addTitleAndDescToScrollList(holidayText, holidayDesc)

    def addOncelyMultipleStartHolidayToScrollList(self, holiday):
        self.addOncelyHolidayToScrollList(holiday)

    def addRelativelyHolidayToScrollList(self, holiday):
        holidayId = holiday[1]
        holidayStart = holiday[2]
        holidayEnd = holiday[3]
        holidayType = holiday[0]
        holidayText = ''
        startTime = datetime.time(holidayStart[2], holidayStart[3])
        endTime = datetime.time(holidayEnd[2], holidayEnd[3])
        startDate = datetime.date(self.myDate.year, holidayStart[0], holidayStart[1])
        endDate = datetime.date(self.myDate.year, holidayEnd[0], holidayEnd[1])
        if endDate < startDate:
            endDate.year += 1
        if holidayId in TTLocalizer.HolidayNamesInCalendar:
            holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
            holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
        else:
            holidayName = TTLocalizer.UnknownHoliday % holidayId
            holidayDesc = ''
        if holidayStart[0] == holidayEnd[0] and holidayStart[1] == holidayEnd[1]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(endTime)
        elif self.myDate.month == holidayStart[0] and self.myDate.day == holidayStart[1]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc = holidayName + '. ' + holidayDesc
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(endTime)
        elif self.myDate.month == holidayEnd[0] and self.myDate.day == holidayEnd[1]:
            holidayText = myStrftime(endTime)
            holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
            holidayDesc = TTLocalizer.CalendarEndOf + holidayName
            holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(startTime)
        else:
            self.notify.error('unhandled case')
        self.addTitleAndDescToScrollList(holidayText, holidayDesc)

    def addTitleAndDescToScrollList(self, title, desc):
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        newItem = DirectButton(relief=None, text=title, text_scale=textSize, text_align=TextNode.ALeft, rolloverSound=None, clickSound=None, pressEffect=0, command=self.__clickedOnScrollItem)
        scrollItemHeight = newItem.getHeight()
        descUnderItemZAdjust = scrollItemHeight * descTextSize / textSize
        descUnderItemZAdjust = max(0.0534, descUnderItemZAdjust)
        descUnderItemZAdjust = -descUnderItemZAdjust
        descZAdjust = descUnderItemZAdjust
        newItem.description = DirectLabel(parent=newItem, pos=(0.115, 0, descZAdjust), text='', text_wordwrap=15, pad=(0.02, 0.02), text_scale=descTextSize, text_align=TextNode.ACenter, textMayChange=0)
        newItem.description.checkedHeight = False
        newItem.description.setBin('gui-popup', 0)
        newItem.description.hide()
        newItem.bind(DGG.ENTER, self.enteredTextItem, extraArgs=[newItem, desc, descUnderItemZAdjust])
        newItem.bind(DGG.EXIT, self.exitedTextItem, extraArgs=[newItem])
        self.scrollList.addItem(newItem)
        return

    def exitedTextItem(self, newItem, mousepos):
        newItem.description.hide()

    def enteredTextItem(self, newItem, descText, descUnderItemZAdjust, mousePos):
        if not newItem.description.checkedHeight:
            newItem.description.checkedHeight = True
            newItem.description['text'] = descText
            bounds = newItem.description.getBounds()
            descHeight = newItem.description.getHeight()
            scrollItemHeight = newItem.getHeight()
            descOverItemZAdjust = descHeight - scrollItemHeight / 2.0
            descZPos = self.getPos(aspect2d)[2] + descUnderItemZAdjust - descHeight
            if descZPos < -1.0:
                newItem.description.setZ(descOverItemZAdjust)
            descWidth = newItem.description.getWidth()
            brightFrame = loader.loadModel('phase_4/models/parties/tt_m_gui_sbk_calendar_popUp_bg')
            newItem.description['geom'] = brightFrame
            newItem.description['geom_scale'] = (descWidth, 1, descHeight)
            descGeomZ = (bounds[2] - bounds[3]) / 2.0
            descGeomZ += bounds[3]
            newItem.description['geom_pos'] = (0, 0, descGeomZ)
        newItem.description.show()

    def addPartyToScrollList(self, party):
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        partyTitle = myStrftime(party.startTime)
        partyTitle = partyTitle + ' ' + TTLocalizer.EventsPageCalendarTabParty
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        newItem = DirectButton(relief=None, text=partyTitle, text_scale=textSize, text_align=TextNode.ALeft, rolloverSound=None, clickSound=None, pressEffect=0, command=self.__clickedOnScrollItem)
        scrollItemHeight = newItem.getHeight()
        descUnderItemZAdjust = scrollItemHeight * descTextSize / textSize
        descUnderItemZAdjust = max(0.0534, descUnderItemZAdjust)
        descUnderItemZAdjust = -descUnderItemZAdjust
        descZAdjust = descUnderItemZAdjust
        self.scrollList.addItem(newItem)
        newItem.description = MiniInviteVisual(newItem, party)
        newItem.description.setBin('gui-popup', 0)
        newItem.description.hide()
        newItem.bind(DGG.ENTER, self.enteredTextItem, extraArgs=[newItem, newItem.description, descUnderItemZAdjust])
        newItem.bind(DGG.EXIT, self.exitedTextItem, extraArgs=[newItem])
        return

    def __clickedOnScrollItem(self):
        self.__clickedOnDay()

    def __clickedOnDay(self):
        acceptClick = True
        if self.onlyFutureDaysClickable:
            curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
            if self.myDate.date() < curServerDate.date():
                acceptClick = False
        if not acceptClick:
            return
        if self.dayClickCallback:
            self.dayClickCallback(self)
        self.notify.debug('we got clicked on %s' % self.myDate.date())
        messenger.send('clickedOnDay', [self.myDate.date()])

    def updateSelected(self, selected):
        multiplier = 1.1
        if selected:
            self.selectedFrame.show()
            self.setScale(multiplier)
            self.setPos(-0.01, 0, 0.01)
            grandParent = self.origParent.getParent()
            self.origParent.reparentTo(grandParent)
        else:
            self.selectedFrame.hide()
            self.setScale(1.0)
            self.setPos(0, 0, 0)

    def changeDate(self, startDate, myDate):
        self.startDate = startDate
        self.myDate = myDate
        self.scrollList.removeAndDestroyAllItems()
        self.update()

    def update(self):
        self.numberWidget['text'] = str(self.myDate.day)
        self.adjustForMonth()
        self.addWeeklyHolidays()
        self.collectTimedEvents()
        self.updateArrowButtons()

    def changeFilter(self, filter):
        oldFilter = self.filter
        self.filter = filter
        if self.filter != oldFilter:
            self.scrollList.removeAndDestroyAllItems()
            self.update()
class CalendarGuiDay(DirectFrame):
	notify = directNotify.newCategory('CalendarGuiDay')
	ScrollListTextSize = 0.03
	LargeTextSize = 0.0232

	def __init__(self, parent, myDate, startDate, dayClickCallback = None, onlyFutureDaysClickable = False):
		self.origParent = parent
		self.startDate = startDate
		self.myDate = myDate
		
		self.dayClickCallback = dayClickCallback
		self.onlyFutureDaysClickable = onlyFutureDaysClickable
		DirectFrame.__init__(self, parent=parent)
		self.timedEvents = []
		self.partiesInvitedToToday = []
		self.hostedPartiesToday = []
		self.yearlyHolidaysToday = []
		self.showMarkers = config.GetBool('show-calendar-markers', 0)
		self.filter = ToontownGlobals.CalendarFilterShowAll
		self.load()
		self.createGuiObjects()
		self.update()

	def createDummyLocators(self):
		self.dayButtonLocator = self.attachNewNode('dayButtonLocator')
		self.dayButtonLocator.setX(0.1)
		self.dayButtonLocator.setZ(-0.05)
		self.numberLocator = self.attachNewNode('numberLocator')
		self.numberLocator.setX(0.09)
		self.scrollLocator = self.attachNewNode('scrollLocator')
		self.selectedLocator = self.attachNewNode('selectedLocator')
		self.selectedLocator.setX(0.11)
		self.selectedLocator.setZ(-0.06)

	def load(self):
		dayAsset = loader.loadModel('phase_4/models/parties/tt_m_gui_sbk_calendar_box')
		dayAsset.reparentTo(self)
		self.dayButtonLocator = self.find('**/loc_origin')
		self.numberLocator = self.find('**/loc_number')
		self.scrollLocator = self.find('**/loc_topLeftList')
		self.selectedLocator = self.find('**/loc_origin')
		self.todayBox = self.find('**/boxToday')
		self.todayBox.hide()
		self.selectedFrame = self.find('**/boxHover')
		self.selectedFrame.hide()
		self.defaultBox = self.find('**/boxBlank')
		self.scrollBottomRightLocator = self.find('**/loc_bottomRightList')
		self.scrollDownLocator = self.find('**/loc_scrollDown')
		self.attachMarker(self.scrollDownLocator)
		self.scrollUpLocator = self.find('**/loc_scrollUp')
		self.attachMarker(self.scrollUpLocator)

	def attachMarker(self, parent, scale = 0.005, color = (1, 0, 0)):
		if self.showMarkers:
			marker = loader.loadModel('phase_3/models/misc/sphere')
			marker.reparentTo(parent)
			marker.setScale(scale)
			marker.setColor(*color)

	def createGuiObjects(self):
		self.dayButton = DirectButton(parent=self.dayButtonLocator, image=self.selectedFrame, relief=None, command=self.__clickedOnDay, pressEffect=1, rolloverSound=None, clickSound=None)
		self.numberWidget = DirectLabel(parent=self.numberLocator, relief=None, text=str(self.myDate.day), text_scale=0.04, text_align=TextNode.ACenter, text_font=ToontownGlobals.getInterfaceFont(), text_fg=Vec4(110 / 255.0, 126 / 255.0, 255 / 255.0, 1))
		self.attachMarker(self.numberLocator)
		self.listXorigin = 0
		self.listFrameSizeX = self.scrollBottomRightLocator.getX() - self.scrollLocator.getX()
		self.scrollHeight = self.scrollLocator.getZ() - self.scrollBottomRightLocator.getZ()
		self.listZorigin = self.scrollBottomRightLocator.getZ()
		self.listFrameSizeZ = self.scrollLocator.getZ() - self.scrollBottomRightLocator.getZ()
		self.arrowButtonXScale = 1
		self.arrowButtonZScale = 1
		self.itemFrameXorigin = 0
		self.itemFrameZorigin = 0
		self.buttonXstart = self.itemFrameXorigin + 0.21
		self.gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui')
		buttonOffSet = -0.01
		incButtonPos = (0.0, 0, 0)
		decButtonPos = (0.0, 0, 0)
		itemFrameMinZ = self.listZorigin
		itemFrameMaxZ = self.listZorigin + self.listFrameSizeZ
		arrowUp = self.find('**/downScroll_up')
		arrowDown = self.find('**/downScroll_down')
		arrowHover = self.find('**/downScroll_hover')
		self.scrollList = DirectScrolledList(parent=self.scrollLocator, relief=None, pos=(0, 0, 0), incButton_image=(arrowUp,
		 arrowDown,
		 arrowHover,
		 arrowUp), incButton_relief=None, incButton_scale=(self.arrowButtonXScale, 1, self.arrowButtonZScale), incButton_pos=incButtonPos, incButton_image3_color=Vec4(1, 1, 1, 0.2), decButton_image=(arrowUp,
		 arrowDown,
		 arrowHover,
		 arrowUp), decButton_relief=None, decButton_scale=(self.arrowButtonXScale, 1, -self.arrowButtonZScale), decButton_pos=decButtonPos, decButton_image3_color=Vec4(1, 1, 1, 0.2), itemFrame_pos=(self.itemFrameXorigin, 0, -0.03), numItemsVisible=4, incButtonCallback=self.scrollButtonPressed, decButtonCallback=self.scrollButtonPressed)
		itemFrameParent = self.scrollList.itemFrame.getParent()
		self.scrollList.incButton.reparentTo(self.scrollDownLocator)
		self.scrollList.decButton.reparentTo(self.scrollUpLocator)
		arrowUp.removeNode()
		arrowDown.removeNode()
		arrowHover.removeNode()
		clipper = PlaneNode('clipper')
		clipper.setPlane(Plane(Vec3(-1, 0, 0), Point3(0.23, 0, 0)))
		clipNP = self.scrollList.component('itemFrame').attachNewNode(clipper)
		self.scrollList.component('itemFrame').setClipPlane(clipNP)

	def scrollButtonPressed(self):
		self.__clickedOnDay()

	def adjustForMonth(self):
		curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
		if self.onlyFutureDaysClickable:
			if self.myDate.year < curServerDate.year or self.myDate.year == curServerDate.year and self.myDate.month < curServerDate.month or self.myDate.year == curServerDate.year and self.myDate.month == curServerDate.month and self.myDate.day < curServerDate.day:
				self.numberWidget.setColorScale(0.5, 0.5, 0.5, 0.5)
				self.numberWidget['state'] = DirectGuiGlobals.DISABLED
			else:
				self.numberWidget.setColorScale(1, 1, 1, 1)
		if self.myDate.month != self.startDate.month:
			self.setColorScale(0.75, 0.75, 0.75, 1.0)
			if self.dayClickCallback is not None:
				self.numberWidget['state'] = DirectGuiGlobals.DISABLED
		else:
			self.setColorScale(1, 1, 1, 1)
		if self.myDate.date() == curServerDate.date():
			self.defaultBox.hide()
			self.todayBox.show()
		else:
			self.defaultBox.show()
			self.todayBox.hide()

	def destroy(self):
		if self.dayClickCallback is not None:
			self.numberWidget.destroy()
		self.dayClickCallback = None
		self.notify.debug('desroying %s' % self.myDate)
		try:
			for item in self.scrollList['items']:
				if hasattr(item, 'description') and item.description and hasattr(item.description, 'destroy'):
					self.notify.debug('desroying description of item %s' % item)
					item.unbind(DGG.ENTER)
					item.unbind(DGG.EXIT)
					item.description.destroy()

		except e:
			self.notify.debug('pass %s' % self.myDate)

		self.scrollList.removeAndDestroyAllItems()
		self.scrollList.destroy()
		self.dayButton.destroy()
		DirectFrame.destroy(self)

	def addWeeklyHolidays(self):
		if not self.filter == ToontownGlobals.CalendarFilterShowAll and not self.filter == ToontownGlobals.CalendarFilterShowOnlyHolidays:
			return
		if base.cr.newsManager:
			holidays = base.cr.newsManager.getHolidaysForWeekday(self.myDate.weekday())
			holidayName = ''
			holidayDesc = ''
			for holidayId in holidays:
				if holidayId in TTLocalizer.HolidayNamesInCalendar:
					holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
					holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
				else:
					holidayName = TTLocalizer.UnknownHoliday % holidayId
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)

			self.scrollList.refresh()
		if config.GetBool('calendar-test-items', 0):
			if self.myDate.date() + datetime.timedelta(days=-1) == base.cr.toontownTimeManager.getCurServerDateTime().date():
				testItems = ('1:00 AM Party', '2:00 AM CEO', '11:15 AM Party', '5:30 PM CJ', '11:00 PM Party', 'Really Really Long String')
				for text in testItems:
					newItem = DirectLabel(relief=None, text=text, text_scale=self.ScrollListTextSize, text_align=TextNode.ALeft)
					self.scrollList.addItem(newItem)

			if self.myDate.date() + datetime.timedelta(days=-2) == base.cr.toontownTimeManager.getCurServerDateTime().date():
				testItems = ('1:00 AM Party', '3:00 AM CFO', '11:00 AM Party')
				textSize = self.ScrollListTextSize
				for text in testItems:
					newItem = DirectLabel(relief=None, text=text, text_scale=textSize, text_align=TextNode.ALeft)
					self.scrollList.addItem(newItem)

	def updateArrowButtons(self):
		numItems = 0
		try:
			numItems = len(self.scrollList['items'])
		except e:
			numItems = 0

		if numItems <= self.scrollList.numItemsVisible:
			self.scrollList.incButton.hide()
			self.scrollList.decButton.hide()
		else:
			self.scrollList.incButton.show()
			self.scrollList.decButton.show()

	def collectTimedEvents(self):
		self.timedEvents = []
		if self.filter == ToontownGlobals.CalendarFilterShowAll or self.filter == ToontownGlobals.CalendarFilterShowOnlyParties:
			for party in localAvatar.partiesInvitedTo:
				if party.startTime.date() == self.myDate.date():
					self.partiesInvitedToToday.append(party)
					self.timedEvents.append((party.startTime.time(), party))

			for party in localAvatar.hostedParties:
				if party.startTime.date() == self.myDate.date():
					self.hostedPartiesToday.append(party)
					self.timedEvents.append((party.startTime.time(), party))

		if base.cr.newsManager and (self.filter == ToontownGlobals.CalendarFilterShowAll or self.filter == ToontownGlobals.CalendarFilterShowOnlyHolidays):
			# December 14th - Winter
			if self.myDate.month == 12 and self.myDate.day == 14:
				holidayName = 'Winter Holiday'
				holidayDesc = 'Celebrate the Winter Holiday with Toontastic decorations,Cattlelog items and more!'
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			if self.myDate.weekday() == 4 or self.myDate.weekday() == 5:
				holidayName = 'Fish Bingo!'
				holidayDesc = 'Celebrate the weekend with bingo!'
			# Janurary 4th - end of Winter
			if self.myDate.month == 1 and self.myDate.day == 4:
				holidayName = 'Winter Holiday End'
				holidayDesc = 'The end of the Winter Holiday!'
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# December 30th - New year's fireworks
			if self.myDate.month == 12 and self.myDate.day == 30:
				holidayName = "New Year's Fireworks"
				holidayDesc = "Let us light the skys with Toontastic fireworks!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# December 31st - New year's fireworks
			if self.myDate.month == 12 and self.myDate.day == 31:
				holidayName = "New Year's Fireworks"
				holidayDesc = "Let us light the skys with Toontastic fireworks!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# October 21st - Halloween
			if self.myDate.month == 10 and self.myDate.day == 21:
				holidayName = "Halloween Holiday"
				holidayDesc = "Celebrate Halloween as spooky trees and streetlights transform Toontown!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# November 1st - end of halloween
			if self.myDate.month == 11 and self.myDate.day == 1:
				holidayName = " End of Halloween Holiday"
				holidayDesc = "The end of the Halloween Holiday!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# March 14th - Ides of March
			if self.myDate.month == 3 and self.myDate.day == 14:
				holidayName = "Ides of March Invasion"
				holidayDesc = "Beware the Ides of March! Stop the Backstabber Cogs from invading Toontown!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# March 15th - Ides of March
			if self.myDate.month == 3 and self.myDate.day == 15:
				holidayName = "Ides of March Invasion"
				holidayDesc = "Beware the Ides of March! Stop the Backstabber Cogs from invading Toontown!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# July 29th - XP week
			if self.myDate.month == 7 and self.myDate.day == 29:
				holidayName = "Triple XP Week"
				holidayDesc = "Celebrate Toontown with extra XP on ALL wacky gags!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# August 5th - end of XP week
			if self.myDate.month == 8 and self.myDate.day == 5:
				holidayName = "End of Triple XP Week"
				holidayDesc = "The end of the triple XP on gags"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)

			if self.myDate.month == 6 and self.myDate.day == 29:
				holidayName = "Summer Fireworks"
				holidayDesc = "Celebrate Summer with a fireworks show every hour in each playground!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# March 29th - April Toons' Week
			if self.myDate.month == 3 and self.myDate.day == 29:
				holidayName = "April Toons' Week"
				holidayDesc = "Celebrate April Toons' Week - a holiday built by Toons for Toons!!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# April 11th - April Toons end
			if self.myDate.month == 4 and self.myDate.day == 11:
				holidayName = "April Toons End"
				holidayDesc = "Here lies then end of all the April Toons' Sillyness!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)

			if self.myDate.month == 7 and self.myDate.day == 15:
				holidayName = "End of Summer Fireworks"
				holidayDesc = "Here lies the end of the Toontastic Summer Fireworks!"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			# 15th of April
			if self.myDate.month == 4 and self.myDate.day == 15:
				holidayName = "Tax Day Invasion"
				holidayDesc = "Number Crunchers are invading us. Apperntly we owe taxes! What are taxes?"
				self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 15 and not self.myDate.month == 4:
			# 	holidayName = "V2.0 Mover & Shakers"
			# 	holidayDesc = "V2.0 Mover & Shakers Cogs are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 31 and self.myDate.month == 1:
			# 	holidayName = "Skelecog Legal Eagle"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 31 and self.myDate.month == 3:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 31 and self.myDate.month == 5:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 31 and self.myDate.month == 7:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 31 and self.myDate.month == 8:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 31 and self.myDate.month == 10 :
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 31 and  self.myDate.month == 12:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 30 and self.myDate.month == 4:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 30 and self.myDate.month == 6:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 30 and self.myDate.month == 9:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 30 and self.myDate.month == 11:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			#
			# if self.myDate.day == 29 and self.myDate.month == 2:
			# 	holidayName = "Skelecog Legal Eagles"
			# 	holidayDesc = "Skelecog Legal Eagles are invading Toontown in masses! Stop them!"
			# 	self.addTitleAndDescToScrollList(holidayName, holidayDesc)
			
			oncelyHolidays = base.cr.newsManager.getOncelyHolidaysForDate(self.myDate)
			for holiday in oncelyHolidays:
				holidayId = holiday[1]
				holidayStart = holiday[2]
				holidayEnd = holiday[3]
				holidayType = holiday[0]
				if holidayStart[0] == self.myDate.year and holidayStart[1] == self.myDate.month and holidayStart[2] == self.myDate.day:
					myTime = datetime.time(holidayStart[3], holidayStart[4])
				elif holidayEnd[0] == self.myDate.year and holidayEnd[1] == self.myDate.month and holidayEnd[2] == self.myDate.day:
					myTime = datetime.time(holidayEnd[3], holidayEnd[4])
				else:
					self.notify.error('holiday is not today %s' % holiday)
				self.timedEvents.append((myTime, holiday))

			multipleStartHolidays = base.cr.newsManager.getMultipleStartHolidaysForDate(self.myDate)
			for holiday in multipleStartHolidays:
				holidayId = holiday[1]
				holidayStart = holiday[2]
				holidayEnd = holiday[3]
				holidayType = holiday[0]
				if holidayStart[0] == self.myDate.year and holidayStart[1] == self.myDate.month and holidayStart[2] == self.myDate.day:
					myTime = datetime.time(holidayStart[3], holidayStart[4])
				elif holidayEnd[0] == self.myDate.year and holidayEnd[1] == self.myDate.month and holidayEnd[2] == self.myDate.day:
					myTime = datetime.time(holidayEnd[3], holidayEnd[4])
				else:
					self.notify.error('holiday is not today %s' % holiday)
				self.timedEvents.append((myTime, holiday))

			relativelyHolidays = base.cr.newsManager.getRelativelyHolidaysForDate(self.myDate)
			for holiday in relativelyHolidays:
				holidayId = holiday[1]
				holidayStart = holiday[2]
				holidayEnd = holiday[3]
				holidayType = holiday[0]
				if holidayStart[0] == self.myDate.month and holidayStart[1] == self.myDate.day:
					myTime = datetime.time(holidayStart[2], holidayStart[3])
				elif holidayEnd[0] == self.myDate.month and holidayEnd[1] == self.myDate.day:
					myTime = datetime.time(holidayEnd[2], holidayEnd[3])
				else:
					self.notify.error('holiday is not today %s' % holiday)
				self.timedEvents.append((myTime, holiday))

		def timedEventCompare(te1, te2):
			if te1[0] < te2[0]:
				return -1
			elif te1[0] == te2[0]:
				return 0
			else:
				return 1

		self.timedEvents.sort(cmp=timedEventCompare)
		for timedEvent in self.timedEvents:
			if isinstance(timedEvent[1], PartyInfo):
				self.addPartyToScrollList(timedEvent[1])
			elif isinstance(timedEvent[1], tuple) and timedEvent[1][0] == NewsManager.YearlyHolidayType:
				self.addYearlyHolidayToScrollList(timedEvent[1])
			elif isinstance(timedEvent[1], tuple) and timedEvent[1][0] == NewsManager.OncelyHolidayType:
				self.addOncelyHolidayToScrollList(timedEvent[1])
			elif isinstance(timedEvent[1], tuple) and timedEvent[1][0] == NewsManager.OncelyMultipleStartHolidayType:
				self.addOncelyMultipleStartHolidayToScrollList(timedEvent[1])
			elif isinstance(timedEvent[1], tuple) and timedEvent[1][0] == NewsManager.RelativelyHolidayType:
				self.addRelativelyHolidayToScrollList(timedEvent[1])

	def addYearlyHolidayToScrollList(self, holiday):
		holidayId = holiday[1]
		holidayStart = holiday[2]
		holidayEnd = holiday[3]
		holidayType = holiday[0]
		holidayText = ''
		startTime = datetime.time(holidayStart[2], holidayStart[3])
		endTime = datetime.time(holidayEnd[2], holidayEnd[3])
		startDate = datetime.date(self.myDate.year, holidayStart[0], holidayStart[1])
		endDate = datetime.date(self.myDate.year, holidayEnd[0], holidayEnd[1])
		if endDate < startDate:
			endDate = datetime.date(endDate.year + 1, endDate.month, endDate.day)
		if holidayId in TTLocalizer.HolidayNamesInCalendar:
			holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
			holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
		else:
			holidayName = TTLocalizer.UnknownHoliday % holidayId
			holidayDesc = TTLocalizer.UnknownHoliday % holidayId
		if holidayStart[0] == holidayEnd[0] and holidayStart[1] == holidayEnd[1]:
			holidayText = myStrftime(startTime)
			holidayText += ' ' + holidayName
			holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(endTime)
		elif self.myDate.month == holidayStart[0] and self.myDate.day == holidayStart[1]:
			holidayText = myStrftime(startTime)
			holidayText += ' ' + holidayName
			holidayDesc = holidayName + '. ' + holidayDesc
			holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(endTime)
		elif self.myDate.month == holidayEnd[0] and self.myDate.day == holidayEnd[1]:
			holidayText = myStrftime(endTime)
			holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
			holidayDesc = TTLocalizer.CalendarEndOf + holidayName
			holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(startTime)
		else:
			self.notify.error('unhandled case')
		self.addTitleAndDescToScrollList(holidayText, holidayDesc)

	def addOncelyHolidayToScrollList(self, holiday):
		holidayId = holiday[1]
		holidayStart = holiday[2]
		holidayEnd = holiday[3]
		holidayType = holiday[0]
		holidayText = ''
		startTime = datetime.time(holidayStart[3], holidayStart[4])
		endTime = datetime.time(holidayEnd[3], holidayEnd[4])
		startDate = datetime.date(holidayStart[0], holidayStart[1], holidayStart[2])
		endDate = datetime.date(holidayStart[0], holidayEnd[1], holidayEnd[2])
		if endDate < startDate:
			endDate = datetime.date(endDate.year + 1, endDate.month, endDate.day)
		if holidayId in TTLocalizer.HolidayNamesInCalendar:
			holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
			holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
		else:
			holidayName = TTLocalizer.UnknownHoliday % holidayId
			holidayDesc = ''
		if holidayStart[1] == holidayEnd[1] and holidayStart[2] == holidayEnd[2]:
			holidayText = myStrftime(startTime)
			holidayText += ' ' + holidayName
			holidayDesc = holidayName + '. ' + holidayDesc
			holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(endTime)
		elif self.myDate.year == holidayStart[0] and self.myDate.month == holidayStart[1] and self.myDate.day == holidayStart[2]:
			holidayText = myStrftime(startTime)
			holidayText += ' ' + holidayName
			holidayDesc = holidayName + '. ' + holidayDesc
			holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(endTime)
		elif self.myDate.year == holidayEnd[0] and self.myDate.month == holidayEnd[1] and self.myDate.day == holidayEnd[2]:
			holidayText = myStrftime(endTime)
			holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
			holidayDesc = TTLocalizer.CalendarEndOf + holidayName
			holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(startTime)
		else:
			self.notify.error('unhandled case')
		self.addTitleAndDescToScrollList(holidayText, holidayDesc)

	def addOncelyMultipleStartHolidayToScrollList(self, holiday):
		self.addOncelyHolidayToScrollList(holiday)

	def addRelativelyHolidayToScrollList(self, holiday):
		holidayId = holiday[1]
		holidayStart = holiday[2]
		holidayEnd = holiday[3]
		holidayType = holiday[0]
		holidayText = ''
		startTime = datetime.time(holidayStart[2], holidayStart[3])
		endTime = datetime.time(holidayEnd[2], holidayEnd[3])
		startDate = datetime.date(self.myDate.year, holidayStart[0], holidayStart[1])
		endDate = datetime.date(self.myDate.year, holidayEnd[0], holidayEnd[1])
		if endDate < startDate:
			endDate.year += 1
		if holidayId in TTLocalizer.HolidayNamesInCalendar:
			holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
			holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
		else:
			holidayName = TTLocalizer.UnknownHoliday % holidayId
			holidayDesc = ''
		if holidayStart[0] == holidayEnd[0] and holidayStart[1] == holidayEnd[1]:
			holidayText = myStrftime(startTime)
			holidayText += ' ' + holidayName
			holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(endTime)
		elif self.myDate.month == holidayStart[0] and self.myDate.day == holidayStart[1]:
			holidayText = myStrftime(startTime)
			holidayText += ' ' + holidayName
			holidayDesc = holidayName + '. ' + holidayDesc
			holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(endTime)
		elif self.myDate.month == holidayEnd[0] and self.myDate.day == holidayEnd[1]:
			holidayText = myStrftime(endTime)
			holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
			holidayDesc = TTLocalizer.CalendarEndOf + holidayName
			holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(TTLocalizer.HolidayFormat) + myStrftime(startTime)
		else:
			self.notify.error('unhandled case')
		self.addTitleAndDescToScrollList(holidayText, holidayDesc)

	def addTitleAndDescToScrollList(self, title, desc):
		textSize = self.ScrollListTextSize
		descTextSize = 0.05
		newItem = DirectButton(relief=None, text=title, text_scale=textSize, text_align=TextNode.ALeft, rolloverSound=None, clickSound=None, pressEffect=0, command=self.__clickedOnScrollItem)
		scrollItemHeight = newItem.getHeight()
		descUnderItemZAdjust = scrollItemHeight * descTextSize / textSize
		descUnderItemZAdjust = max(0.0534, descUnderItemZAdjust)
		descUnderItemZAdjust = -descUnderItemZAdjust
		descZAdjust = descUnderItemZAdjust
		newItem.description = DirectLabel(parent=newItem, pos=(0.115, 0, descZAdjust), text='', text_wordwrap=15, pad=(0.02, 0.02), text_scale=descTextSize, text_align=TextNode.ACenter, textMayChange=0)
		newItem.description.checkedHeight = False
		newItem.description.setBin('gui-popup', 0)
		newItem.description.hide()
		newItem.bind(DGG.ENTER, self.enteredTextItem, extraArgs=[newItem, desc, descUnderItemZAdjust])
		newItem.bind(DGG.EXIT, self.exitedTextItem, extraArgs=[newItem])
		self.scrollList.addItem(newItem)

	def exitedTextItem(self, newItem, mousepos):
		newItem.description.hide()

	def enteredTextItem(self, newItem, descText, descUnderItemZAdjust, mousePos):
		if not newItem.description.checkedHeight:
			newItem.description.checkedHeight = True
			newItem.description['text'] = descText
			bounds = newItem.description.getBounds()
			descHeight = newItem.description.getHeight()
			scrollItemHeight = newItem.getHeight()
			descOverItemZAdjust = descHeight - scrollItemHeight / 2.0
			descZPos = self.getPos(aspect2d)[2] + descUnderItemZAdjust - descHeight
			if descZPos < -1.0:
				newItem.description.setZ(descOverItemZAdjust)
			descWidth = newItem.description.getWidth()
			brightFrame = loader.loadModel('phase_4/models/parties/tt_m_gui_sbk_calendar_popUp_bg')
			newItem.description['geom'] = brightFrame
			newItem.description['geom_scale'] = (descWidth, 1, descHeight)
			descGeomZ = (bounds[2] - bounds[3]) / 2.0
			descGeomZ += bounds[3]
			newItem.description['geom_pos'] = (0, 0, descGeomZ)
		newItem.description.show()

	def addPartyToScrollList(self, party):
		textSize = self.ScrollListTextSize
		descTextSize = 0.05
		partyTitle = myStrftime(party.startTime)
		partyTitle = partyTitle + ' ' + TTLocalizer.EventsPageCalendarTabParty
		textSize = self.ScrollListTextSize
		descTextSize = 0.05
		newItem = DirectButton(relief=None, text=partyTitle, text_scale=textSize, text_align=TextNode.ALeft, rolloverSound=None, clickSound=None, pressEffect=0, command=self.__clickedOnScrollItem)
		scrollItemHeight = newItem.getHeight()
		descUnderItemZAdjust = scrollItemHeight * descTextSize / textSize
		descUnderItemZAdjust = max(0.0534, descUnderItemZAdjust)
		descUnderItemZAdjust = -descUnderItemZAdjust
		descZAdjust = descUnderItemZAdjust
		self.scrollList.addItem(newItem)
		newItem.description = MiniInviteVisual(newItem, party)
		newItem.description.setBin('gui-popup', 0)
		newItem.description.hide()
		newItem.bind(DGG.ENTER, self.enteredTextItem, extraArgs=[newItem, newItem.description, descUnderItemZAdjust])
		newItem.bind(DGG.EXIT, self.exitedTextItem, extraArgs=[newItem])

	def __clickedOnScrollItem(self):
		self.__clickedOnDay()

	def __clickedOnDay(self):
		acceptClick = True
		if self.onlyFutureDaysClickable:
			curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
			if self.myDate.date() < curServerDate.date():
				acceptClick = False
		if not acceptClick:
			return
		if self.dayClickCallback:
			self.dayClickCallback(self)
		self.notify.debug('we got clicked on %s' % self.myDate.date())
		messenger.send('clickedOnDay', [self.myDate.date()])

	def updateSelected(self, selected):
		multiplier = 1.1
		if selected:
			self.selectedFrame.show()
			self.setScale(multiplier)
			self.setPos(-0.01, 0, 0.01)
			grandParent = self.origParent.getParent()
			self.origParent.reparentTo(grandParent)
		else:
			self.selectedFrame.hide()
			self.setScale(1.0)
			self.setPos(0, 0, 0)

	def changeDate(self, startDate, myDate):
		self.startDate = startDate
		self.myDate = myDate
		self.scrollList.removeAndDestroyAllItems()
		self.update()

	def update(self):
		self.numberWidget['text'] = str(self.myDate.day)
		self.adjustForMonth()
		self.addWeeklyHolidays()
		self.collectTimedEvents()
		self.updateArrowButtons()

	def changeFilter(self, filter):
		oldFilter = self.filter
		self.filter = filter
		if self.filter != oldFilter:
			self.scrollList.removeAndDestroyAllItems()
			self.update()
예제 #39
0
class QuestMap(DirectFrame):

    def __init__(self, av, **kw):
        DirectFrame.__init__(self, relief=None, sortOrder=50)
        self.initialiseoptions(QuestMap)
        self.container = DirectFrame(parent=self, relief=None)
        self.marker = DirectFrame(parent=self.container, relief=None)
        self.cogInfoFrame = DirectFrame(parent=self.container, relief=None)
        cm = CardMaker('bg')
        cm.setFrame(-0.5, 0.5, -0.5, 0.5)
        bg = self.cogInfoFrame.attachNewNode(cm.generate())
        bg.setTransparency(1)
        bg.setColor(0.5, 0.5, 0.5, 0.5)
        bg.setBin('fixed', 0)
        self.cogInfoFrame['geom'] = bg
        self.cogInfoFrame['geom_pos'] = (0, 0, 0)
        self.cogInfoFrame['geom_scale'] = (6, 1, 2)
        self.cogInfoFrame.setScale(0.05)
        self.cogInfoFrame.setPos(0, 0, 0.6)
        self.buildingMarkers = []
        self.av = av
        self.wantToggle = False
        if base.config.GetBool('want-toggle-quest-map', True):
            self.wantToggle = True
        self.updateMarker = True
        self.cornerPosInfo = None
        self.hqPosInfo = None
        self.fishingSpotInfo = None
        self.load()
        self.setScale(1.5)
        bg.removeNode()
        self.hoodId = None
        self.zoneId = None
        self.suitPercentage = {}
        for currHoodInfo in SuitPlannerBase.SuitPlannerBase.SuitHoodInfo:
            tracks = currHoodInfo[SuitPlannerBase.SuitPlannerBase.SUIT_HOOD_INFO_TRACK]
            self.suitPercentage[currHoodInfo[SuitPlannerBase.SuitPlannerBase.SUIT_HOOD_INFO_ZONE]] = tracks

        return

    def load(self):
        gui = loader.loadModel('phase_4/models/questmap/questmap_gui')
        icon = gui.find('**/tt_t_gui_qst_arrow')
        iconNP = aspect2d.attachNewNode('iconNP')
        icon.reparentTo(iconNP)
        icon.setR(90)
        self.marker['geom'] = iconNP
        self.marker['image'] = iconNP
        self.marker.setScale(0.05)
        iconNP.removeNode()
        self.mapOpenButton = DirectButton(image=(gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapClose'), gui.find('**/tt_t_gui_qst_mapTryToOpen')), relief=None, pos=(-0.08, 0, 0.37), parent=base.a2dBottomRight, scale=0.205, command=self.show)
        self.mapCloseButton = DirectButton(image=(gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapOpen'), gui.find('**/tt_t_gui_qst_mapTryToClose')), relief=None, pos=(-0.08, 0, 0.37), parent=base.a2dBottomRight, scale=0.205, command=self.hide)
        self.mapOpenButton.hide()
        self.mapCloseButton.hide()
        gui.removeNode()
        icons = loader.loadModel('phase_3/models/gui/cog_icons')
        cIcon = icons.find('**/CorpIcon')
        lIcon = icons.find('**/LegalIcon')
        mIcon = icons.find('**/MoneyIcon')
        sIcon = icons.find('**/SalesIcon')
        cogInfoTextColor = (0.2, 0.2, 0.2, 1)
        textPos = (1.2, -0.2)
        textScale = 0.8
        self.cInfo = DirectLabel(parent=self.cogInfoFrame, text='', text_fg=cogInfoTextColor, text_pos=textPos, text_scale=textScale, geom=cIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None)
        self.cInfo.setPos(-2.2, 0, 0.5)
        self.lInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=lIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None)
        self.lInfo.setPos(-2.2, 0, -0.5)
        self.mInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=mIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None)
        self.mInfo.setPos(0.8, 0, 0.5)
        self.sInfo = DirectLabel(parent=self.cogInfoFrame, text_fg=cogInfoTextColor, text='', text_pos=textPos, text_scale=textScale, geom=sIcon, geom_pos=(-0.2, 0, 0), geom_scale=0.8, relief=None)
        self.sInfo.setPos(0.8, 0, -0.5)
        icons.removeNode()
        return

    def updateCogInfo(self):
        currPercentage = self.suitPercentage.get(self.zoneId)
        if currPercentage is None:
            return
        self.cInfo['text'] = '%s%%' % currPercentage[0]
        self.lInfo['text'] = '%s%%' % currPercentage[1]
        self.mInfo['text'] = '%s%%' % currPercentage[2]
        self.sInfo['text'] = '%s%%' % currPercentage[3]
        return

    def destroy(self):
        self.ignore('questPageUpdated')
        self.mapOpenButton.destroy()
        self.mapCloseButton.destroy()
        del self.mapOpenButton
        del self.mapCloseButton
        DirectFrame.destroy(self)

    def putBuildingMarker(self, pos, hpr = (0, 0, 0), mapIndex = None):
        marker = DirectLabel(parent=self.container, text='', text_pos=(-0.05, -0.15), text_fg=(1, 1, 1, 1), relief=None)
        gui = loader.loadModel('phase_4/models/parties/schtickerbookHostingGUI')
        icon = gui.find('**/startPartyButton_inactive')
        iconNP = aspect2d.attachNewNode('iconNP')
        icon.reparentTo(iconNP)
        icon.setX(-12.0792 / 30.48)
        icon.setZ(-9.7404 / 30.48)
        marker['text'] = '%s' % mapIndex
        marker['text_scale'] = 0.7
        marker['image'] = iconNP
        marker['image_color'] = (1, 0, 0, 1)
        marker['image_scale'] = 6
        marker.setScale(0.05)
        relX, relY = self.transformAvPos(pos)
        marker.setPos(relX, 0, relY)
        self.buildingMarkers.append(marker)
        iconNP.removeNode()
        gui.removeNode()
        return

    def updateQuestInfo(self):
        for marker in self.buildingMarkers:
            marker.destroy()

        self.buildingMarkers = []

        for (i, questDesc) in enumerate(self.av.quests):
            mapIndex = i + 1
            quest = Quests.getQuest(questDesc[0])
            toNpcId = questDesc[2]

            completed = quest.getCompletionStatus(self.av, questDesc) == Quests.COMPLETE
            if not completed:
                if quest.getType() == Quests.RecoverItemQuest:
                    if quest.getHolder() == Quests.AnyFish:
                        self.putBuildingMarker(self.fishingSpotInfo, mapIndex=mapIndex)
                    continue
                elif quest.getType() not in (
                    Quests.DeliverGagQuest, Quests.DeliverItemQuest,
                    Quests.VisitQuest, Quests.TrackChoiceQuest):
                    continue

            if toNpcId == Quests.ToonHQ:
                self.putBuildingMarker(self.hqPosInfo, mapIndex=mapIndex)
                continue

            npcZoneId = NPCToons.getNPCZone(toNpcId)
            hoodId = ZoneUtil.getCanonicalHoodId(npcZoneId)
            branchId = ZoneUtil.getCanonicalBranchZone(npcZoneId)

            if (self.hoodId != hoodId) or (self.zoneId != branchId):
                continue

            for blockIndex in xrange(base.cr.playGame.dnaStore.getNumBlockNumbers()):
                blockNumber = base.cr.playGame.dnaStore.getBlockNumberAt(blockIndex)
                zoneId = base.cr.playGame.dnaStore.getZoneFromBlockNumber(blockNumber)
                interiorZoneId = (zoneId - (zoneId%100)) + 500 + blockNumber
                if npcZoneId == interiorZoneId:
                    self.putBuildingMarker(
                        base.cr.playGame.dnaStore.getDoorPosHprFromBlockNumber(blockNumber).getPos(render),
                        base.cr.playGame.dnaStore.getDoorPosHprFromBlockNumber(blockNumber).getHpr(render),
                        mapIndex=mapIndex)

    def transformAvPos(self, pos):
        if self.cornerPosInfo is None:
            return (0, 0)
        topRight = self.cornerPosInfo[0]
        bottomLeft = self.cornerPosInfo[1]
        relativeX = (pos.getX() - bottomLeft.getX()) / (topRight.getX() - bottomLeft.getX()) - 0.5
        relativeY = (pos.getY() - bottomLeft.getY()) / (topRight.getY() - bottomLeft.getY()) - 0.5
        return (relativeX, relativeY)

    def update(self, task):
        if self.av:
            if self.updateMarker:
                relX, relY = self.transformAvPos(self.av.getPos())
                self.marker.setPos(relX, 0, relY)
                self.marker.setHpr(0, 0, -180 - self.av.getH())
        i = 0
        for buildingMarker in self.buildingMarkers:
            buildingMarker.setScale((math.sin(task.time * 16.0 + i * math.pi / 3.0) + 1) * 0.005 + 0.04)
            i = i + 1

        return Task.cont

    def updateMap(self):
        if self.av:
            hoodId = ZoneUtil.getCanonicalHoodId(self.av.getLocation()[1])
            zoneId = ZoneUtil.getCanonicalBranchZone(self.av.getLocation()[1])
            try:
                mapsGeom = loader.loadModel('phase_4/models/questmap/%s_maps' % ToontownGlobals.dnaMap[hoodId])
            except:
                self.stop()
                return
            mapImage = mapsGeom.find('**/%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId))
            if not mapImage.isEmpty():
                self.container['image'] = mapImage
                self.resetFrameSize()
                self.cornerPosInfo = QuestMapGlobals.CornerPosTable.get('%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId))
                self.hqPosInfo = QuestMapGlobals.HQPosTable.get('%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId))
                self.fishingSpotInfo = QuestMapGlobals.FishingSpotPosTable.get('%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId))
                self.cogInfoPos = QuestMapGlobals.CogInfoPosTable.get('%s_%s_english' % (ToontownGlobals.dnaMap[hoodId], zoneId))
                self.cogInfoFrame.setPos(self.cogInfoPos)
                self.hide()
                self.hoodId = hoodId
                self.zoneId = zoneId
                self.updateQuestInfo()
                self.updateCogInfo()
                taskMgr.add(self.update, 'questMapUpdate')
            else:
                self.stop()
                mapsGeom.removeNode()

    def start(self):
        self.container.show()
        self.accept('questPageUpdated', self.updateMap)
        self.handleMarker()
        self.updateMap()

    def initMarker(self, task):
        if self.av:
            if not hasattr(base.cr.playGame.getPlace(), 'isInterior') or not base.cr.playGame.getPlace().isInterior:
                relX, relY = self.transformAvPos(self.av.getPos())
                self.marker.setPos(relX, 0, relY)
                self.marker.setHpr(0, 0, -180 - self.av.getH())
            self.marker['geom_scale'] = 1.4 * task.time % 0.5 * 10 + 1
            self.marker['geom_color'] = (1,
             1,
             1,
             0.8 - 1.4 * task.time % 0.5 * 2 / 0.8 + 0.2)
        if task.time < 1:
            return Task.cont
        else:
            self.marker['geom_color'] = (1, 1, 1, 0)
            return Task.done

    def show(self):
        taskMgr.add(self.initMarker, 'questMapInit')
        DirectFrame.show(self)
        self.mapOpenButton.hide()
        if self.container['image']:
            self.mapCloseButton.show()

    def hide(self):
        taskMgr.remove('questMapInit')
        DirectFrame.hide(self)
        if self.container['image']:
            self.mapOpenButton.show()
        self.mapCloseButton.hide()

    def toggle(self):
        if self.isHidden():
            self.show()
        else:
            self.hide()

    def obscureButton(self):
        self.mapOpenButton.hide()
        self.mapCloseButton.hide()

    def stop(self):
        self.container['image'] = None
        for marker in self.buildingMarkers:
            marker.destroy()

        self.buildingMarkers = []
        self.container.hide()
        self.hide()
        self.obscureButton()
        self.ignore('questPageUpdated')
        taskMgr.remove('questMapUpdate')
        return

    def handleMarker(self):
        if hasattr(base.cr.playGame.getPlace(), 'isInterior') and base.cr.playGame.getPlace().isInterior:
            self.updateMarker = False
        else:
            self.updateMarker = True

    def acceptOnscreenHooks(self):
        if self.wantToggle:
            self.accept(ToontownGlobals.MapHotkey, self.toggle)
        else:
            self.accept(ToontownGlobals.MapHotkeyOn, self.show)
            self.accept(ToontownGlobals.MapHotkeyOff, self.hide)
        self.updateMap()

    def ignoreOnscreenHooks(self):
        self.ignore(ToontownGlobals.MapHotkey)
        self.ignore(ToontownGlobals.MapHotkeyOn)
        self.ignore(ToontownGlobals.MapHotkeyOff)
        self.obscureButton()
예제 #40
0
 def destroy(self):
     self.unbind(DirectGuiGlobals.B1PRESS)
     self.unbind(DirectGuiGlobals.B1RELEASE)
     self.unbind(DirectGuiGlobals.ENTER)
     self.unbind(DirectGuiGlobals.EXIT)
     DirectButton.destroy(self)
예제 #41
0
class PartyEditor(DirectObject, FSM):
    notify = directNotify.newCategory('PartyEditor')

    def __init__(self, partyPlanner, parent):
        FSM.__init__(self, self.__class__.__name__)
        self.partyPlanner = partyPlanner
        self.parent = parent
        self.partyEditorGrid = PartyEditorGrid(self)
        self.currentElement = None
        self.defaultTransitions = {'Hidden': ['Idle', 'Cleanup'],
         'Idle': ['DraggingElement', 'Hidden', 'Cleanup'],
         'DraggingElement': ['Idle',
                             'DraggingElement',
                             'Hidden',
                             'Cleanup'],
         'Cleanup': []}
        self.initElementList()
        self.initPartyClock()
        self.initTrashCan()
        return

    def initElementList(self):
        self.activityIconsModel = loader.loadModel('phase_4/models/parties/eventSignIcons')
        self.decorationModels = loader.loadModel('phase_4/models/parties/partyDecorations')
        pos = self.partyPlanner.gui.find('**/step_05_activitiesIcon_locator').getPos()
        self.elementList = DirectScrolledList(parent=self.parent, relief=None, decButton_image=(self.partyPlanner.gui.find('**/activitiesButtonUp_up'),
         self.partyPlanner.gui.find('**/activitiesButtonUp_down'),
         self.partyPlanner.gui.find('**/activitiesButtonUp_rollover'),
         self.partyPlanner.gui.find('**/activitiesButtonUp_inactive')), decButton_relief=None, decButton_pos=(-0.05, 0.0, -0.38), incButton_image=(self.partyPlanner.gui.find('**/activitiesButtonDown_up'),
         self.partyPlanner.gui.find('**/activitiesButtonDown_down'),
         self.partyPlanner.gui.find('**/activitiesButtonDown_rollover'),
         self.partyPlanner.gui.find('**/activitiesButtonDown_inactive')), incButton_relief=None, incButton_pos=(-0.05, 0.0, -0.94), itemFrame_pos=(pos[0], pos[1], pos[2] + 0.04), itemFrame_relief=None, numItemsVisible=1, items=[])
        holidayIds = base.cr.newsManager.getHolidayIdList()
        isWinter = ToontownGlobals.WINTER_DECORATIONS in holidayIds or ToontownGlobals.WACKY_WINTER_DECORATIONS in holidayIds
        isVictory = ToontownGlobals.VICTORY_PARTY_HOLIDAY in holidayIds
        isValentine = ToontownGlobals.VALENTINES_DAY in holidayIds
        for activityId in PartyGlobals.PartyEditorActivityOrder:
            if not isVictory and activityId in PartyGlobals.VictoryPartyActivityIds or not isWinter and activityId in PartyGlobals.WinterPartyActivityIds or not isValentine and activityId in PartyGlobals.ValentinePartyActivityIds:
                pass
            elif isVictory and activityId in PartyGlobals.VictoryPartyReplacementActivityIds or isWinter and activityId in PartyGlobals.WinterPartyReplacementActivityIds or isValentine and activityId in PartyGlobals.ValentinePartyReplacementActivityIds:
                pass
            else:
                pele = PartyEditorListElement(self, activityId)
                self.elementList.addItem(pele)
                if activityId == PartyGlobals.ActivityIds.PartyClock:
                    self.partyClockElement = pele

        for decorationId in PartyGlobals.DecorationIds:
            if not isVictory and decorationId in PartyGlobals.VictoryPartyDecorationIds or not isWinter and decorationId in PartyGlobals.WinterPartyDecorationIds or not isValentine and decorationId in PartyGlobals.ValentinePartyDecorationIds:
                pass
            elif isVictory and decorationId in PartyGlobals.VictoryPartyReplacementDecorationIds or isValentine and decorationId in PartyGlobals.ValentinePartyReplacementDecorationIds:
                pass
            elif decorationId in PartyGlobals.TTIUnreleasedDecor:
                pass
            else:
                pele = PartyEditorListElement(self, decorationId, isDecoration=True)
                self.elementList.addItem(pele)

        self.elementList.refresh()
        self.elementList['command'] = self.scrollItemChanged
        return

    def initPartyClock(self):
        self.partyClockElement.buyButtonClicked((8, 7))

    def initTrashCan(self):
        trashcanGui = loader.loadModel('phase_3/models/gui/trashcan_gui')
        self.trashCanButton = DirectButton(parent=self.parent, relief=None, pos=Point3(*PartyGlobals.TrashCanPosition), scale=PartyGlobals.TrashCanScale, geom=(trashcanGui.find('**/TrashCan_CLSD'),
         trashcanGui.find('**/TrashCan_OPEN'),
         trashcanGui.find('**/TrashCan_RLVR'),
         trashcanGui.find('**/TrashCan_RLVR')), command=self.trashCanClicked)
        self.trashCanButton.bind(DirectGuiGlobals.ENTER, self.mouseEnterTrash)
        self.trashCanButton.bind(DirectGuiGlobals.EXIT, self.mouseExitTrash)
        self.mouseOverTrash = False
        self.oldInstructionText = ''
        self.trashCanLastClickedTime = 0
        return

    def scrollItemChanged(self):
        if not self.elementList['items']:
            return
        self.currentElement = self.elementList['items'][self.elementList.getSelectedIndex()]
        self.elementList['items'][self.elementList.getSelectedIndex()].elementSelectedFromList()
        if self.elementList['items'][self.elementList.getSelectedIndex()].isDecoration:
            self.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsClickedElementDecoration
        else:
            self.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsClickedElementActivity

    def listElementClicked(self):
        self.request('DraggingElement')

    def listElementReleased(self):
        self.request('Idle', True)

    def trashCanClicked(self):
        currentTime = time.time()
        if currentTime - self.trashCanLastClickedTime < 0.2:
            self.clearPartyGrounds()
        self.trashCanLastClickedTime = time.time()

    def clearPartyGrounds(self):
        for item in self.elementList['items']:
            item.clearPartyGrounds()

        self.initPartyClock()
        if self.currentElement:
            self.currentElement.checkSoldOutAndPaidStatusAndAffordability()

    def buyCurrentElement(self):
        if self.currentElement:
            purchaseSuccessful = self.currentElement.buyButtonClicked()
            if purchaseSuccessful:
                self.handleMutuallyExclusiveActivities()
            else:
                self.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsNoRoom

    def mouseEnterTrash(self, mouseEvent):
        self.mouseOverTrash = True
        self.oldInstructionText = self.partyPlanner.instructionLabel['text']
        self.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsTrash

    def mouseExitTrash(self, mouseEvent):
        self.mouseOverTrash = False
        self.partyPlanner.instructionLabel['text'] = self.oldInstructionText

    def enterHidden(self):
        PartyEditor.notify.debug('Enter Hidden')

    def exitHidden(self):
        PartyEditor.notify.debug('Exit Hidden')

    def enterIdle(self, fromDragging = False):
        PartyEditor.notify.debug('Enter Idle')
        if not fromDragging:
            self.elementList.scrollTo(0)
            self.elementList['items'][0].elementSelectedFromList()
            self.currentElement = self.elementList['items'][self.elementList.getSelectedIndex()]
            self.currentElement.checkSoldOutAndPaidStatusAndAffordability()
        self.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsIdle
        self.updateCostsAndBank()
        self.handleMutuallyExclusiveActivities()

    def handleMutuallyExclusiveActivities(self):
        mutSet = self.getMutuallyExclusiveActivities()
        if not mutSet:
            return
        currentActivities = self.partyEditorGrid.getActivitiesElementsOnGrid()
        lastActivity = self.partyEditorGrid.lastActivityIdPlaced
        for act in currentActivities:
            if act.id in mutSet and not lastActivity == act.id:
                act.removeFromGrid()
                removedName = TTLocalizer.PartyActivityNameDict[act.id]['editor']
                addedName = TTLocalizer.PartyActivityNameDict[lastActivity]['editor']
                instr = TTLocalizer.PartyPlannerEditorInstructionsRemoved % {'removed': removedName,
                 'added': addedName}
                self.partyPlanner.instructionLabel['text'] = instr
                self.updateCostsAndBank()

    def getMutuallyExclusiveActivities(self):
        currentActivities = self.partyEditorGrid.getActivitiesOnGrid()
        actSet = Set([])
        for act in currentActivities:
            actSet.add(act[0])

        result = None
        for mutuallyExclusiveTuples in PartyGlobals.MutuallyExclusiveActivities:
            mutSet = Set(mutuallyExclusiveTuples)
            inter = mutSet.intersection(actSet)
            if len(inter) > 1:
                result = inter
                break

        return result

    def updateCostsAndBank(self):
        currentActivities = self.partyEditorGrid.getActivitiesOnGrid()
        currentDecorations = self.partyEditorGrid.getDecorationsOnGrid()
        newCost = 0
        for elementTuple in currentActivities:
            newCost += PartyGlobals.ActivityInformationDict[elementTuple[0]]['cost']

        for elementTuple in currentDecorations:
            newCost += PartyGlobals.DecorationInformationDict[elementTuple[0]]['cost']

        self.partyPlanner.costLabel['text'] = TTLocalizer.PartyPlannerTotalCost % newCost
        if len(currentActivities) > 0 or len(currentDecorations) > 0:
            self.partyPlanner.setNextButtonState(enabled=True)
        else:
            self.partyPlanner.setNextButtonState(enabled=False)
        self.partyPlanner.totalCost = newCost
        self.partyPlanner.beanBank['text'] = str(int(self.partyPlanner.totalMoney - self.partyPlanner.totalCost))

    def exitIdle(self):
        PartyEditor.notify.debug('Exit Idle')

    def enterDraggingElement(self):
        PartyEditor.notify.debug('Enter DraggingElement')
        if self.currentElement.isDecoration:
            self.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsDraggingDecoration
        else:
            self.partyPlanner.instructionLabel['text'] = TTLocalizer.PartyPlannerEditorInstructionsDraggingActivity

    def exitDraggingElement(self):
        PartyEditor.notify.debug('Exit DraggingElement')

    def enterCleanup(self):
        PartyEditor.notify.debug('Enter Cleanup')
        self.partyEditorGrid.destroy()
        self.elementList.removeAndDestroyAllItems()
        self.elementList.destroy()
        self.trashCanButton.unbind(DirectGuiGlobals.ENTER)
        self.trashCanButton.unbind(DirectGuiGlobals.EXIT)
        self.trashCanButton.destroy()

    def exitCleanup(self):
        PartyEditor.notify.debug('Exit Cleanup')
예제 #42
0
  def render(self):
    ''' traverse the tree and update the visuals according to it
    '''
    for treeItem in self.treeStructure.getRec():
      # create nodes that have no visual elements
      if not treeItem in self.treeStructureNodes:
        treeNode = self.childrenCanvas.attachNewNode('')
        
        hor=self.horizontalTreeLine.instanceUnderNode(treeNode,'')
        vert=self.verticalTreeLine.instanceUnderNode(treeNode,'')
        vert.setZ(0.007)
        hor.setPos(-1.5*self.itemIndent,0,self.itemScale*.25)
        vert.setX(-.5*self.itemIndent)
        
        nodeButton = DirectButton(
            parent=treeNode,
            scale=self.itemScale,
            relief=DGG.FLAT,
            text_scale=self.itemTextScale,
            text_align=TextNode.ALeft,
            text=treeItem.name,
            rolloverSound=None,
            #clickSound=None,
          )
        nodeButton.bind(DGG.B1PRESS,treeItem.button1press)
        nodeButton.bind(DGG.B2PRESS,treeItem.button2press)
        nodeButton.bind(DGG.B3PRESS,treeItem.button3press)
        
        #treeButton = None
        #if len(treeItem.childrens) > 0:
        treeButton = DirectButton(
            parent=nodeButton,
            frameColor=(1,1,1,1),
            frameSize=(-.4,.4,-.4,.4),
            pos=(-.5*self.itemIndent/self.itemScale,0,.25),
            text='',
            text_pos=(-.1,-.22),
            text_scale=(1.6,1),
            text_fg=(0,0,0,1),
            enableEdit=0,
            command=treeItem.setOpen,
            sortOrder=1000,
            rolloverSound=None,
            #clickSound=None,
          )
        

        self.treeStructureNodes[treeItem] = [treeNode, nodeButton, treeButton, hor, vert]
    
    # destroy nodes no more used
    for treeItem in self.treeStructureNodes.keys()[:]:
      #treeItem = self.treeStructureNodes[treeName]
      if treeItem not in self.treeStructure.getRec():
        treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[treeItem]
        #nodeButton['text']=''
        nodeButton.unbind(DGG.B1PRESS)
        nodeButton.unbind(DGG.B2PRESS)
        nodeButton.unbind(DGG.B3PRESS)
        #nodeButton.detachNode()
        #nodeButton.removeNode()
        nodeButton.destroy()
        if treeButton:
          #treeButton['text']=''
          #treeButton['command']=None
          treeButton.detachNode()
          treeButton.removeNode()
        hor.detachNode()
        hor.removeNode()
        vert.detachNode()
        vert.removeNode()
        treeItem.destroy()
        #treeNode.detachNode()
        treeNode.removeNode()
        #treeNode.destroy()
        del self.treeStructureNodes[treeItem]
    
    frameHeight = len(self.treeStructureNodes) * self.verticalSpacing
    self.childrenFrame['canvasSize'] = (0, self.frameWidth-self.itemScale*2, 0, frameHeight)
    self.childrenCanvas.setZ(frameHeight-1)
class DistributedPartyTrampolineActivity(DistributedPartyActivity):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyTrampolineActivity')

    def __init__(self, cr, doJellyBeans = True, doTricks = False, texture = None):
        DistributedPartyTrampolineActivity.notify.debug('__init__')
        DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityTypes.GuestInitiated, wantLever=False, wantRewardGui=True)
        self.doJellyBeans = doJellyBeans
        self.doTricks = doTricks
        self.texture = texture
        self.toon = None
        self.trampHeight = 3.6
        self.trampK = 400.0
        self.normalTrampB = 2.5
        self.leavingTrampB = 8.0
        self.trampB = self.normalTrampB
        self.g = -32.0
        self.jumpBoost = 330.0
        self.beginningBoost = 500.0
        self.beginningBoostThreshold = self.trampHeight + 1.5
        self.earlyJumpThreshold = 75.0
        self.boingThreshold = 300.0
        self.turnFactor = 120.0
        self.stepDT = 0.001
        self.targetCameraPos = Point3(0.0, 40.0, 10.0)
        self.cameraSpeed = 2.0
        self.hopOffPos = Point3(16.0, 0.0, 0.0)
        self.indicatorFactor = 0.0095
        self.dropShadowCutoff = 15.0
        self.minHeightForText = 15.0
        self.heightTextOffset = -0.065
        self.beanOffset = 0.5
        self.guiBeanOffset = -0.02
        self.jumpTextShown = False
        self.toonJumped = False
        self.turnLeft = False
        self.turnRight = False
        self.leavingTrampoline = False
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.lastPeak = 0.0
        self.beginRoundInterval = None
        self.hopOnAnim = None
        self.hopOffAnim = None
        self.flashTextInterval = None
        self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans
        self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus
        self.jellyBeanStartHeight = 20.0
        self.jellyBeanStopHeight = 90.0
        self.jellyBeanColors = [VBase4(1.0, 0.5, 0.5, 1.0),
         VBase4(0.5, 1.0, 0.5, 1.0),
         VBase4(0.5, 1.0, 1.0, 1.0),
         VBase4(1.0, 1.0, 0.4, 1.0),
         VBase4(0.4, 0.4, 1.0, 1.0),
         VBase4(1.0, 0.5, 1.0, 1.0)]
        delta = (self.jellyBeanStopHeight - self.jellyBeanStartHeight) / (self.numJellyBeans - 1)
        self.jellyBeanPositions = [ self.jellyBeanStartHeight + n * delta for n in xrange(self.numJellyBeans) ]
        self.doSimulateStep = False
        return

    def load(self):
        DistributedPartyTrampolineActivity.notify.debug('load')
        DistributedPartyActivity.load(self)
        self.loadModels()
        self.loadCollision()
        self.loadGUI()
        self.loadSounds()
        self.loadIntervals()
        self.activityFSM = TrampolineActivityFSM(self)
        self.activityFSM.request('Idle')
        self.animFSM = TrampolineAnimFSM(self)
        self.setBestHeightInfo('', 0)

    def loadModels(self):
        self.tramp = self.root.attachNewNode(self.uniqueName('tramp'))
        self.trampActor = Actor('phase_13/models/parties/trampoline_model', {'emptyAnim': 'phase_13/models/parties/trampoline_anim'})
        self.trampActor.reparentTo(self.tramp)
        if self.texture:
            reskinNode = self.tramp.find('**/trampoline/__Actor_modelRoot/-GeomNode')
            reskinNode.setTexture(loader.loadTexture(self.texture), 100)
        self.surface = NodePath(self.uniqueName('trampSurface'))
        self.surface.reparentTo(self.tramp)
        self.surface.setZ(self.trampHeight)
        self.trampActor.controlJoint(self.surface, 'modelRoot', 'trampoline_joint1')
        self.sign.setPos(PartyGlobals.TrampolineSignOffset)
        self.beans = [ loader.loadModelCopy('phase_4/models/props/jellybean4') for i in xrange(self.numJellyBeans) ]
        for bean in self.beans:
            bean.find('**/jellybean').setP(-35.0)
            bean.setScale(3.0)
            bean.setTransparency(True)
            bean.reparentTo(self.tramp)
            bean.stash()

        self.beans[-1].setScale(8.0)

    def loadCollision(self):
        collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4)
        collTube.setTangible(True)
        self.trampolineCollision = CollisionNode(self.uniqueName('TrampolineCollision'))
        self.trampolineCollision.addSolid(collTube)
        self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask | OTPGlobals.WallBitmask)
        self.trampolineCollisionNP = self.tramp.attachNewNode(self.trampolineCollision)
        collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0)
        collSphere.setTangible(False)
        self.trampolineTrigger = CollisionNode(self.uniqueName('TrampolineTrigger'))
        self.trampolineTrigger.addSolid(collSphere)
        self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask)
        self.trampolineTriggerNP = self.tramp.attachNewNode(self.trampolineTrigger)
        self.accept('enter%s' % self.uniqueName('TrampolineTrigger'), self.onTrampolineTrigger)

    def loadGUI(self):
        self.gui = loader.loadModel('phase_13/models/parties/trampolineGUI')
        self.gui.reparentTo(base.a2dTopLeft)
        self.gui.setPos(0.115, 0, -1)
        self.gui.hide()
        self.toonIndicator = self.gui.find('**/trampolineGUI_MovingBar')
        jumpLineLocator = self.gui.find('**/jumpLine_locator')
        guiBean = self.gui.find('**/trampolineGUI_GreenJellyBean')
        self.gui.find('**/trampolineGUI_GreenJellyBean').stash()
        self.guiBeans = [ guiBean.instanceUnderNode(jumpLineLocator, self.uniqueName('guiBean%d' % i)) for i in xrange(self.numJellyBeans) ]
        self.guiBeans[-1].setScale(1.5)
        heightTextNode = TextNode(self.uniqueName('TrampolineActivity.heightTextNode'))
        heightTextNode.setFont(ToontownGlobals.getSignFont())
        heightTextNode.setAlign(TextNode.ALeft)
        heightTextNode.setText('0.0')
        heightTextNode.setShadow(0.05, 0.05)
        heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0)
        heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0)
        self.heightText = jumpLineLocator.attachNewNode(heightTextNode)
        self.heightText.setX(0.15)
        self.heightText.setScale(0.1)
        self.heightText.setAlphaScale(0.0)
        self.quitEarlyButtonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui')
        quitEarlyUp = self.quitEarlyButtonModels.find('**//InventoryButtonUp')
        quitEarlyDown = self.quitEarlyButtonModels.find('**/InventoryButtonDown')
        quitEarlyRollover = self.quitEarlyButtonModels.find('**/InventoryButtonRollover')
        self.quitEarlyButton = DirectButton(parent=base.a2dTopRight, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-0.183, 0, -0.4), scale=0.09, command=self.leaveTrampoline)
        self.quitEarlyButton.stash()
        self.flashText = OnscreenText(text='', pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True)
        self.timer = PartyUtils.getNewToontownTimer()
        self.timer.posInTopRightCorner()
        return

    def loadSounds(self):
        self.jellyBeanSound = base.loadSfx('phase_4/audio/sfx/sparkly.ogg')
        self.boingSound = base.loadSfx('phase_4/audio/sfx/target_trampoline_2.ogg')
        self.whistleSound = base.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg')

    def loadIntervals(self):

        def prepareHeightText():
            self.heightText.node().setText(TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ()))
            self.heightText.setZ(self.indicatorFactor * self.toon.getZ() + self.heightTextOffset)

        self.heightTextInterval = Sequence(Func(prepareHeightText), LerpFunc(self.heightText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0))

    def unload(self):
        DistributedPartyTrampolineActivity.notify.debug('unload')
        if self.hopOnAnim and self.hopOnAnim.isPlaying():
            self.hopOnAnim.finish()
        if self.hopOffAnim and self.hopOffAnim.isPlaying():
            self.hopOffAnim.finish()
        if self.beginRoundInterval and self.beginRoundInterval.isPlaying():
            self.beginRoundInterval.finish()
        if self.flashTextInterval and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        if self.heightTextInterval and self.heightTextInterval.isPlaying():
            self.heightTextInterval.finish()
        self.timer.stop()
        DistributedPartyActivity.unload(self)
        taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask'))
        taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask'))
        self.ignoreAll()
        del self.heightTextInterval
        del self.beginRoundInterval
        del self.hopOnAnim
        del self.hopOffAnim
        del self.flashTextInterval
        if hasattr(self, 'beanAnims'):
            self.cleanupJellyBeans()
        self.quitEarlyButton.destroy()
        del self.quitEarlyButton
        del self.gui
        del self.activityFSM
        del self.animFSM
        return

    def setBestHeightInfo(self, toonName, height):
        self.bestHeightInfo = (toonName, height)
        DistributedPartyTrampolineActivity.notify.debug('%s has the best height of %d' % (toonName, height))
        if height > 0:
            self.setSignNote(TTLocalizer.PartyTrampolineBestHeight % self.bestHeightInfo)
        else:
            self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet)

    def leaveTrampoline(self):
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp)
            self.leavingTrampoline = True
            self.timer.reset()
            self.trampB = self.leavingTrampB
            self.ignore('control')
            self.quitEarlyButton.stash()
            self.gui.hide()
        return

    def requestAnim(self, request):
        self.animFSM.request(request)

    def b_requestAnim(self, request):
        self.requestAnim(request)
        self.sendUpdate('requestAnim', [request])

    def requestAnimEcho(self, request):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.requestAnim(request)
        return

    def removeBeans(self, beansToRemove):
        for i in beansToRemove:
            height, bean, guiBean, beanAnim = self.beanDetails[i]
            guiBean.stash()
            if i in self.beansToCollect:
                self.beansToCollect.remove(i)
            else:
                self.notify.warning('removeBeans avoided a crash, %d not in self.beansToCollect' % i)
            self.poofBean(bean, beanAnim)

    def b_removeBeans(self, beansToRemove):
        self.removeBeans(beansToRemove)
        self.sendUpdate('removeBeans', [beansToRemove])

    def removeBeansEcho(self, beansToRemove):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.removeBeans(beansToRemove)
        return

    def joinRequestDenied(self, reason):
        DistributedPartyActivity.joinRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny)
        base.cr.playGame.getPlace().fsm.request('walk')

    def exitRequestDenied(self, reason):
        DistributedPartyActivity.exitRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny)

    def setState(self, newState, timestamp):
        DistributedPartyTrampolineActivity.notify.debug('setState( newState=%s, ... )' % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        self.activityFSM.request(newState)

    def startIdle(self):
        DistributedPartyTrampolineActivity.notify.debug('startIdle')

    def finishIdle(self):
        DistributedPartyTrampolineActivity.notify.debug('finishIdle')

    def startRules(self):
        DistributedPartyTrampolineActivity.notify.debug('startRules')
        if self.doJellyBeans:
            self.setupJellyBeans()
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self.acquireToon()
        return

    def startActive(self):
        DistributedPartyTrampolineActivity.notify.debug('startActive')
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            base.setCellsActive(base.bottomCells, True)
            self.accept('arrow_left', self.onLeft)
            self.accept('arrow_left-up', self.onLeftUp)
            self.accept('arrow_right', self.onRight)
            self.accept('arrow_right-up', self.onRightUp)
            self.beginRoundInterval = Sequence(Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady), Wait(1.2), Func(self.flashMessage, TTLocalizer.PartyTrampolineGo), Func(self.beginRound))
            self.beginRoundInterval.start()
        return

    def finishActive(self):
        DistributedPartyTrampolineActivity.notify.debug('finishActive')
        if self.doJellyBeans:
            self.cleanupJellyBeans()

    def setupJellyBeans(self):
        self.beanAnims = []
        self.beansToCollect = []
        self.beanDetails = []
        self.numBeansCollected = 0
        for i in xrange(self.numJellyBeans):
            bean = self.beans[i]
            guiBean = self.guiBeans[i]
            height = self.jellyBeanPositions[i]
            color = random.choice(self.jellyBeanColors)
            bean.find('**/jellybean').setColor(color)
            if self.toon.doId == base.localAvatar.doId:
                bean.setAlphaScale(1.0)
            else:
                bean.setAlphaScale(0.5)
            guiBean.setColor(color)
            bean.setZ(height + self.toon.getHeight() + self.beanOffset)
            guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset)
            bean.setH(0.0)
            bean.unstash()
            guiBean.unstash()
            beanAnim = bean.hprInterval(1.5, VBase3((i % 2 * 2 - 1) * 360.0, 0.0, 0.0))
            beanAnim.loop()
            self.beanAnims.append(beanAnim)
            self.beanDetails.append((height,
             bean,
             guiBean,
             beanAnim))

        self.beansToCollect = range(self.numJellyBeans)

    def cleanupJellyBeans(self):
        for bean in self.beans:
            bean.stash()

        for guiBean in self.guiBeans:
            guiBean.stash()

        if hasattr(self, 'beanAnims'):
            for beanAnim in self.beanAnims:
                beanAnim.finish()

            del self.beanAnims
            del self.beansToCollect

    def beginRound(self):
        base.playSfx(self.whistleSound)
        self.timer.setTime(PartyGlobals.TrampolineDuration)
        self.timer.countdown(PartyGlobals.TrampolineDuration)
        self.timer.show()
        self.gui.show()
        self.quitEarlyButton.unstash()
        self.notify.debug('Accepting contorl')
        self.accept('control', self.onJump)
        self.notify.debug('setting simulate step to true')
        self.doSimulateStep = True

    def acquireToon(self):
        self.toon.disableSmartCameraViews()
        self.toon.stopUpdateSmartCamera()
        camera.wrtReparentTo(render)
        self.toon.dropShadow.reparentTo(hidden)
        self.toon.startPosHprBroadcast(period=0.2)
        self.toonAcceleration = 0.0
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.trampB = self.normalTrampB
        self.leavingTrampoline = False
        self.hopOnAnim = Sequence(Func(self.toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, Point3(0.0, 0.0, self.trampHeight), 5.0, self.tramp), Func(self.postHopOn))
        self.hopOnAnim.start()

    def postHopOn(self):
        self.toon.setH(self.toon.getH() + 90.0)
        self.toon.dropShadow.reparentTo(self.surface)
        self.timeLeftToSimulate = 0.0
        self.doSimulateStep = False
        taskMgr.add(self.updateTask, self.uniqueName('TrampolineActivity.updateTask'))
        base.setCellsActive(base.leftCells, False)
        base.setCellsActive(base.bottomCells, False)
        DistributedPartyActivity.startRules(self)

    def releaseToon(self):
        self._hideFlashMessage()
        self.ignore('arrow_left')
        self.ignore('arrow_left-up')
        self.ignore('arrow_right')
        self.ignore('arrow_right-up')
        taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask'))
        self.hopOffAnim = Sequence(self.toon.hprInterval(0.5, VBase3(-90.0, 0.0, 0.0), other=self.tramp), Func(self.toon.b_setAnimState, 'jump', 1.0), Func(self.toon.dropShadow.reparentTo, hidden), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0, self.tramp), Func(self.postHopOff))
        self.hopOffAnim.start()

    def postHopOff(self):
        base.setCellsActive(base.leftCells, True)
        self.timer.stop()
        self.timer.hide()
        self.toon.dropShadow.reparentTo(self.toon.getShadowJoint())
        self.toon.dropShadow.setAlphaScale(1.0)
        self.toon.dropShadow.setScale(1.0)
        self.b_requestAnim('Off')
        camera.reparentTo(base.localAvatar)
        base.localAvatar.startUpdateSmartCamera()
        base.localAvatar.enableSmartCameraViews()
        base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex)
        place = base.cr.playGame.getPlace()
        if self.doJellyBeans:
            self.sendUpdate('awardBeans', [self.numBeansCollected, int(self.topHeight)])
            if int(self.topHeight) > self.bestHeightInfo[1]:
                self.sendUpdate('reportHeightInformation', [int(self.topHeight)])
        self.d_toonExitDemand()

    def onTrampolineTrigger(self, collEntry):
        if self.activityFSM.state == 'Idle' and self.toon == None and base.cr.playGame.getPlace().fsm.getCurrentState().getName() == 'walk':
            base.cr.playGame.getPlace().fsm.request('activity')
            self.d_toonJoinRequest()
        else:
            self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied, duration=2.0)
        return

    def onJump(self):
        self.notify.debug('got onJump')
        if self.toon != None and self.toon.getZ() < self.trampHeight:
            self.toonJumped = True
            self.b_requestAnim('Jump')
        else:
            self.notify.debug('z is less than tramp height')
        return

    def onLeft(self):
        self.turnLeft = True

    def onLeftUp(self):
        self.turnLeft = False

    def onRight(self):
        self.turnRight = True

    def onRightUp(self):
        self.turnRight = False

    def handleToonJoined(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonJoined')
        self.toon = self.getAvatar(toonId)
        if self.toon != None and not self.toon.isEmpty():
            self.oldJumpSquatPlayRate = self.toon.getPlayRate('jump-squat')
            self.oldJumpLandPlayRate = self.toon.getPlayRate('jump-land')
            self.toon.setPlayRate(2.5, 'jump-squat')
            self.toon.setPlayRate(2.0, 'jump-land')
            self.turnLeft = False
            self.turnRight = False
            self.activityFSM.request('Rules')
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.add(self.remoteUpdateTask, self.uniqueName('TrampolineActivity.remoteUpdateTask'))
        else:
            self.notify.warning('handleToonJoined could not get toon %d' % toonId)
        return

    def handleToonExited(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonExited')
        if self.toon != None:
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask'))
            self.surface.setZ(self.trampHeight)
            self.toon.setPlayRate(self.oldJumpSquatPlayRate, 'jump-squat')
            self.toon.setPlayRate(self.oldJumpLandPlayRate, 'jump-land')
            self.toon = None
        return

    def handleToonDisabled(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonDisabled')
        DistributedPartyTrampolineActivity.notify.debug('avatar ' + str(toonId) + ' disabled')
        if base.localAvatar.doId == toonId:
            self.releaseToon()

    def handleRulesDone(self):
        self.sendUpdate('toonReady')
        self.finishRules()

    def getTitle(self):
        if self.doJellyBeans:
            return TTLocalizer.PartyTrampolineJellyBeanTitle
        elif self.doTricks:
            return TTLocalizer.PartyTrampolineTricksTitle
        else:
            return DistributedPartyActivity.getTitle(self)

    def getInstructions(self):
        return TTLocalizer.PartyTrampolineActivityInstructions

    def updateTask(self, task):
        z = self.toon.getZ()
        dt = globalClock.getDt()
        if self.doSimulateStep:
            self.timeLeftToSimulate += dt
            while self.timeLeftToSimulate >= self.stepDT:
                z, a = self.simulateStep(z)
                self.timeLeftToSimulate -= self.stepDT

        self.toon.setZ(z)
        if z <= self.trampHeight:
            self.surface.setZ(z)
        else:
            self.surface.setZ(self.trampHeight)
        self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor)
        if self.turnLeft:
            self.toon.setH(self.toon.getH() + self.turnFactor * dt)
        if self.turnRight:
            self.toon.setH(self.toon.getH() - self.turnFactor * dt)
        currentPos = base.camera.getPos(self.toon)
        vec = self.targetCameraPos - currentPos
        newPos = currentPos + vec * (dt * self.cameraSpeed)
        base.camera.setPos(self.toon, newPos)
        base.camera.lookAt(self.toon)
        #if z > self.trampHeight:
        #    heightFactor = 1.0 - min(1.0, (z - self.trampHeight) / self.dropShadowCutoff)
        #    self.toon.dropShadow.setAlphaScale(heightFactor)
        #    self.toon.dropShadow.setScale(max(0.1, heightFactor))
        #else:
        #    self.toon.dropShadow.setAlphaScale(1.0)
        #    self.toon.dropShadow.setScale(1.0)
        if self.leavingTrampoline and z < self.trampHeight and abs(a) < 0.1:
            self.releaseToon()
        return Task.cont

    def simulateStep(self, z):
        if z >= self.trampHeight:
            a = self.g
            self.toonJumped = False
        else:
            a = self.g + self.trampK * (self.trampHeight - z) - self.trampB * self.toonVelocity
            if self.toonJumped:
                if self.lastPeak > self.earlyJumpThreshold or self.toonVelocity >= -300000.0:
                    a += self.jumpBoost
                    if self.lastPeak < self.beginningBoostThreshold:
                        a += self.beginningBoost
        lastVelocity = self.toonVelocity
        self.toonVelocity += a * self.stepDT
        if lastVelocity > 0.0 and self.toonVelocity <= 0.0:
            topOfJump = True
            bottomOfJump = False
        elif lastVelocity < 0.0 and self.toonVelocity >= 0.0:
            topOfJump = False
            bottomOfJump = True
        else:
            topOfJump = False
            bottomOfJump = False
        newZ = z + self.toonVelocity * self.stepDT
        if newZ > self.topHeight:
            self.topHeight = newZ
            if self.doJellyBeans:
                self.collectJellyBeans(newZ)
        if topOfJump:
            self.lastPeak = newZ
            if newZ >= self.minHeightForText:
                self.heightTextInterval.start()
        if topOfJump:
            if newZ > self.trampHeight + 20.0:
                self.b_requestAnim('Falling')
            elif self.animFSM.state == 'Jump':
                self.b_requestAnim('Falling')
        if newZ <= self.trampHeight and z > self.trampHeight:
            if self.animFSM.state == 'Falling':
                self.b_requestAnim('Land')
            elif self.animFSM.state != 'Neutral':
                self.b_requestAnim('Neutral')
        if bottomOfJump and a > self.boingThreshold:
            base.playSfx(self.boingSound)
        return (newZ, a)

    def collectJellyBeans(self, z):
        beansToRemove = []
        for i in self.beansToCollect:
            height = self.beanDetails[i][0]
            if height <= z:
                beansToRemove.append(i)

        if len(beansToRemove) > 0:
            base.playSfx(self.jellyBeanSound)
            self.numBeansCollected += len(beansToRemove)
            self.b_removeBeans(beansToRemove)

    def remoteUpdateTask(self, task):
        if self.toon != None and not self.toon.isEmpty():
            z = self.toon.getZ()
            if z <= self.trampHeight:
                self.surface.setZ(z)
            else:
                self.surface.setZ(self.trampHeight)
        return Task.cont

    def poofBean(self, bean, beanAnim):
        if bean == None:
            self.notify.warning('poofBean, returning immediately as bean is None')
            return
        if bean.isEmpty():
            self.notify.warning('poofBean, returning immediately as bean is empty')
            return
        currentAlpha = bean.getColorScale()[3]
        currentScale = bean.getScale()
        poofAnim = Sequence(Parallel(LerpFunc(bean.setAlphaScale, fromData=currentAlpha, toData=0.0, duration=0.25), LerpFunc(bean.setScale, fromData=currentScale, toData=currentScale * 5.0, duration=0.25)), Func(bean.stash), Func(beanAnim.finish), Func(bean.setAlphaScale, currentAlpha), Func(bean.setScale, currentScale))
        poofAnim.start()
        return

    def _showFlashMessage(self, message):
        if self.isDisabled():
            return
        if self.flashTextInterval is not None and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        self.flashText.setText(message)
        self.flashText.setAlphaScale(1.0)
        self.flashText.unstash()
        return

    def _hideFlashMessage(self, duration = 0.0):
        if self.isDisabled():
            pass
        self.flashTextInterval = Sequence(Wait(duration), LerpFunc(self.flashText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), Func(self.flashText.stash))
        self.flashTextInterval.start()

    def flashMessage(self, message, duration = 0.5):
        self._showFlashMessage(message)
        self._hideFlashMessage(duration)
예제 #44
0
class CalendarGuiDay(DirectFrame):
    notify = directNotify.newCategory('CalendarGuiDay')
    ScrollListTextSize = 0.03

    def __init__(self,
                 parent,
                 myDate,
                 startDate,
                 dayClickCallback=None,
                 onlyFutureDaysClickable=False):
        self.origParent = parent
        self.startDate = startDate
        self.myDate = myDate
        self.dayClickCallback = dayClickCallback
        self.onlyFutureDaysClickable = onlyFutureDaysClickable
        DirectFrame.__init__(self, parent=parent)
        self.timedEvents = []
        self.partiesInvitedToToday = []
        self.hostedPartiesToday = []
        self.yearlyHolidaysToday = []
        self.showMarkers = base.config.GetBool('show-calendar-markers', 0)
        self.filter = ToontownGlobals.CalendarFilterShowAll
        self.load()
        self.createGuiObjects()
        self.update()

    def createDummyLocators(self):
        self.dayButtonLocator = self.attachNewNode('dayButtonLocator')
        self.dayButtonLocator.setX(0.1)
        self.dayButtonLocator.setZ(-0.05)
        self.numberLocator = self.attachNewNode('numberLocator')
        self.numberLocator.setX(0.09)
        self.scrollLocator = self.attachNewNode('scrollLocator')
        self.selectedLocator = self.attachNewNode('selectedLocator')
        self.selectedLocator.setX(0.11)
        self.selectedLocator.setZ(-0.06)

    def load(self):
        dayAsset = loader.loadModel(
            'phase_4/models/parties/tt_m_gui_sbk_calendar_box')
        dayAsset.reparentTo(self)
        self.dayButtonLocator = self.find('**/loc_origin')
        self.numberLocator = self.find('**/loc_number')
        self.scrollLocator = self.find('**/loc_topLeftList')
        self.selectedLocator = self.find('**/loc_origin')
        self.todayBox = self.find('**/boxToday')
        self.todayBox.hide()
        self.selectedFrame = self.find('**/boxHover')
        self.selectedFrame.hide()
        self.defaultBox = self.find('**/boxBlank')
        self.scrollBottomRightLocator = self.find('**/loc_bottomRightList')
        self.scrollDownLocator = self.find('**/loc_scrollDown')
        self.attachMarker(self.scrollDownLocator)
        self.scrollUpLocator = self.find('**/loc_scrollUp')
        self.attachMarker(self.scrollUpLocator)

    def attachMarker(self, parent, scale=0.005, color=(1, 0, 0)):
        if self.showMarkers:
            marker = loader.loadModel('phase_3/models/misc/sphere')
            marker.reparentTo(parent)
            marker.setScale(scale)
            marker.setColor(*color)

    def createGuiObjects(self):
        self.dayButton = DirectButton(parent=self.dayButtonLocator,
                                      image=self.selectedFrame,
                                      relief=None,
                                      command=self.__clickedOnDay,
                                      pressEffect=1,
                                      rolloverSound=None,
                                      clickSound=None)
        self.numberWidget = DirectLabel(
            parent=self.numberLocator,
            relief=None,
            text=str(self.myDate.day),
            text_scale=0.04,
            text_align=TextNode.ACenter,
            text_font=ToontownGlobals.getInterfaceFont(),
            text_fg=Vec4(110 / 255.0, 126 / 255.0, 255 / 255.0, 1))
        self.attachMarker(self.numberLocator)
        self.listXorigin = 0
        self.listFrameSizeX = self.scrollBottomRightLocator.getX(
        ) - self.scrollLocator.getX()
        self.scrollHeight = self.scrollLocator.getZ(
        ) - self.scrollBottomRightLocator.getZ()
        self.listZorigin = self.scrollBottomRightLocator.getZ()
        self.listFrameSizeZ = self.scrollLocator.getZ(
        ) - self.scrollBottomRightLocator.getZ()
        self.arrowButtonXScale = 1
        self.arrowButtonZScale = 1
        self.itemFrameXorigin = 0
        self.itemFrameZorigin = 0
        self.buttonXstart = self.itemFrameXorigin + 0.21
        self.gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui')
        buttonOffSet = -0.01
        incButtonPos = (0.0, 0, 0)
        decButtonPos = (0.0, 0, 0)
        itemFrameMinZ = self.listZorigin
        itemFrameMaxZ = self.listZorigin + self.listFrameSizeZ
        arrowUp = self.find('**/downScroll_up')
        arrowDown = self.find('**/downScroll_down')
        arrowHover = self.find('**/downScroll_hover')
        self.scrollList = DirectScrolledList(
            parent=self.scrollLocator,
            relief=None,
            pos=(0, 0, 0),
            incButton_image=(arrowUp, arrowDown, arrowHover, arrowUp),
            incButton_relief=None,
            incButton_scale=(self.arrowButtonXScale, 1,
                             self.arrowButtonZScale),
            incButton_pos=incButtonPos,
            incButton_image3_color=Vec4(1, 1, 1, 0.2),
            decButton_image=(arrowUp, arrowDown, arrowHover, arrowUp),
            decButton_relief=None,
            decButton_scale=(self.arrowButtonXScale, 1,
                             -self.arrowButtonZScale),
            decButton_pos=decButtonPos,
            decButton_image3_color=Vec4(1, 1, 1, 0.2),
            itemFrame_pos=(self.itemFrameXorigin, 0, -0.03),
            numItemsVisible=4,
            incButtonCallback=self.scrollButtonPressed,
            decButtonCallback=self.scrollButtonPressed)
        itemFrameParent = self.scrollList.itemFrame.getParent()
        self.scrollList.incButton.reparentTo(self.scrollDownLocator)
        self.scrollList.decButton.reparentTo(self.scrollUpLocator)
        arrowUp.removeNode()
        arrowDown.removeNode()
        arrowHover.removeNode()
        clipper = PlaneNode('clipper')
        clipper.setPlane(Plane(Vec3(-1, 0, 0), Point3(0.23, 0, 0)))
        clipNP = self.scrollList.component('itemFrame').attachNewNode(clipper)
        self.scrollList.component('itemFrame').setClipPlane(clipNP)
        return

    def scrollButtonPressed(self):
        self.__clickedOnDay()

    def adjustForMonth(self):
        curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
        if self.onlyFutureDaysClickable:
            if self.myDate.year < curServerDate.year or self.myDate.year == curServerDate.year and self.myDate.month < curServerDate.month or self.myDate.year == curServerDate.year and self.myDate.month == curServerDate.month and self.myDate.day < curServerDate.day:
                self.numberWidget.setColorScale(0.5, 0.5, 0.5, 0.5)
                self.numberWidget['state'] = DirectGuiGlobals.DISABLED
            else:
                self.numberWidget.setColorScale(1, 1, 1, 1)
        if self.myDate.month != self.startDate.month:
            self.setColorScale(0.75, 0.75, 0.75, 1.0)
            if self.dayClickCallback is not None:
                self.numberWidget['state'] = DirectGuiGlobals.DISABLED
        else:
            self.setColorScale(1, 1, 1, 1)
        if self.myDate.date() == curServerDate.date():
            self.defaultBox.hide()
            self.todayBox.show()
        else:
            self.defaultBox.show()
            self.todayBox.hide()
        return

    def destroy(self):
        if self.dayClickCallback is not None:
            self.numberWidget.destroy()
        self.dayClickCallback = None
        self.notify.debug('desroying %s' % self.myDate)
        try:
            for item in self.scrollList['items']:
                if hasattr(item,
                           'description') and item.description and hasattr(
                               item.description, 'destroy'):
                    self.notify.debug('desroying description of item %s' %
                                      item)
                    item.unbind(DGG.ENTER)
                    item.unbind(DGG.EXIT)
                    item.description.destroy()

        except e:
            self.notify.debug('pass %s' % self.myDate)

        self.scrollList.removeAndDestroyAllItems()
        self.scrollList.destroy()
        self.dayButton.destroy()
        DirectFrame.destroy(self)
        return

    def addWeeklyHolidays(self):
        if not self.filter == ToontownGlobals.CalendarFilterShowAll and not self.filter == ToontownGlobals.CalendarFilterShowOnlyHolidays:
            return
        if base.cr.newsManager:
            holidays = base.cr.newsManager.getHolidaysForWeekday(
                self.myDate.weekday())
            holidayName = ''
            holidayDesc = ''
            for holidayId in holidays:
                if holidayId in TTLocalizer.HolidayNamesInCalendar:
                    holidayName = TTLocalizer.HolidayNamesInCalendar[
                        holidayId][0]
                    holidayDesc = TTLocalizer.HolidayNamesInCalendar[
                        holidayId][1]
                else:
                    holidayName = TTLocalizer.UnknownHoliday % holidayId
                self.addTitleAndDescToScrollList(holidayName, holidayDesc)

            self.scrollList.refresh()
        if base.config.GetBool('calendar-test-items', 0):
            if self.myDate.date() + datetime.timedelta(
                    days=-1
            ) == base.cr.toontownTimeManager.getCurServerDateTime().date():
                testItems = ('1:00 AM Party', '2:00 AM CEO', '11:15 AM Party',
                             '5:30 PM CJ', '11:00 PM Party',
                             'Really Really Long String')
                for text in testItems:
                    newItem = DirectLabel(relief=None,
                                          text=text,
                                          text_scale=self.ScrollListTextSize,
                                          text_align=TextNode.ALeft)
                    self.scrollList.addItem(newItem)

            if self.myDate.date() + datetime.timedelta(
                    days=-2
            ) == base.cr.toontownTimeManager.getCurServerDateTime().date():
                testItems = ('1:00 AM Party', '3:00 AM CFO', '11:00 AM Party')
                textSize = self.ScrollListTextSize
                for text in testItems:
                    newItem = DirectLabel(relief=None,
                                          text=text,
                                          text_scale=textSize,
                                          text_align=TextNode.ALeft)
                    self.scrollList.addItem(newItem)

    def updateArrowButtons(self):
        numItems = 0
        try:
            numItems = len(self.scrollList['items'])
        except e:
            numItems = 0

        if numItems <= self.scrollList.numItemsVisible:
            self.scrollList.incButton.hide()
            self.scrollList.decButton.hide()
        else:
            self.scrollList.incButton.show()
            self.scrollList.decButton.show()

    def collectTimedEvents(self):
        self.timedEvents = []
        if self.filter == ToontownGlobals.CalendarFilterShowAll or self.filter == ToontownGlobals.CalendarFilterShowOnlyParties:
            for party in localAvatar.partiesInvitedTo:
                if party.startTime.date() == self.myDate.date():
                    self.partiesInvitedToToday.append(party)
                    self.timedEvents.append((party.startTime.time(), party))

            for party in localAvatar.hostedParties:
                if party.startTime.date() == self.myDate.date():
                    self.hostedPartiesToday.append(party)
                    self.timedEvents.append((party.startTime.time(), party))

        if base.cr.newsManager and (
                self.filter == ToontownGlobals.CalendarFilterShowAll or
                self.filter == ToontownGlobals.CalendarFilterShowOnlyHolidays):
            yearlyHolidays = base.cr.newsManager.getYearlyHolidaysForDate(
                self.myDate)
            for holiday in yearlyHolidays:
                holidayId = holiday[1]
                holidayStart = holiday[2]
                holidayEnd = holiday[3]
                holidayType = holiday[0]
                if holidayStart[0] == self.myDate.month and holidayStart[
                        1] == self.myDate.day:
                    myTime = datetime.time(holidayStart[2], holidayStart[3])
                elif holidayEnd[0] == self.myDate.month and holidayEnd[
                        1] == self.myDate.day:
                    myTime = datetime.time(holidayEnd[2], holidayEnd[3])
                else:
                    self.notify.error('holiday is not today %s' % holiday)
                self.timedEvents.append((myTime, holiday))

            oncelyHolidays = base.cr.newsManager.getOncelyHolidaysForDate(
                self.myDate)
            for holiday in oncelyHolidays:
                holidayId = holiday[1]
                holidayStart = holiday[2]
                holidayEnd = holiday[3]
                holidayType = holiday[0]
                if holidayStart[0] == self.myDate.year and holidayStart[
                        1] == self.myDate.month and holidayStart[
                            2] == self.myDate.day:
                    myTime = datetime.time(holidayStart[3], holidayStart[4])
                elif holidayEnd[0] == self.myDate.year and holidayEnd[
                        1] == self.myDate.month and holidayEnd[
                            2] == self.myDate.day:
                    myTime = datetime.time(holidayEnd[3], holidayEnd[4])
                else:
                    self.notify.error('holiday is not today %s' % holiday)
                self.timedEvents.append((myTime, holiday))

            multipleStartHolidays = base.cr.newsManager.getMultipleStartHolidaysForDate(
                self.myDate)
            for holiday in multipleStartHolidays:
                holidayId = holiday[1]
                holidayStart = holiday[2]
                holidayEnd = holiday[3]
                holidayType = holiday[0]
                if holidayStart[0] == self.myDate.year and holidayStart[
                        1] == self.myDate.month and holidayStart[
                            2] == self.myDate.day:
                    myTime = datetime.time(holidayStart[3], holidayStart[4])
                elif holidayEnd[0] == self.myDate.year and holidayEnd[
                        1] == self.myDate.month and holidayEnd[
                            2] == self.myDate.day:
                    myTime = datetime.time(holidayEnd[3], holidayEnd[4])
                else:
                    self.notify.error('holiday is not today %s' % holiday)
                self.timedEvents.append((myTime, holiday))

            relativelyHolidays = base.cr.newsManager.getRelativelyHolidaysForDate(
                self.myDate)
            for holiday in relativelyHolidays:
                holidayId = holiday[1]
                holidayStart = holiday[2]
                holidayEnd = holiday[3]
                holidayType = holiday[0]
                if holidayStart[0] == self.myDate.month and holidayStart[
                        1] == self.myDate.day:
                    myTime = datetime.time(holidayStart[2], holidayStart[3])
                elif holidayEnd[0] == self.myDate.month and holidayEnd[
                        1] == self.myDate.day:
                    myTime = datetime.time(holidayEnd[2], holidayEnd[3])
                else:
                    self.notify.error('holiday is not today %s' % holiday)
                self.timedEvents.append((myTime, holiday))

        def timedEventCompare(te1, te2):
            if te1[0] < te2[0]:
                return -1
            elif te1[0] == te2[0]:
                return 0
            else:
                return 1

        self.timedEvents.sort(cmp=timedEventCompare)
        for timedEvent in self.timedEvents:
            if isinstance(timedEvent[1], PartyInfo):
                self.addPartyToScrollList(timedEvent[1])
            elif isinstance(
                    timedEvent[1], tuple
            ) and timedEvent[1][0] == NewsManager.YearlyHolidayType:
                self.addYearlyHolidayToScrollList(timedEvent[1])
            elif isinstance(
                    timedEvent[1], tuple
            ) and timedEvent[1][0] == NewsManager.OncelyHolidayType:
                self.addOncelyHolidayToScrollList(timedEvent[1])
            elif isinstance(timedEvent[1], tuple) and timedEvent[1][
                    0] == NewsManager.OncelyMultipleStartHolidayType:
                self.addOncelyMultipleStartHolidayToScrollList(timedEvent[1])
            elif isinstance(
                    timedEvent[1], tuple
            ) and timedEvent[1][0] == NewsManager.RelativelyHolidayType:
                self.addRelativelyHolidayToScrollList(timedEvent[1])

    def addYearlyHolidayToScrollList(self, holiday):
        holidayId = holiday[1]
        holidayStart = holiday[2]
        holidayEnd = holiday[3]
        holidayType = holiday[0]
        holidayText = ''
        startTime = datetime.time(holidayStart[2], holidayStart[3])
        endTime = datetime.time(holidayEnd[2], holidayEnd[3])
        startDate = datetime.date(self.myDate.year, holidayStart[0],
                                  holidayStart[1])
        endDate = datetime.date(self.myDate.year, holidayEnd[0], holidayEnd[1])
        if endDate < startDate:
            endDate = datetime.date(endDate.year + 1, endDate.month,
                                    endDate.day)
        if holidayId in TTLocalizer.HolidayNamesInCalendar:
            holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
            holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
        else:
            holidayName = TTLocalizer.UnknownHoliday % holidayId
            holidayDesc = TTLocalizer.UnknownHoliday % holidayId
        if holidayStart[0] == holidayEnd[0] and holidayStart[1] == holidayEnd[
                1]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(
                endTime)
        elif self.myDate.month == holidayStart[
                0] and self.myDate.day == holidayStart[1]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc = holidayName + '. ' + holidayDesc
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(
                TTLocalizer.HolidayFormat) + myStrftime(endTime)
        elif self.myDate.month == holidayEnd[
                0] and self.myDate.day == holidayEnd[1]:
            holidayText = myStrftime(endTime)
            holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
            holidayDesc = TTLocalizer.CalendarEndOf + holidayName
            holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(
                TTLocalizer.HolidayFormat) + myStrftime(startTime)
        else:
            self.notify.error('unhandled case')
        self.addTitleAndDescToScrollList(holidayText, holidayDesc)

    def addOncelyHolidayToScrollList(self, holiday):
        holidayId = holiday[1]
        holidayStart = holiday[2]
        holidayEnd = holiday[3]
        holidayType = holiday[0]
        holidayText = ''
        startTime = datetime.time(holidayStart[3], holidayStart[4])
        endTime = datetime.time(holidayEnd[3], holidayEnd[4])
        startDate = datetime.date(holidayStart[0], holidayStart[1],
                                  holidayStart[2])
        endDate = datetime.date(holidayStart[0], holidayEnd[1], holidayEnd[2])
        if endDate < startDate:
            endDate = datetime.date(endDate.year + 1, endDate.month,
                                    endDate.day)
        if holidayId in TTLocalizer.HolidayNamesInCalendar:
            holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
            holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
        else:
            holidayName = TTLocalizer.UnknownHoliday % holidayId
            holidayDesc = ''
        if holidayStart[1] == holidayEnd[1] and holidayStart[2] == holidayEnd[
                2]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc = holidayName + '. ' + holidayDesc
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(
                endTime)
        elif self.myDate.year == holidayStart[
                0] and self.myDate.month == holidayStart[
                    1] and self.myDate.day == holidayStart[2]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc = holidayName + '. ' + holidayDesc
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(
                TTLocalizer.HolidayFormat) + myStrftime(endTime)
        elif self.myDate.year == holidayEnd[
                0] and self.myDate.month == holidayEnd[
                    1] and self.myDate.day == holidayEnd[2]:
            holidayText = myStrftime(endTime)
            holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
            holidayDesc = TTLocalizer.CalendarEndOf + holidayName
            holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(
                TTLocalizer.HolidayFormat) + myStrftime(startTime)
        else:
            self.notify.error('unhandled case')
        self.addTitleAndDescToScrollList(holidayText, holidayDesc)

    def addOncelyMultipleStartHolidayToScrollList(self, holiday):
        self.addOncelyHolidayToScrollList(holiday)

    def addRelativelyHolidayToScrollList(self, holiday):
        holidayId = holiday[1]
        holidayStart = holiday[2]
        holidayEnd = holiday[3]
        holidayType = holiday[0]
        holidayText = ''
        startTime = datetime.time(holidayStart[2], holidayStart[3])
        endTime = datetime.time(holidayEnd[2], holidayEnd[3])
        startDate = datetime.date(self.myDate.year, holidayStart[0],
                                  holidayStart[1])
        endDate = datetime.date(self.myDate.year, holidayEnd[0], holidayEnd[1])
        if endDate < startDate:
            endDate.year += 1
        if holidayId in TTLocalizer.HolidayNamesInCalendar:
            holidayName = TTLocalizer.HolidayNamesInCalendar[holidayId][0]
            holidayDesc = TTLocalizer.HolidayNamesInCalendar[holidayId][1]
        else:
            holidayName = TTLocalizer.UnknownHoliday % holidayId
            holidayDesc = ''
        if holidayStart[0] == holidayEnd[0] and holidayStart[1] == holidayEnd[
                1]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + myStrftime(
                endTime)
        elif self.myDate.month == holidayStart[
                0] and self.myDate.day == holidayStart[1]:
            holidayText = myStrftime(startTime)
            holidayText += ' ' + holidayName
            holidayDesc = holidayName + '. ' + holidayDesc
            holidayDesc += ' ' + TTLocalizer.CalendarEndsAt + endDate.strftime(
                TTLocalizer.HolidayFormat) + myStrftime(endTime)
        elif self.myDate.month == holidayEnd[
                0] and self.myDate.day == holidayEnd[1]:
            holidayText = myStrftime(endTime)
            holidayText += ' ' + TTLocalizer.CalendarEndDash + holidayName
            holidayDesc = TTLocalizer.CalendarEndOf + holidayName
            holidayDesc += '. ' + TTLocalizer.CalendarStartedOn + startDate.strftime(
                TTLocalizer.HolidayFormat) + myStrftime(startTime)
        else:
            self.notify.error('unhandled case')
        self.addTitleAndDescToScrollList(holidayText, holidayDesc)

    def addTitleAndDescToScrollList(self, title, desc):
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        newItem = DirectButton(relief=None,
                               text=title,
                               text_scale=textSize,
                               text_align=TextNode.ALeft,
                               rolloverSound=None,
                               clickSound=None,
                               pressEffect=0,
                               command=self.__clickedOnScrollItem)
        scrollItemHeight = newItem.getHeight()
        descUnderItemZAdjust = scrollItemHeight * descTextSize / textSize
        descUnderItemZAdjust = max(0.0534, descUnderItemZAdjust)
        descUnderItemZAdjust = -descUnderItemZAdjust
        descZAdjust = descUnderItemZAdjust
        newItem.description = DirectLabel(parent=newItem,
                                          pos=(0.115, 0, descZAdjust),
                                          text='',
                                          text_wordwrap=15,
                                          pad=(0.02, 0.02),
                                          text_scale=descTextSize,
                                          text_align=TextNode.ACenter,
                                          textMayChange=0)
        newItem.description.checkedHeight = False
        newItem.description.setBin('gui-popup', 0)
        newItem.description.hide()
        newItem.bind(DGG.ENTER,
                     self.enteredTextItem,
                     extraArgs=[newItem, desc, descUnderItemZAdjust])
        newItem.bind(DGG.EXIT, self.exitedTextItem, extraArgs=[newItem])
        self.scrollList.addItem(newItem)
        return

    def exitedTextItem(self, newItem, mousepos):
        newItem.description.hide()

    def enteredTextItem(self, newItem, descText, descUnderItemZAdjust,
                        mousePos):
        if not newItem.description.checkedHeight:
            newItem.description.checkedHeight = True
            newItem.description['text'] = descText
            bounds = newItem.description.getBounds()
            descHeight = newItem.description.getHeight()
            scrollItemHeight = newItem.getHeight()
            descOverItemZAdjust = descHeight - scrollItemHeight / 2.0
            descZPos = self.getPos(
                aspect2d)[2] + descUnderItemZAdjust - descHeight
            if descZPos < -1.0:
                newItem.description.setZ(descOverItemZAdjust)
            descWidth = newItem.description.getWidth()
            brightFrame = loader.loadModel(
                'phase_4/models/parties/tt_m_gui_sbk_calendar_popUp_bg')
            newItem.description['geom'] = brightFrame
            newItem.description['geom_scale'] = (descWidth, 1, descHeight)
            descGeomZ = (bounds[2] - bounds[3]) / 2.0
            descGeomZ += bounds[3]
            newItem.description['geom_pos'] = (0, 0, descGeomZ)
        newItem.description.show()

    def addPartyToScrollList(self, party):
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        partyTitle = myStrftime(party.startTime)
        partyTitle = partyTitle + ' ' + TTLocalizer.EventsPageCalendarTabParty
        textSize = self.ScrollListTextSize
        descTextSize = 0.05
        newItem = DirectButton(relief=None,
                               text=partyTitle,
                               text_scale=textSize,
                               text_align=TextNode.ALeft,
                               rolloverSound=None,
                               clickSound=None,
                               pressEffect=0,
                               command=self.__clickedOnScrollItem)
        scrollItemHeight = newItem.getHeight()
        descUnderItemZAdjust = scrollItemHeight * descTextSize / textSize
        descUnderItemZAdjust = max(0.0534, descUnderItemZAdjust)
        descUnderItemZAdjust = -descUnderItemZAdjust
        descZAdjust = descUnderItemZAdjust
        self.scrollList.addItem(newItem)
        newItem.description = MiniInviteVisual(newItem, party)
        newItem.description.setBin('gui-popup', 0)
        newItem.description.hide()
        newItem.bind(
            DGG.ENTER,
            self.enteredTextItem,
            extraArgs=[newItem, newItem.description, descUnderItemZAdjust])
        newItem.bind(DGG.EXIT, self.exitedTextItem, extraArgs=[newItem])
        return

    def __clickedOnScrollItem(self):
        self.__clickedOnDay()

    def __clickedOnDay(self):
        acceptClick = True
        if self.onlyFutureDaysClickable:
            curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
            if self.myDate.date() < curServerDate.date():
                acceptClick = False
        if not acceptClick:
            return
        if self.dayClickCallback:
            self.dayClickCallback(self)
        self.notify.debug('we got clicked on %s' % self.myDate.date())
        messenger.send('clickedOnDay', [self.myDate.date()])

    def updateSelected(self, selected):
        multiplier = 1.1
        if selected:
            self.selectedFrame.show()
            self.setScale(multiplier)
            self.setPos(-0.01, 0, 0.01)
            grandParent = self.origParent.getParent()
            self.origParent.reparentTo(grandParent)
        else:
            self.selectedFrame.hide()
            self.setScale(1.0)
            self.setPos(0, 0, 0)

    def changeDate(self, startDate, myDate):
        self.startDate = startDate
        self.myDate = myDate
        self.scrollList.removeAndDestroyAllItems()
        self.update()

    def update(self):
        self.numberWidget['text'] = str(self.myDate.day)
        self.adjustForMonth()
        self.addWeeklyHolidays()
        self.collectTimedEvents()
        self.updateArrowButtons()

    def changeFilter(self, filter):
        oldFilter = self.filter
        self.filter = filter
        if self.filter != oldFilter:
            self.scrollList.removeAndDestroyAllItems()
            self.update()
예제 #45
0
class ToonPanel(DirectFrame):
    notify = directNotify.newCategory('ToonPanel')
    animal2HeadData = {'dog': (0.125, 0.04),
     'duck': (0.1, 0.025),
     'cat': (0.115, 0.04),
     'rabbit': (0.115, 0.04),
     'horse': (0.115, 0.06),
     'monkey': (0.115, 0.06),
     'pig': (0.115, 0.07),
     'mouse': (0.09, 0.02),
     'bear': (0.125, 0.05)}
    State2Text = {'status': ('Seeing if %s is available...', '%s is busy right now; try again later.'),
     'teleport': ('Trying to go to %s...', 'Could not go to %s.'),
     'friend': ('Asking %s to be your friend...', '%s said no, thank you.', 'You are now friends with %s!'),
     'remove': ('Are you sure you want to remove %s from your friends list?', '%s left your friends list.')}

    def __init__(self):
        DirectFrame.__init__(self, scale=1.2)
        self['image'] = DGG.getDefaultDialogGeom()
        self['image_hpr'] = (0, 0, -90)
        self['image_scale'] = (0.62, 0.9, 0.325)
        self['image_color'] = (1, 1, 0.75, 1)
        self['image_pos'] = (0, 0, -0.065)
        self['relief'] = None
        self.reparentTo(base.a2dTopRight)
        self.setPos(-0.235, 0.0, -0.325)
        self.hide()
        self.head = None
        self.laffMeter = None
        self.exitButton = None
        self.friendButton = None
        self.teleportButton = None
        self.nameText = None
        self.actionFrame = None
        self.actionFrameText = None
        self.actionFrameButton = None
        self.actionFrameButton2 = None
        self.avatarInfo = None
        self.action = None
        self.fsm = ClassicFSM.ClassicFSM('ToonPanel', [State.State('off', self.enterOff, self.exitOff), State.State('waitOnAvatarInfoResponse', self.enterWaitOnAvatarInfoResponse, self.exitWaitOnAvatarInfoResponse, ['panel']), State.State('panel', self.enterPanel, self.exitPanel, ['off'])], 'off', 'off')
        self.fsm.enterInitialState()
        self.actionFSM = ClassicFSM.ClassicFSM('ToonPanelActionFSM', [State.State('off', self.enterOff, self.exitOff),
         State.State('waitOnAvatarStatusResponse', self.enterWaitOnAvatarStatusResponse, self.exitWaitOnAvatarStatusResponse, ['waitOnAvatarTeleportResponse',
          'waitOnAvatarFriendListResponse',
          'avatarBusy',
          'off']),
         State.State('avatarBusy', self.enterAvatarBusy, self.exitAvatarBusy, ['off']),
         State.State('waitOnAvatarTeleportResponse', self.enterWaitOnAvatarTeleportResponse, self.exitWaitOnAvatarTeleportResponse, ['unableToTP']),
         State.State('unableToTP', self.enterUnableToTP, self.exitUnableToTP, ['off']),
         State.State('waitOnAvatarFriendListResponse', self.enterWaitOnAvatarFriendListResponse, self.exitWaitOnAvatarFriendListResponse, ['fRequestA', 'fRequestR']),
         State.State('fRequestA', self.enterFriendRequestAccepted, self.exitFriendRequestAccepted, ['off']),
         State.State('fRequestR', self.enterFriendRequestRejected, self.exitFriendRequestRejected, ['off']),
         State.State('removeFriendConfirm', self.enterRemoveFriendConfirm, self.exitRemoveFriendConfirm, ['off', 'removedFriend']),
         State.State('removedFriend', self.enterRemovedFriend, self.exitRemovedFriend, ['off'])], 'off', 'off')
        self.actionFSM.enterInitialState()
        return

    def maybeUpdateFriendButton(self):
        if self.friendButton:
            if self.avatarInfo:
                if self.avatarInfo[0] not in base.localAvatar.friends:
                    self.friendButton['text'] = 'Add Friend'
                    self.friendButton['extraArgs'] = ['waitOnAvatarFriendListResponse']
                else:
                    self.friendButton['text'] = 'Remove Friend'
                    self.friendButton['extraArgs'] = ['removeFriendConfirm']

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterUnableToTP(self):
        pass

    def exitUnableToTP(self):
        pass

    def enterWaitOnAvatarTeleportResponse(self):
        self.setActionText(self.State2Text['teleport'][0] % self.getAvatarName())
        self.makeButtons('Cancel')
        self.acceptOnce('gotAvatarTeleportResponse', self.handleTeleportResponse)
        base.cr.friendsManager.d_iWantToTeleportToAvatar(self.avatarInfo[0])

    def handleTeleportResponse(self, avatarId, shardId, zoneId):
        if self.avatarInfo[0] == avatarId:
            requestStatus = {}
            whereName = ZoneUtil.getWhereName(zoneId)
            loaderName = ZoneUtil.getLoaderName(zoneId)
            requestStatus['zoneId'] = zoneId
            if base.localAvatar.parentId == shardId:
                requestStatus['shardId'] = None
            else:
                requestStatus['shardId'] = shardId
            requestStatus['hoodId'] = ZoneUtil.getHoodId(zoneId, 1)
            requestStatus['where'] = whereName
            requestStatus['loader'] = loaderName
            requestStatus['how'] = 'teleportIn'
            requestStatus['avId'] = avatarId
            base.cr.playGame.getPlace().fsm.request('teleportOut', [requestStatus])
            self.cleanup()
        return

    def exitWaitOnAvatarTeleportResponse(self):
        self.ignore('gotAvatarTeleportResponse')
        self.clearActionText()
        self.clearActionButtons()

    def setActionText(self, text):
        self.actionFrameText.setText(text)

    def clearActionText(self):
        self.actionFrameText.setText('')

    def makeButtons(self, button1, button2 = None):
        button2GeomFunc = {'Cancel': CIGlobals.getCancelBtnGeom,
         'No': CIGlobals.getCancelBtnGeom,
         'Okay': CIGlobals.getOkayBtnGeom,
         'Yes': CIGlobals.getOkayBtnGeom}
        if button1 and not button2:
            button1Pos = (0, 0, -0.1)
        elif button1 and button2:
            button1Pos = (-0.1, 0, -0.1)
        button2Pos = (0.1, 0, -0.1)
        if button1:
            self.actionFrameButton = DirectButton(text=button1, geom=button2GeomFunc[button1](), parent=self.actionFrame, pos=button1Pos, text_scale=0.045, text_pos=(0, -0.08), command=self.actionButtonPressed, extraArgs=[1], relief=None, geom_scale=0.75)
        if button2:
            self.actionFrameButton2 = DirectButton(text=button2, geom=button2GeomFunc[button2](), parent=self.actionFrame, pos=button2Pos, text_scale=0.045, text_pos=(0, -0.08), command=self.actionButtonPressed, extraArgs=[2], relief=None, geom_scale=0.75)
        return

    def actionButtonPressed(self, buttonNum):
        currentState = self.actionFSM.getCurrentState().getName()
        if buttonNum == 1:
            if currentState in ('waitOnAvatarStatusResponse', 'waitOnAvatarTeleportResponse', 'waitOnAvatarFriendListResponse', 'avatarBusy', 'unableToTP', 'fRequestA', 'fRequestR', 'removeFriendConfirm', 'removedFriend'):
                if currentState == 'waitOnAvatarFriendListResponse':
                    base.cr.friendsManager.d_iCancelledFriendRequest(self.avatarInfo[0])
                elif currentState == 'removeFriendConfirm':
                    self.actionFSM.request('removedFriend')
                    return
                self.actionFSM.request('off')
                self.removeActionPanel()
                self.action = None
        elif buttonNum == 2:
            self.actionFSM.request('off')
            self.removeActionPanel()
            self.action = None
        return

    def clearActionButtons(self):
        if self.actionFrameButton2:
            self.actionFrameButton2.destroy()
            self.actionFrameButton2 = None
        if self.actionFrameButton:
            self.actionFrameButton.destroy()
            self.actionFrameButton = None
        return

    def enterAvatarBusy(self):
        self.setActionText(self.State2Text['status'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitAvatarBusy(self):
        self.clearActionText()
        self.clearActionButtons()

    def getAvatarName(self):
        if self.avatarInfo:
            return self.avatarInfo[1]

    def enterWaitOnAvatarStatusResponse(self):
        self.acceptOnce('gotAvatarStatus', self.handleAvatarStatusResponse)
        base.cr.friendsManager.d_requestAvatarStatus(self.avatarInfo[0])
        self.setActionText(self.State2Text['status'][0] % self.getAvatarName())
        self.makeButtons('Cancel')

    def handleAvatarStatusResponse(self, avatarId, status):
        if avatarId == self.avatarInfo[0]:
            if status == 1:
                self.actionFSM.request('avatarBusy')
            else:
                self.actionFSM.request(self.action)
        else:
            self.acceptOnce('gotAvatarStatus', self.handleAvatarStatusResponse)

    def exitWaitOnAvatarStatusResponse(self):
        self.ignore('gotAvatarStatus')
        self.clearActionText()
        self.clearActionButtons()

    def enterWaitOnAvatarFriendListResponse(self):
        self.acceptOnce('friendRequestAccepted', self.handleFriendRequestAccepted)
        self.acceptOnce('friendRequestRejected', self.handleFriendRequestRejected)
        base.cr.friendsManager.d_askAvatarToBeFriends(self.avatarInfo[0])
        self.setActionText(self.State2Text['friend'][0] % self.getAvatarName())
        self.makeButtons('Cancel')

    def handleFriendRequestAccepted(self):
        self.actionFSM.request('fRequestA')

    def handleFriendRequestRejected(self):
        self.actionFSM.request('fRequestR')

    def exitWaitOnAvatarFriendListResponse(self):
        self.ignore('friendRequestAccepted')
        self.ignore('friendRequestRejected')
        self.clearActionText()
        self.clearActionButtons()

    def enterFriendRequestAccepted(self):
        self.setActionText(self.State2Text['friend'][2] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitFriendRequestAccepted(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterFriendRequestRejected(self):
        self.setActionText(self.State2Text['friend'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitFriendRequestRejected(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterRemoveFriendConfirm(self):
        self.setActionText(self.State2Text['remove'][0] % self.getAvatarName())
        self.makeButtons('Yes', 'No')

    def exitRemoveFriendConfirm(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterRemovedFriend(self):
        base.cr.friendsManager.d_iRemovedFriend(self.avatarInfo[0])
        self.setActionText(self.State2Text['remove'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitRemovedFriend(self):
        self.clearActionText()
        self.clearActionButtons()

    def makeActionPanel(self):
        self.actionFrame = DirectFrame(image=DGG.getDefaultDialogGeom(), image_scale=(0.7, 0.5, 0.45), image_color=(1, 1, 0.75, 1), relief=None)
        self.actionFrame.reparentTo(base.a2dTopRight)
        self.actionFrame.setPos(-0.815, 0, -0.31)
        self.actionFrameText = OnscreenText(text='', parent=self.actionFrame, scale=0.05, wordwrap=12, pos=(0, 0.1))
        return

    def removeActionPanel(self):
        self.clearActionButtons()
        if self.actionFrameText:
            self.actionFrameText.destroy()
            self.actionFrameText = None
        if self.actionFrame:
            self.actionFrame.destroy()
            self.actionFrame = None
        return

    def doAction(self, action):
        self.action = action
        self.actionFSM.requestFinalState()
        self.removeActionPanel()
        self.makeActionPanel()
        if action != 'removeFriendConfirm':
            self.actionFSM.request('waitOnAvatarStatusResponse')
        else:
            self.actionFSM.request(action)

    def enterWaitOnAvatarInfoResponse(self):
        self.label = OnscreenText(text='Retrieving Toon\ndetails...', parent=self, scale=0.04)
        self.acceptOnce('avatarInfoResponse', self.handleAvatarInfoResponse)
        base.cr.friendsManager.d_requestAvatarInfo(self.avatarInfo[0])

    def handleAvatarInfoResponse(self, name, dna, maxHealth, health):
        if self.avatarInfo:
            self.avatarInfo.append(name)
            self.avatarInfo.append(dna)
            self.avatarInfo.append(maxHealth)
            self.avatarInfo.append(health)
            self.fsm.request('panel')

    def exitWaitOnAvatarInfoResponse(self):
        self.label.destroy()
        del self.label
        self.ignore('avatarInfoResponse')

    def makePanel(self, avId):
        if self.avatarInfo:
            if self.avatarInfo[0] == avId:
                return
        self.cleanup()
        base.localAvatar.hideFriendButton()
        self.show()
        self.avatarInfo = []
        self.avatarInfo.append(avId)
        self.fsm.request('waitOnAvatarInfoResponse')

    def exitClicked(self):
        self.cleanup()
        base.localAvatar.showFriendButton()

    def cleanup(self):
        self.actionFSM.requestFinalState()
        self.fsm.requestFinalState()
        self.avatarInfo = None
        return

    def enterPanel(self):
        self.nameText = OnscreenText(text=self.avatarInfo[1], parent=self, pos=(0, 0.2), scale=0.035, wordwrap=8)
        self.nameText.setBin('gui-popup', 60)
        dna = ToonDNA.ToonDNA()
        dna.setDNAStrand(self.avatarInfo[2])
        self.head = ToonHead.ToonHead(base.cr)
        self.head.generateHead(dna.gender, dna.animal, dna.head, 1)
        self.head.setHeadColor(dna.headcolor)
        self.head.reparentTo(self)
        self.head.setDepthWrite(1)
        self.head.setDepthTest(1)
        self.head.setH(180)
        self.head.setScale(self.animal2HeadData[dna.animal][0])
        self.head.setZ(self.animal2HeadData[dna.animal][1])
        self.laffMeter = LaffOMeter()
        r, g, b, _ = dna.headcolor
        self.laffMeter.generate(r, g, b, dna.animal, self.avatarInfo[3], self.avatarInfo[4])
        self.laffMeter.reparentTo(self)
        self.laffMeter.setBin('gui-popup', 60)
        self.laffMeter.setScale(0.045)
        self.laffMeter.setPos(0, 0, -0.1)
        self.friendButton = DirectButton(geom=CIGlobals.getDefaultBtnGeom(), text='Add Friend', scale=0.58, relief=None, text_scale=0.058, geom_scale=(1.25, 0, 0.9), text_pos=(0, -0.0125), parent=self, pos=(0, 0, -0.12), command=self.doAction, extraArgs=['waitOnAvatarFriendListResponse'])
        self.friendButton.setPos(0, 0.0, -0.225)
        self.maybeUpdateFriendButton()
        self.teleportButton = DirectButton(geom=CIGlobals.getDefaultBtnGeom(), text='Teleport', scale=0.58, relief=None, text_scale=0.058, geom_scale=(1.25, 0, 0.9), text_pos=(0, -0.0125), parent=self, pos=(0, 0, -0.12), command=self.doAction, extraArgs=['waitOnAvatarTeleportResponse'])
        self.teleportButton.setPos(0, 0, -0.275)
        self.exitButton = DirectButton(geom=CIGlobals.getCancelBtnGeom(), parent=self, relief=None, scale=0.6, pos=(-0.127, 0.0, -0.3425), command=self.exitClicked)
        return

    def exitPanel(self):
        if self.actionFSM.getCurrentState().getName() == 'waitOnAvatarFriendListResponse':
            if self.avatarInfo:
                base.cr.friendsManager.d_iCancelledFriendRequest(self.avatarInfo[0])
        self.actionFSM.requestFinalState()
        self.action = None
        self.avatarInfo = None
        self.removeActionPanel()
        self.hide()
        if self.nameText:
            self.nameText.destroy()
            self.nameText = None
        if self.head:
            self.head.removeNode()
            self.head.delete()
            self.head = None
        if self.laffMeter:
            self.laffMeter.disable()
            self.laffMeter.delete()
            self.laffMeter = None
        if self.friendButton:
            self.friendButton.destroy()
            self.friendButton = None
        if self.teleportButton:
            self.teleportButton.destroy()
            self.teleportButton = None
        if self.exitButton:
            self.exitButton.destroy()
            self.exitButton = None
        return
예제 #46
0
class JellybeanRewardGui(DirectFrame):
    notify = directNotify.newCategory('JellybeanRewardGui')
    PreCountdownDelay = 1.0
    CountDownRate = 0.20000000000000001
    JarLabelTextColor = (0.94999999999999996, 0.94999999999999996, 0.0, 1.0)
    JarLabelMaxedTextColor = (1.0, 0.0, 0.0, 1.0)

    def __init__(self, doneEvent):
        self.doneEvent = doneEvent
        DirectFrame.__init__(self)
        self.reparentTo(aspect2d)
        self.setPos(0.0, 0.0, 0.16)
        self.stash()
        publicPartyGui = loader.loadModel(
            'phase_4/models/parties/publicPartyGUI')
        self.frame = DirectFrame(
            parent=self,
            geom=publicPartyGui.find('**/activities_background'),
            geom_pos=(-0.80000000000000004, 0.0, 0.20000000000000001),
            geom_scale=2.0,
            relief=None)
        self.earnedLabel = DirectLabel(
            parent=self,
            relief=None,
            text=str(0),
            text_align=TextNode.ACenter,
            text_pos=(0.0, -0.070000000000000007),
            text_scale=0.20000000000000001,
            text_fg=(0.94999999999999996, 0.94999999999999996, 0.0, 1.0),
            text_font=ToontownGlobals.getSignFont(),
            textMayChange=True,
            image=DirectGuiGlobals.getDefaultDialogGeom(),
            image_scale=(0.33000000000000002, 1.0, 0.33000000000000002),
            pos=(-0.29999999999999999, 0.0, 0.20000000000000001),
            scale=0.90000000000000002)
        purchaseModels = loader.loadModel('phase_4/models/gui/purchase_gui')
        jarImage = purchaseModels.find('**/Jar')
        self.jarLabel = DirectLabel(
            parent=self,
            relief=None,
            text=str(0),
            text_align=TextNode.ACenter,
            text_pos=(0.0, -0.070000000000000007),
            text_scale=0.20000000000000001,
            text_fg=JellybeanRewardGui.JarLabelTextColor,
            text_font=ToontownGlobals.getSignFont(),
            textMayChange=True,
            image=jarImage,
            scale=0.69999999999999996,
            pos=(0.29999999999999999, 0.0, 0.17000000000000001))
        purchaseModels.removeNode()
        del purchaseModels
        jarImage.removeNode()
        del jarImage
        self.messageLabel = DirectLabel(parent=self,
                                        relief=None,
                                        text='',
                                        text_align=TextNode.ALeft,
                                        text_wordwrap=16.0,
                                        text_scale=0.070000000000000007,
                                        pos=(-0.52000000000000002, 0.0,
                                             -0.10000000000000001),
                                        textMayChange=True)
        self.doubledJellybeanLabel = DirectLabel(
            parent=self,
            relief=None,
            text=TTLocalizer.PartyRewardDoubledJellybean,
            text_align=TextNode.ACenter,
            text_wordwrap=12.0,
            text_scale=0.089999999999999997,
            text_fg=(1.0, 0.125, 0.125, 1.0),
            pos=(0.0, 0.0, -0.46500000000000002),
            textMayChange=False)
        self.doubledJellybeanLabel.hide()
        self.closeButton = DirectButton(
            parent=self,
            relief=None,
            text=TTLocalizer.PartyJellybeanRewardOK,
            text_align=TextNode.ACenter,
            text_scale=0.065000000000000002,
            text_pos=(0.0, -0.625),
            geom=(publicPartyGui.find('**/startButton_up'),
                  publicPartyGui.find('**/startButton_down'),
                  publicPartyGui.find('**/startButton_rollover'),
                  publicPartyGui.find('**/startButton_inactive')),
            geom_pos=(-0.39000000000000001, 0.0, 0.125),
            command=self._close)
        publicPartyGui.removeNode()
        del publicPartyGui
        self.countSound = base.loadSfx(
            'phase_13/audio/sfx/tick_counter_short.mp3')
        self.overMaxSound = base.loadSfx(
            'phase_13/audio/sfx/tick_counter_overflow.mp3')

    def showReward(self, earnedAmount, jarAmount, message):
        JellybeanRewardGui.notify.debug(
            'showReward( earnedAmount=%d, jarAmount=%d, ...)' %
            (earnedAmount, jarAmount))
        self.earnedCount = earnedAmount
        self.earnedLabel['text'] = str(self.earnedCount)
        self.jarCount = jarAmount
        self.jarMax = base.localAvatar.getMaxMoney()
        self.jarLabel['text'] = str(self.jarCount)
        self.jarLabel['text_fg'] = JellybeanRewardGui.JarLabelTextColor
        self.messageLabel['text'] = message
        if base.cr.newsManager.isHolidayRunning(
                ToontownGlobals.JELLYBEAN_DAY
        ) and base.cr.newsManager.isHolidayRunning(
                ToontownGlobals.JELLYBEAN_PARTIES_HOLIDAY
        ) or base.cr.newsManager.isHolidayRunning(
                ToontownGlobals.JELLYBEAN_PARTIES_HOLIDAY_MONTH):
            self.doubledJellybeanLabel.show()
        else:
            self.doubledJellybeanLabel.hide()
        self.unstash()
        taskMgr.doMethodLater(JellybeanRewardGui.PreCountdownDelay,
                              self.transferOneJellybean,
                              'JellybeanRewardGuiTransferOneJellybean',
                              extraArgs=[])

    def transferOneJellybean(self):
        if self.earnedCount == 0:
            return None

        self.earnedCount -= 1
        self.earnedLabel['text'] = str(self.earnedCount)
        self.jarCount += 1
        if self.jarCount <= self.jarMax:
            self.jarLabel['text'] = str(self.jarCount)
        elif self.jarCount > self.jarMax:
            self.jarLabel[
                'text_fg'] = JellybeanRewardGui.JarLabelMaxedTextColor

        if self.jarCount <= self.jarMax:
            base.playSfx(self.countSound)
        else:
            base.playSfx(self.overMaxSound)
        taskMgr.doMethodLater(JellybeanRewardGui.CountDownRate,
                              self.transferOneJellybean,
                              'JellybeanRewardGuiTransferOneJellybean',
                              extraArgs=[])

    def _close(self):
        taskMgr.remove('JellybeanRewardGuiTransferOneJellybean')
        self.stash()
        messenger.send(self.doneEvent)

    def destroy(self):
        taskMgr.remove('JellybeanRewardGuiTransferOneJellybean')
        del self.countSound
        del self.overMaxSound
        self.frame.destroy()
        self.earnedLabel.destroy()
        self.jarLabel.destroy()
        self.messageLabel.destroy()
        self.closeButton.destroy()
        DirectFrame.destroy(self)
class ToonPanel(DirectFrame):
    notify = directNotify.newCategory("ToonPanel")

    animal2HeadData = {
        'dog': (0.125, 0.04),
        'duck': (0.1, 0.025),
        'cat': (0.115, 0.04),
        'rabbit': (0.115, 0.04),
        'horse': (0.115, 0.06),
        'monkey': (0.115, 0.06),
        'pig': (0.115, 0.07),
        'mouse': (0.09, 0.02),
        'bear': (0.125, 0.05)
    }

    State2Text = {
        'status': ('Seeing if %s is available...',
                   '%s is busy right now; try again later.'),
        'teleport': ('Trying to go to %s...', 'Could not go to %s.'),
        'friend': ('Asking %s to be your friend...', '%s said no, thank you.',
                   'You are now friends with %s!'),
        'remove':
        ('Are you sure you want to remove %s from your friends list?',
         '%s left your friends list.')
    }

    def __init__(self):
        DirectFrame.__init__(self, scale=1.2)
        self['image'] = DGG.getDefaultDialogGeom()
        self['image_hpr'] = (0, 0, -90)
        self['image_scale'] = (0.67, 0.9, 0.325)
        self['image_color'] = (1, 1, 0.75, 1)
        self['image_pos'] = (0, 0, -0.09)
        self['relief'] = None
        self.reparentTo(base.a2dTopRight)
        self.setPos(-0.235, 0.0, -0.325)
        self.hide()
        self.head = None
        self.laffMeter = None
        self.exitButton = None
        self.friendButton = None
        self.teleportButton = None
        self.whisperButton = None
        self.nameText = None
        self.actionFrame = None
        self.actionFrameText = None
        self.actionFrameButton = None
        self.actionFrameButton2 = None
        self.avatarInfo = None
        self.action = None
        self.locationText = None
        self.shardText = None
        self.detailsExitBtn = None

        self.fsm = ClassicFSM.ClassicFSM('ToonPanel', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('waitOnAvatarInfoResponse',
                        self.enterWaitOnAvatarInfoResponse,
                        self.exitWaitOnAvatarInfoResponse, ['panel']),
            State.State('panel', self.enterPanel, self.exitPanel, ['off'])
        ], 'off', 'off')
        self.fsm.enterInitialState()

        self.actionFSM = ClassicFSM.ClassicFSM('ToonPanelActionFSM', [
            State.State('off', self.enterOff, self.exitOff),
            State.State(
                'waitOnAvatarStatusResponse',
                self.enterWaitOnAvatarStatusResponse,
                self.exitWaitOnAvatarStatusResponse, [
                    'waitOnAvatarTeleportResponse',
                    'waitOnAvatarFriendListResponse', 'avatarBusy', 'off'
                ]),
            State.State('avatarBusy', self.enterAvatarBusy,
                        self.exitAvatarBusy, ['off']),
            State.State('waitOnAvatarTeleportResponse',
                        self.enterWaitOnAvatarTeleportResponse,
                        self.exitWaitOnAvatarTeleportResponse, ['unableToTP']),
            State.State('unableToTP', self.enterUnableToTP,
                        self.exitUnableToTP, ['off']),
            State.State('waitOnAvatarFriendListResponse',
                        self.enterWaitOnAvatarFriendListResponse,
                        self.exitWaitOnAvatarFriendListResponse,
                        ['fRequestA', 'fRequestR']),
            State.State('fRequestA', self.enterFriendRequestAccepted,
                        self.exitFriendRequestAccepted, ['off']),
            State.State('fRequestR', self.enterFriendRequestRejected,
                        self.exitFriendRequestRejected, ['off']),
            State.State('removeFriendConfirm', self.enterRemoveFriendConfirm,
                        self.exitRemoveFriendConfirm,
                        ['off', 'removedFriend']),
            State.State('removedFriend', self.enterRemovedFriend,
                        self.exitRemovedFriend, ['off'])
        ], 'off', 'off')
        self.actionFSM.enterInitialState()

    def makeMoreDetailsPanel(self):
        self.actionFSM.request('off')
        self.removeMoreDetailsPanel()
        self.removeActionPanel()
        self.makeActionPanel()
        zoneId = self.avatarInfo[5]
        shardId = self.avatarInfo[6]
        isOnline = self.avatarInfo[7]
        shardName = 'Unknown District'
        hoodName = ZoneUtil.getHoodId(zoneId, 1)
        for district in base.cr.activeDistricts.values():
            if district.doId == shardId:
                shardName = district.getDistrictName()
                break
        if not isOnline:
            hoodName = 'Offline'
            shardName = 'Offline'
        self.locationText = OnscreenText('Location: {0}'.format(hoodName),
                                         parent=self.actionFrame,
                                         pos=(-0.3, 0.05, 0),
                                         align=TextNode.ALeft,
                                         scale=0.04)
        self.shardText = OnscreenText('District: {0}'.format(shardName),
                                      parent=self.actionFrame,
                                      pos=(-0.3, 0.0, 0),
                                      align=TextNode.ALeft,
                                      scale=0.04)
        self.detailsExitBtn = DirectButton(geom=CIGlobals.getCancelBtnGeom(),
                                           parent=self.actionFrame,
                                           relief=None,
                                           scale=0.8,
                                           pos=(-0.3, 0.0, -0.175),
                                           command=self.removeMoreDetailsPanel)

    def removeMoreDetailsPanel(self):
        if self.locationText:
            self.locationText.destroy()
            self.locationText = None
        if self.shardText:
            self.shardText.destroy()
            self.shardText = None
        if self.detailsExitBtn:
            self.detailsExitBtn.destroy()
            self.detailsExitBtn = None
        self.removeActionPanel()

    def maybeUpdateFriendButton(self):
        if self.friendButton:
            if self.avatarInfo:
                if not self.avatarInfo[0] in base.localAvatar.friends:
                    self.friendButton['text'] = 'Add Friend'
                    self.friendButton['extraArgs'] = [
                        'waitOnAvatarFriendListResponse'
                    ]
                else:
                    self.friendButton['text'] = 'Remove Friend'
                    self.friendButton['extraArgs'] = ['removeFriendConfirm']

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterUnableToTP(self):
        pass

    def exitUnableToTP(self):
        pass

    def enterWaitOnAvatarTeleportResponse(self):
        self.setActionText(self.State2Text['teleport'][0] %
                           self.getAvatarName())
        self.makeButtons('Cancel')
        self.acceptOnce('gotAvatarTeleportResponse',
                        self.handleTeleportResponse)
        base.cr.friendsManager.d_iWantToTeleportToAvatar(self.avatarInfo[0])

    def handleTeleportResponse(self, avatarId, shardId, zoneId):
        if self.avatarInfo[0] == avatarId:
            requestStatus = {}
            whereName = ZoneUtil.getWhereName(zoneId)
            loaderName = ZoneUtil.getLoaderName(zoneId)
            requestStatus['zoneId'] = zoneId
            if base.localAvatar.parentId == shardId:
                requestStatus['shardId'] = None
            else:
                requestStatus['shardId'] = shardId
            requestStatus['hoodId'] = ZoneUtil.getHoodId(zoneId, 1)
            requestStatus['where'] = whereName
            requestStatus['loader'] = loaderName
            requestStatus['how'] = 'teleportIn'
            requestStatus['avId'] = avatarId
            base.cr.playGame.getPlace().fsm.request('teleportOut',
                                                    [requestStatus])
            self.cleanup()

    def exitWaitOnAvatarTeleportResponse(self):
        self.ignore('gotAvatarTeleportResponse')
        self.clearActionText()
        self.clearActionButtons()

    def setActionText(self, text):
        self.actionFrameText.setText(text)

    def clearActionText(self):
        self.actionFrameText.setText("")

    def makeButtons(self, button1, button2=None):
        button2GeomFunc = {
            'Cancel': CIGlobals.getCancelBtnGeom,
            'No': CIGlobals.getCancelBtnGeom,
            'Okay': CIGlobals.getOkayBtnGeom,
            'Yes': CIGlobals.getOkayBtnGeom
        }
        if button1 and not button2:
            button1Pos = (0, 0, -0.1)
        elif button1 and button2:
            button1Pos = (-0.1, 0, -0.1)
        button2Pos = (0.1, 0, -0.1)
        if button1:
            self.actionFrameButton = DirectButton(
                text=button1,
                geom=button2GeomFunc[button1](),
                parent=self.actionFrame,
                pos=button1Pos,
                text_scale=0.045,
                text_pos=(0, -0.08),
                command=self.actionButtonPressed,
                extraArgs=[1],
                relief=None,
                geom_scale=0.75)
        if button2:
            self.actionFrameButton2 = DirectButton(
                text=button2,
                geom=button2GeomFunc[button2](),
                parent=self.actionFrame,
                pos=button2Pos,
                text_scale=0.045,
                text_pos=(0, -0.08),
                command=self.actionButtonPressed,
                extraArgs=[2],
                relief=None,
                geom_scale=0.75)

    def actionButtonPressed(self, buttonNum):
        currentState = self.actionFSM.getCurrentState().getName()
        if buttonNum == 1:
            if currentState in [
                    'waitOnAvatarStatusResponse',
                    'waitOnAvatarTeleportResponse',
                    'waitOnAvatarFriendListResponse', 'avatarBusy',
                    'unableToTP', 'fRequestA', 'fRequestR',
                    'removeFriendConfirm', 'removedFriend'
            ]:
                if currentState == 'waitOnAvatarFriendListResponse':
                    base.cr.friendsManager.d_iCancelledFriendRequest(
                        self.avatarInfo[0])
                elif currentState == 'removeFriendConfirm':
                    self.actionFSM.request('removedFriend')
                    return
                self.actionFSM.request('off')
                self.removeActionPanel()
                self.action = None
        elif buttonNum == 2:
            self.actionFSM.request('off')
            self.removeActionPanel()
            self.action = None

    def clearActionButtons(self):
        if self.actionFrameButton2:
            self.actionFrameButton2.destroy()
            self.actionFrameButton2 = None
        if self.actionFrameButton:
            self.actionFrameButton.destroy()
            self.actionFrameButton = None

    def enterAvatarBusy(self):
        self.setActionText(self.State2Text['status'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitAvatarBusy(self):
        self.clearActionText()
        self.clearActionButtons()

    def getAvatarName(self):
        if self.avatarInfo:
            return self.avatarInfo[1]

    def enterWaitOnAvatarStatusResponse(self):
        self.acceptOnce('gotAvatarStatus', self.handleAvatarStatusResponse)
        base.cr.friendsManager.d_requestAvatarStatus(self.avatarInfo[0])
        self.setActionText(self.State2Text['status'][0] % self.getAvatarName())
        self.makeButtons('Cancel')

    def handleAvatarStatusResponse(self, avatarId, status):
        if avatarId == self.avatarInfo[0]:

            # Busy
            if status == 1:
                self.actionFSM.request('avatarBusy')

            # Not busy
            else:
                self.actionFSM.request(self.action)
        else:
            self.acceptOnce('gotAvatarStatus', self.handleAvatarStatusResponse)

    def exitWaitOnAvatarStatusResponse(self):
        self.ignore('gotAvatarStatus')
        self.clearActionText()
        self.clearActionButtons()

    def enterWaitOnAvatarFriendListResponse(self):
        self.acceptOnce('friendRequestAccepted',
                        self.handleFriendRequestAccepted)
        self.acceptOnce('friendRequestRejected',
                        self.handleFriendRequestRejected)
        base.cr.friendsManager.d_askAvatarToBeFriends(self.avatarInfo[0])
        self.setActionText(self.State2Text['friend'][0] % self.getAvatarName())
        self.makeButtons('Cancel')

    def handleFriendRequestAccepted(self):
        self.actionFSM.request('fRequestA')

    def handleFriendRequestRejected(self):
        self.actionFSM.request('fRequestR')

    def exitWaitOnAvatarFriendListResponse(self):
        self.ignore('friendRequestAccepted')
        self.ignore('friendRequestRejected')
        self.clearActionText()
        self.clearActionButtons()

    def enterFriendRequestAccepted(self):
        self.setActionText(self.State2Text['friend'][2] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitFriendRequestAccepted(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterFriendRequestRejected(self):
        self.setActionText(self.State2Text['friend'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitFriendRequestRejected(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterRemoveFriendConfirm(self):
        self.setActionText(self.State2Text['remove'][0] % self.getAvatarName())
        self.makeButtons('Yes', 'No')

    def exitRemoveFriendConfirm(self):
        self.clearActionText()
        self.clearActionButtons()

    def enterRemovedFriend(self):
        base.cr.friendsManager.d_iRemovedFriend(self.avatarInfo[0])
        self.setActionText(self.State2Text['remove'][1] % self.getAvatarName())
        self.makeButtons('Okay')

    def exitRemovedFriend(self):
        self.clearActionText()
        self.clearActionButtons()

    def makeActionPanel(self):
        self.actionFrame = DirectFrame(image=DGG.getDefaultDialogGeom(),
                                       image_scale=(0.7, 0.5, 0.45),
                                       image_color=(1, 1, 0.75, 1),
                                       relief=None)
        self.actionFrame.reparentTo(base.a2dTopRight)
        self.actionFrame.setPos(-0.815, 0, -0.31)
        self.actionFrameText = OnscreenText(text="",
                                            parent=self.actionFrame,
                                            scale=0.05,
                                            wordwrap=12,
                                            pos=(0, 0.1))

    def removeActionPanel(self):
        self.clearActionButtons()
        if self.actionFrameText:
            self.actionFrameText.destroy()
            self.actionFrameText = None
        if self.actionFrame:
            self.actionFrame.destroy()
            self.actionFrame = None

    def doAction(self, action):
        self.action = action
        self.actionFSM.requestFinalState()
        self.removeMoreDetailsPanel()
        self.removeActionPanel()
        self.makeActionPanel()
        if action != 'removeFriendConfirm':
            self.actionFSM.request('waitOnAvatarStatusResponse')
        else:
            self.actionFSM.request(action)

    def enterWaitOnAvatarInfoResponse(self):
        self.label = OnscreenText(text='Retrieving Toon\ndetails...',
                                  parent=self,
                                  scale=0.04)
        self.acceptOnce('avatarInfoResponse', self.handleAvatarInfoResponse)
        base.cr.friendsManager.d_requestAvatarInfo(self.avatarInfo[0])

    def handleAvatarInfoResponse(self, name, dna, maxHealth, health, zoneId,
                                 shardId, isOnline, adminToken):
        if self.avatarInfo:
            self.avatarInfo.append(name)
            self.avatarInfo.append(dna)
            self.avatarInfo.append(maxHealth)
            self.avatarInfo.append(health)
            self.avatarInfo.append(zoneId)
            self.avatarInfo.append(shardId)
            self.avatarInfo.append(isOnline)
            self.avatarInfo.append(adminToken)
            self.fsm.request('panel')

    def exitWaitOnAvatarInfoResponse(self):
        self.label.destroy()
        del self.label
        self.ignore('avatarInfoResponse')

    def makePanel(self, avId):
        if self.avatarInfo:
            if self.avatarInfo[0] == avId:
                # They clicked on the same toon without closing the
                # previous panel, maybe they're spamming?
                return

        self.cleanup()

        base.localAvatar.hideFriendButton()

        self.show()
        self.avatarInfo = []
        self.avatarInfo.append(avId)
        self.fsm.request('waitOnAvatarInfoResponse')

    def exitClicked(self):
        self.cleanup()
        base.localAvatar.showFriendButton()

    def cleanup(self):
        self.actionFSM.requestFinalState()
        self.fsm.requestFinalState()
        self.avatarInfo = None

    def enterPanel(self):
        adminToken = self.avatarInfo[8]
        text_color = CIGlobals.TextColorByAdminToken[adminToken]
        self.nameText = OnscreenText(text=self.avatarInfo[1],
                                     parent=self,
                                     pos=(0, 0.2),
                                     scale=0.035,
                                     wordwrap=8,
                                     fg=text_color)
        self.nameText.setBin('gui-popup', 60)

        dna = ToonDNA.ToonDNA()
        dna.setDNAStrand(self.avatarInfo[2])

        self.head = ToonHead.ToonHead(base.cr)
        self.head.generateHead(dna.gender, dna.animal, dna.head, 1)
        self.head.setHeadColor(dna.headcolor)
        self.head.reparentTo(self)
        self.head.setDepthWrite(1)
        self.head.setDepthTest(1)
        self.head.setH(180)
        self.head.setScale(self.animal2HeadData[dna.animal][0])
        self.head.setZ(self.animal2HeadData[dna.animal][1])

        self.laffMeter = LaffOMeter()
        r, g, b, _ = dna.headcolor
        self.laffMeter.generate(r, g, b, dna.animal, self.avatarInfo[3],
                                self.avatarInfo[4])
        self.laffMeter.reparentTo(self)
        self.laffMeter.setBin('gui-popup', 60)
        self.laffMeter.setScale(0.045)
        self.laffMeter.setPos(0, 0, -0.1)

        self.friendButton = DirectButton(
            geom=CIGlobals.getDefaultBtnGeom(),
            text="Add Friend",
            scale=0.58,
            relief=None,
            text_scale=0.058,
            geom_scale=(1.25, 0, 0.9),
            text_pos=(0, -0.0125),
            parent=self,
            pos=(0, 0, -0.12),
            command=self.doAction,
            extraArgs=['waitOnAvatarFriendListResponse'])
        self.friendButton.setPos(0, 0.0, -0.225)
        self.maybeUpdateFriendButton()

        self.teleportButton = DirectButton(
            geom=CIGlobals.getDefaultBtnGeom(),
            text="Teleport",
            scale=0.58,
            relief=None,
            text_scale=0.058,
            geom_scale=(1.25, 0, 0.9),
            text_pos=(0, -0.0125),
            parent=self,
            pos=(0, 0, -0.12),
            command=self.doAction,
            extraArgs=['waitOnAvatarTeleportResponse'])
        self.teleportButton.setPos(0, 0, -0.275)

        self.whisperButton = DirectButton(
            geom=CIGlobals.getDefaultBtnGeom(),
            text="Whisper",
            scale=0.58,
            relief=None,
            text_scale=0.058,
            geom_scale=(1.25, 0, 0.9),
            text_pos=(0, -0.0125),
            parent=self,
            pos=(0, 0, -0.12),
            command=base.localAvatar.handleClickedWhisper,
            extraArgs=[self.avatarInfo[1], self.avatarInfo[0], 1])
        self.whisperButton.setPos(0, 0, -0.325)

        self.exitButton = DirectButton(geom=CIGlobals.getCancelBtnGeom(),
                                       parent=self,
                                       relief=None,
                                       scale=0.6,
                                       pos=(0, 0.0, -0.39),
                                       command=self.exitClicked)
        gui = loader.loadModel("phase_3.5/models/gui/friendslist_gui.bam")
        self.moreDetailsBtn = DirectButton(
            geom=(gui.find('**/Horiz_Arrow_UP'), gui.find('**/Horiz_Arrow_DN'),
                  gui.find('**/Horiz_Arrow_Rllvr'),
                  gui.find('**/Horiz_Arrow_UP')),
            relief=None,
            parent=self,
            pos=(-0.127, 0.0, -0.39),
            geom_hpr=(180, 0, 0),
            command=self.makeMoreDetailsPanel,
            scale=0.77,
            text=('', 'More Details', 'More Details', ''),
            text_scale=0.045,
            text_fg=(1, 1, 1, 1),
            text_shadow=(0, 0, 0, 1),
            text_pos=(-0.08, -0.01),
            text_align=TextNode.ARight)

    def exitPanel(self):
        if self.actionFSM.getCurrentState().getName(
        ) == 'waitOnAvatarFriendListResponse':
            if self.avatarInfo:
                base.cr.friendsManager.d_iCancelledFriendRequest(
                    self.avatarInfo[0])
        self.actionFSM.requestFinalState()
        self.action = None
        self.avatarInfo = None
        self.removeActionPanel()
        self.removeMoreDetailsPanel()
        self.hide()
        if self.nameText:
            self.nameText.destroy()
            self.nameText = None
        if self.head:
            self.head.removeNode()
            self.head.delete()
            self.head = None
        if self.laffMeter:
            self.laffMeter.disable()
            self.laffMeter.delete()
            self.laffMeter = None
        if self.friendButton:
            self.friendButton.destroy()
            self.friendButton = None
        if self.teleportButton:
            self.teleportButton.destroy()
            self.teleportButton = None
        if self.whisperButton:
            self.whisperButton.destroy()
            self.whisperButton = None
        if self.exitButton:
            self.exitButton.destroy()
            self.exitButton = None
        if self.moreDetailsBtn:
            self.moreDetailsBtn.destroy()
            self.moreDetailsBtn = None
예제 #48
0
class CharSelection:
    notify = directNotify.newCategory('CharSelection')
    STAGE_TOON_POS = (66.4, 74.47, -25)
    STAGE_TOON_HPR = (227.73, 0, 0)
    NO_TOON = 'Empty Slot'
    PLAY = 'Play'
    CREATE = 'Create'
    TITLE = 'Pick  A  Toon  To  Play'

    def __init__(self, avChooser):
        self.avChooser = avChooser
        self.choice = None
        self.charList = None
        self.charNameLabel = None
        self.charButtons = []
        self.playOrCreateButton = None
        self.deleteButton = None
        self.quitButton = None
        self.world = None
        self.sky = None
        self.fog = None
        self.title = None
        self.stageToon = None
        self.selectionFSM = ClassicFSM.ClassicFSM('CharSelection', [State.State('off', self.enterOff, self.exitOff), State.State('character', self.enterCharSelected, self.exitCharSelected), State.State('empty', self.enterEmptySelected, self.exitEmptySelected)], 'off', 'off')
        self.selectionFSM.enterInitialState()
        return

    def __setupStageToon(self):
        self.stageToon = Toon(base.cr)
        self.stageToon.setPos(self.STAGE_TOON_POS)
        self.stageToon.setHpr(self.STAGE_TOON_HPR)

    def cleanupStageToon(self):
        if self.stageToon != None:
            self.stageToon.disable()
            self.stageToon.delete()
            self.stageToon = None
        return

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterCharSelected(self, slot):
        self.choice = self.avChooser.getAvChoiceBySlot(slot)
        dna = self.choice.dna
        name = self.choice.name
        self.stageToon.setName(name)
        self.stageToon.setDNAStrand(dna)
        self.stageToon.nameTag.setColorLocal()
        self.stageToon.animFSM.request('neutral')
        self.stageToon.reparentTo(base.render)
        self.charNameLabel.setText(name)
        self.playOrCreateButton['text'] = self.PLAY
        self.playOrCreateButton['extraArgs'] = ['play']
        self.playOrCreateButton.show()
        self.deleteButton.show()

    def exitCharSelected(self):
        self.stageToon.animFSM.requestFinalState()
        self.stageToon.deleteCurrentToon()
        self.stageToon.reparentTo(base.hidden)
        self.playOrCreateButton.hide()
        self.deleteButton.hide()
        self.choice = None
        return

    def enterEmptySelected(self):
        self.charNameLabel.setText(self.NO_TOON)
        self.playOrCreateButton['text'] = self.CREATE
        self.playOrCreateButton['extraArgs'] = ['create']
        self.playOrCreateButton.show()

    def exitEmptySelected(self):
        self.playOrCreateButton.hide()

    def __action(self, action):
        for btn in self.charButtons:
            if btn['state'] == DGG.DISABLED:
                self.slot = btn.getPythonTag('slot')
                break

        func = None
        arg = None
        if action == 'delete':
            func = self.deleteToon
            arg = self.choice.avId
        elif action == 'play':
            func = self.playGame
            arg = self.choice.slot
        elif action == 'create':
            func = self.enterMAT
        elif action == 'quit':
            func = sys.exit
        base.transitions.fadeOut(0.3)
        if arg != None:
            Sequence(Wait(0.31), Func(func, arg)).start()
        else:
            Sequence(Wait(0.31), Func(func)).start()
        return

    def playGame(self, slot):
        messenger.send('avChooseDone', [self.avChooser.getAvChoiceBySlot(slot)])

    def enterMAT(self):
        messenger.send('enterMakeAToon', [self.slot])

    def deleteToon(self, avId):
        self.avChooser.avChooseFSM.request('waitForToonDelResponse', [avId])

    def __handleCharButton(self, slot):
        for btn in self.charButtons:
            if btn.getPythonTag('slot') == slot:
                btn['state'] = DGG.DISABLED
            else:
                btn['state'] = DGG.NORMAL

        if self.avChooser.hasToonInSlot(slot):
            self.selectionFSM.request('character', [slot])
        else:
            self.selectionFSM.request('empty')

    def load(self):
        base.cr.renderFrame()
        base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4.0 / 3.0))
        self.__setupStageToon()
        self.world = loader.loadModel('phase_9/models/cogHQ/SellbotHQExterior.bam')
        self.world.reparentTo(base.render)
        self.world.setPos(0, 227.09, -25.36)
        self.sky = loader.loadModel('phase_9/models/cogHQ/cog_sky.bam')
        self.sky.setScale(1)
        self.sky.reparentTo(base.render)
        self.sky.find('**/InnerGroup').removeNode()
        self.fog = Fog('charSelectFog')
        self.fog.setColor(0.2, 0.2, 0.2)
        self.fog.setExpDensity(0.003)
        base.render.setFog(self.fog)
        self.title = DirectLabel(text=self.TITLE, text_font=CIGlobals.getMickeyFont(), text_fg=(1, 0.9, 0.1, 1), relief=None, text_scale=0.13, pos=(0, 0, 0.82))
        self.charNameLabel = OnscreenText(text='', font=CIGlobals.getMickeyFont(), pos=(-0.25, 0.5, 0), fg=(1, 0.9, 0.1, 1.0))
        self.charNameLabel.hide()
        self.playOrCreateButton = DirectButton(text='', pos=(0.8125, 0, -0.735), command=self.__action, geom=CIGlobals.getDefaultBtnGeom(), text_scale=0.06, relief=None, text_pos=(0, -0.01))
        self.playOrCreateButton.hide()
        self.deleteButton = DirectButton(text='Delete', pos=(0.8125, 0, -0.835), command=self.__action, extraArgs=['delete'], geom=CIGlobals.getDefaultBtnGeom(), text_scale=0.06, relief=None, text_pos=(0, -0.01))
        self.deleteButton.hide()
        self.quitButton = DirectButton(text='Quit', pos=(-1.1, 0, -0.925), command=self.__action, extraArgs=['quit'], text_scale=0.06, geom=CIGlobals.getDefaultBtnGeom(), relief=None, text_pos=(0, -0.01))
        textRolloverColor = Vec4(1, 1, 0, 1)
        textDownColor = Vec4(0.5, 0.9, 1, 1)
        textDisabledColor = Vec4(0.4, 0.8, 0.4, 1)
        for slot in range(6):
            if self.avChooser.hasToonInSlot(slot):
                choice = self.avChooser.getAvChoiceBySlot(slot)
                text = choice.name
            else:
                text = self.NO_TOON
            btn = DirectButton(relief=None, text=text, text_scale=0.06, text_align=TextNode.ALeft, text1_bg=textDownColor, text2_bg=textRolloverColor, text3_fg=textDisabledColor, textMayChange=0, command=self.__handleCharButton, extraArgs=[slot], text_pos=(0, 0, 0.0))
            btn.setPythonTag('slot', slot)
            self.charButtons.append(btn)
            btn['state'] = DGG.NORMAL

        gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        listXorigin = -0.02
        listFrameSizeX = 0.625
        listZorigin = -0.96
        listFrameSizeZ = 1.04
        arrowButtonScale = 1.3
        itemFrameXorigin = -0.237
        itemFrameZorigin = 0.365
        buttonXstart = itemFrameXorigin + 0.293
        self.charList = DirectScrolledList(relief=None, pos=(0.75, 0, 0.08), incButton_image=(gui.find('**/FndsLst_ScrollUp'),
         gui.find('**/FndsLst_ScrollDN'),
         gui.find('**/FndsLst_ScrollUp_Rllvr'),
         gui.find('**/FndsLst_ScrollUp')), incButton_relief=None, incButton_scale=(arrowButtonScale, arrowButtonScale, -arrowButtonScale), incButton_pos=(buttonXstart, 0, itemFrameZorigin - 0.999), incButton_image3_color=Vec4(1, 1, 1, 0.2), decButton_image=(gui.find('**/FndsLst_ScrollUp'),
         gui.find('**/FndsLst_ScrollDN'),
         gui.find('**/FndsLst_ScrollUp_Rllvr'),
         gui.find('**/FndsLst_ScrollUp')), decButton_relief=None, decButton_scale=(arrowButtonScale, arrowButtonScale, arrowButtonScale), decButton_pos=(buttonXstart, 0, itemFrameZorigin + 0.125), decButton_image3_color=Vec4(1, 1, 1, 0.2), itemFrame_pos=(itemFrameXorigin, 0, itemFrameZorigin), itemFrame_scale=1.0, itemFrame_relief=DGG.SUNKEN, itemFrame_frameSize=(listXorigin,
         listXorigin + listFrameSizeX,
         listZorigin,
         listZorigin + listFrameSizeZ), itemFrame_frameColor=(0.85, 0.95, 1, 1), itemFrame_borderWidth=(0.01, 0.01), numItemsVisible=15, forceHeight=0.075, items=self.charButtons)
        base.camera.setPos(75.12, 63.22, -23)
        base.camera.setHpr(26.57, 9.62, 0)
        return

    def unload(self):
        self.selectionFSM.requestFinalState()
        self.cleanupStageToon()
        self.choice = None
        if self.charButtons:
            for btn in self.charButtons:
                btn.destroy()

            self.charButtons = None
        if self.charList:
            self.charList.destroy()
            self.charList = None
        if self.charNameLabel:
            self.charNameLabel.destroy()
            self.charNameLabel = None
        if self.playOrCreateButton:
            self.playOrCreateButton.destroy()
            self.playOrCreateButton = None
        if self.deleteButton:
            self.deleteButton.destroy()
            self.deleteButton = None
        if self.quitButton:
            self.quitButton.destroy()
            self.quitButton = None
        if self.sky:
            self.sky.removeNode()
            self.sky = None
        if self.world:
            self.world.removeNode()
            self.world = None
        if self.title:
            self.title.destroy()
            self.title = None
        base.render.clearFog()
        self.fog = None
        base.camera.setPos(0, 0, 0)
        base.camera.setHpr(0, 0, 0)
        base.transitions.noTransitions()
        del self.selectionFSM
        return
예제 #49
0
class QuestMap(DirectFrame):
    def __init__(self, av, **kw):
        DirectFrame.__init__(self, relief=None, sortOrder=50)
        self.initialiseoptions(QuestMap)
        self.container = DirectFrame(parent=self, relief=None)
        self.marker = DirectFrame(parent=self.container, relief=None)
        self.cogInfoFrame = DirectFrame(parent=self.container, relief=None)
        cm = CardMaker('bg')
        cm.setFrame(-0.5, 0.5, -0.5, 0.5)
        bg = self.cogInfoFrame.attachNewNode(cm.generate())
        bg.setTransparency(1)
        bg.setColor(0.5, 0.5, 0.5, 0.5)
        bg.setBin('fixed', 0)
        self.cogInfoFrame['geom'] = bg
        self.cogInfoFrame['geom_pos'] = (0, 0, 0)
        self.cogInfoFrame['geom_scale'] = (6, 1, 2)
        self.cogInfoFrame.setScale(0.05)
        self.cogInfoFrame.setPos(0, 0, 0.6)
        self.buildingMarkers = []
        self.av = av
        self.wantToggle = False
        if base.config.GetBool('want-toggle-quest-map', True):
            self.wantToggle = True
        self.updateMarker = True
        self.cornerPosInfo = None
        self.hqPosInfo = None
        self.fishingSpotInfo = None
        self.load()
        self.setScale(1.5)
        bg.removeNode()
        self.hoodId = None
        self.zoneId = None
        self.suitPercentage = {}
        for currHoodInfo in SuitPlannerBase.SuitPlannerBase.SuitHoodInfo:
            tracks = currHoodInfo[
                SuitPlannerBase.SuitPlannerBase.SUIT_HOOD_INFO_TRACK]
            self.suitPercentage[currHoodInfo[
                SuitPlannerBase.SuitPlannerBase.SUIT_HOOD_INFO_ZONE]] = tracks

        return

    def load(self):
        gui = loader.loadModel('phase_4/models/questmap/questmap_gui')
        icon = gui.find('**/tt_t_gui_qst_arrow')
        iconNP = aspect2d.attachNewNode('iconNP')
        icon.reparentTo(iconNP)
        icon.setR(90)
        self.marker['geom'] = iconNP
        self.marker['image'] = iconNP
        self.marker.setScale(0.05)
        iconNP.removeNode()
        self.mapOpenButton = DirectButton(
            image=(gui.find('**/tt_t_gui_qst_mapClose'),
                   gui.find('**/tt_t_gui_qst_mapClose'),
                   gui.find('**/tt_t_gui_qst_mapTryToOpen')),
            relief=None,
            pos=(-0.084, 0, 0.37),
            parent=base.a2dBottomRight,
            scale=0.205,
            command=self.show)
        self.mapCloseButton = DirectButton(
            image=(gui.find('**/tt_t_gui_qst_mapOpen'),
                   gui.find('**/tt_t_gui_qst_mapOpen'),
                   gui.find('**/tt_t_gui_qst_mapTryToClose')),
            relief=None,
            pos=(-0.084, 0, 0.37),
            parent=base.a2dBottomRight,
            scale=0.205,
            command=self.hide)
        self.mapOpenButton.hide()
        self.mapCloseButton.hide()
        gui.removeNode()
        icons = loader.loadModel('phase_3/models/gui/cog_icons')
        cIcon = icons.find('**/CorpIcon')
        lIcon = icons.find('**/LegalIcon')
        mIcon = icons.find('**/MoneyIcon')
        sIcon = icons.find('**/SalesIcon')
        cogInfoTextColor = (0.2, 0.2, 0.2, 1)
        textPos = (1.2, -0.2)
        textScale = 0.8
        self.cInfo = DirectLabel(parent=self.cogInfoFrame,
                                 text='',
                                 text_fg=cogInfoTextColor,
                                 text_pos=textPos,
                                 text_scale=textScale,
                                 geom=cIcon,
                                 geom_pos=(-0.2, 0, 0),
                                 geom_scale=0.8,
                                 relief=None)
        self.cInfo.setPos(-2.2, 0, 0.5)
        self.lInfo = DirectLabel(parent=self.cogInfoFrame,
                                 text_fg=cogInfoTextColor,
                                 text='',
                                 text_pos=textPos,
                                 text_scale=textScale,
                                 geom=lIcon,
                                 geom_pos=(-0.2, 0, 0),
                                 geom_scale=0.8,
                                 relief=None)
        self.lInfo.setPos(-2.2, 0, -0.5)
        self.mInfo = DirectLabel(parent=self.cogInfoFrame,
                                 text_fg=cogInfoTextColor,
                                 text='',
                                 text_pos=textPos,
                                 text_scale=textScale,
                                 geom=mIcon,
                                 geom_pos=(-0.2, 0, 0),
                                 geom_scale=0.8,
                                 relief=None)
        self.mInfo.setPos(0.8, 0, 0.5)
        self.sInfo = DirectLabel(parent=self.cogInfoFrame,
                                 text_fg=cogInfoTextColor,
                                 text='',
                                 text_pos=textPos,
                                 text_scale=textScale,
                                 geom=sIcon,
                                 geom_pos=(-0.2, 0, 0),
                                 geom_scale=0.8,
                                 relief=None)
        self.sInfo.setPos(0.8, 0, -0.5)
        icons.removeNode()
        return

    def updateCogInfo(self):
        currPercentage = self.suitPercentage.get(self.zoneId)
        if currPercentage is None:
            return
        self.cInfo['text'] = '%s%%' % currPercentage[0]
        self.lInfo['text'] = '%s%%' % currPercentage[1]
        self.mInfo['text'] = '%s%%' % currPercentage[2]
        self.sInfo['text'] = '%s%%' % currPercentage[3]
        return

    def destroy(self):
        self.ignore('questPageUpdated')
        self.mapOpenButton.destroy()
        self.mapCloseButton.destroy()
        del self.mapOpenButton
        del self.mapCloseButton
        DirectFrame.destroy(self)

    def putBuildingMarker(self, pos, hpr=(0, 0, 0), mapIndex=None):
        marker = DirectLabel(parent=self.container,
                             text='',
                             text_pos=(-0.05, -0.15),
                             text_fg=(1, 1, 1, 1),
                             relief=None)
        gui = loader.loadModel(
            'phase_4/models/parties/schtickerbookHostingGUI')
        icon = gui.find('**/startPartyButton_inactive')
        iconNP = aspect2d.attachNewNode('iconNP')
        icon.reparentTo(iconNP)
        icon.setX(-12.0792 / 30.48)
        icon.setZ(-9.7404 / 30.48)
        marker['text'] = '%s' % mapIndex
        marker['text_scale'] = 0.7
        marker['image'] = iconNP
        marker['image_color'] = (1, 0, 0, 1)
        marker['image_scale'] = 6
        marker.setScale(0.05)
        relX, relY = self.transformAvPos(pos)
        marker.setPos(relX, 0, relY)
        self.buildingMarkers.append(marker)
        iconNP.removeNode()
        gui.removeNode()
        return

    def updateQuestInfo(self):
        for marker in self.buildingMarkers:
            marker.destroy()

        self.buildingMarkers = []
        dnaStore = base.cr.playGame.dnaStore
        for questIndex in self.av.questPage.quests.keys():
            questDesc = self.av.questPage.quests.get(questIndex)
            if questDesc is None:
                continue
            mapIndex = questIndex + 1
            questId, fromNpcId, toNpcId, rewardId, toonProgress = questDesc
            quest = Quests.getQuest(questId)
            fComplete = quest.getCompletionStatus(self.av,
                                                  questDesc) == Quests.COMPLETE
            if not fComplete:
                if quest.getType() == Quests.RecoverItemQuest:
                    if quest.getHolder() == Quests.AnyFish:
                        self.putBuildingMarker(self.fishingSpotInfo,
                                               mapIndex=mapIndex)
                    continue
                elif quest.getType(
                ) != Quests.DeliverGagQuest and quest.getType(
                ) != Quests.DeliverItemQuest and quest.getType(
                ) != Quests.VisitQuest and quest.getType(
                ) != Quests.TrackChoiceQuest:
                    continue
            if toNpcId == Quests.ToonHQ:
                self.putBuildingMarker(self.hqPosInfo, mapIndex=mapIndex)
            else:
                npcZone = NPCToons.getNPCZone(toNpcId)
                hoodId = ZoneUtil.getCanonicalHoodId(npcZone)
                branchId = ZoneUtil.getCanonicalBranchZone(npcZone)
                if self.hoodId == hoodId and self.zoneId == branchId:
                    for blockIndex in xrange(dnaStore.getNumBlockTitles()):
                        blockNumber = dnaStore.getTitleBlockAt(blockIndex)
                        zone = dnaStore.getZoneFromBlockNumber(blockNumber)
                        branchZone = zone - zone % 100
                        finalZone = branchZone + 500 + blockNumber
                        buildingType = dnaStore.getBlockBuildingType(
                            blockNumber)
                        if npcZone == finalZone:
                            self.putBuildingMarker(
                                dnaStore.getDoorPosHprFromBlockNumber(
                                    blockNumber).getPos(),
                                dnaStore.getDoorPosHprFromBlockNumber(
                                    blockNumber).getHpr(),
                                mapIndex=mapIndex)

        return

    def transformAvPos(self, pos):
        if self.cornerPosInfo is None:
            return (0, 0)
        topRight = self.cornerPosInfo[0]
        bottomLeft = self.cornerPosInfo[1]
        relativeX = (pos.getX() - bottomLeft.getX()) / (
            topRight.getX() - bottomLeft.getX()) - 0.5
        relativeY = (pos.getY() - bottomLeft.getY()) / (
            topRight.getY() - bottomLeft.getY()) - 0.5
        return (relativeX, relativeY)

    def update(self, task):
        if self.av:
            if self.updateMarker:
                relX, relY = self.transformAvPos(self.av.getPos())
                self.marker.setPos(relX, 0, relY)
                self.marker.setHpr(0, 0, -180 - self.av.getH())
        i = 0
        for buildingMarker in self.buildingMarkers:
            buildingMarker.setScale(
                (math.sin(task.time * 16.0 + i * math.pi / 3.0) + 1) * 0.005 +
                0.04)
            i = i + 1

        return Task.cont

    def updateMap(self):
        if self.av:
            try:
                hoodId = ZoneUtil.getCanonicalHoodId(self.av.getLocation()[1])
                zoneId = ZoneUtil.getCanonicalBranchZone(
                    self.av.getLocation()[1])
                mapsGeom = loader.loadModel('phase_4/models/questmap/%s_maps' %
                                            ToontownGlobals.dnaMap[hoodId])
                mapImage = mapsGeom.find(
                    '**/%s_%s_english' %
                    (ToontownGlobals.dnaMap[hoodId], zoneId))
                if not mapImage.isEmpty():
                    self.container['image'] = mapImage
                    self.resetFrameSize()
                    self.cornerPosInfo = QuestMapGlobals.CornerPosTable.get(
                        '%s_%s_english' %
                        (ToontownGlobals.dnaMap[hoodId], zoneId))
                    self.hqPosInfo = QuestMapGlobals.HQPosTable.get(
                        '%s_%s_english' %
                        (ToontownGlobals.dnaMap[hoodId], zoneId))
                    self.fishingSpotInfo = QuestMapGlobals.FishingSpotPosTable.get(
                        '%s_%s_english' %
                        (ToontownGlobals.dnaMap[hoodId], zoneId))
                    self.cogInfoPos = QuestMapGlobals.CogInfoPosTable.get(
                        '%s_%s_english' %
                        (ToontownGlobals.dnaMap[hoodId], zoneId))
                    self.cogInfoFrame.setPos(self.cogInfoPos)
                    self.hide()
                    self.hoodId = hoodId
                    self.zoneId = zoneId
                    self.updateQuestInfo()
                    self.updateCogInfo()
                    taskMgr.add(self.update, 'questMapUpdate')
                else:
                    self.stop()
                mapsGeom.removeNode()
            except:
                self.stop()

    def start(self):
        self.container.show()
        self.accept('questPageUpdated', self.updateMap)
        self.handleMarker()
        self.updateMap()

    def initMarker(self, task):
        if self.av:
            if not hasattr(base.cr.playGame.getPlace(), 'isInterior'
                           ) or not base.cr.playGame.getPlace().isInterior:
                relX, relY = self.transformAvPos(self.av.getPos())
                self.marker.setPos(relX, 0, relY)
                self.marker.setHpr(0, 0, -180 - self.av.getH())
            self.marker['geom_scale'] = 1.4 * task.time % 0.5 * 10 + 1
            self.marker['geom_color'] = (1, 1, 1, 0.8 -
                                         1.4 * task.time % 0.5 * 2 / 0.8 + 0.2)
        if task.time < 1:
            return Task.cont
        else:
            self.marker['geom_color'] = (1, 1, 1, 0)
            return Task.done

    def show(self):
        taskMgr.add(self.initMarker, 'questMapInit')
        DirectFrame.show(self)
        self.mapOpenButton.hide()
        if self.container['image']:
            self.mapCloseButton.show()

    def hide(self):
        taskMgr.remove('questMapInit')
        DirectFrame.hide(self)
        if self.container['image']:
            self.mapOpenButton.show()
        self.mapCloseButton.hide()

    def toggle(self):
        if self.isHidden():
            self.show()
        else:
            self.hide()

    def obscureButton(self):
        self.mapOpenButton.hide()
        self.mapCloseButton.hide()

    def stop(self):
        self.container['image'] = None
        for marker in self.buildingMarkers:
            marker.destroy()

        self.buildingMarkers = []
        self.container.hide()
        self.hide()
        self.obscureButton()
        self.ignore('questPageUpdated')
        taskMgr.remove('questMapUpdate')
        return

    def handleMarker(self):
        if hasattr(base.cr.playGame.getPlace(),
                   'isInterior') and base.cr.playGame.getPlace().isInterior:
            self.updateMarker = False
        else:
            self.updateMarker = True

    def acceptOnscreenHooks(self):
        if self.wantToggle:
            self.accept(ToontownGlobals.MapHotkey, self.toggle)
        else:
            self.accept(ToontownGlobals.MapHotkeyOn, self.show)
            self.accept(ToontownGlobals.MapHotkeyOff, self.hide)
        self.updateMap()

    def ignoreOnscreenHooks(self):
        self.ignore(ToontownGlobals.MapHotkey)
        self.ignore(ToontownGlobals.MapHotkeyOn)
        self.ignore(ToontownGlobals.MapHotkeyOff)
        self.obscureButton()
예제 #50
0
class PartyEditor(DirectObject, FSM):
    """
    This class creates the grid and scrolled list needed for players to
    drag and drop activities and decorations onto their party grounds.
    """
    notify = directNotify.newCategory("PartyEditor")

    def __init__(self, partyPlanner, parent):
        FSM.__init__(self, self.__class__.__name__)
        self.partyPlanner = partyPlanner
        self.parent = parent
        self.partyEditorGrid = PartyEditorGrid(self)
        self.currentElement = None

        self.defaultTransitions = {
            "Hidden": ["Idle", "Cleanup"],
            "Idle": ["DraggingElement", "Hidden", "Cleanup"],
            "DraggingElement":
            ["Idle", "DraggingElement", "Hidden", "Cleanup"],
            "Cleanup": [],
        }
        self.initElementList()
        self.initPartyClock()
        self.initTrashCan()

    def initElementList(self):
        self.activityIconsModel = loader.loadModel(
            "phase_4/models/parties/eventSignIcons")
        self.decorationModels = loader.loadModel(
            "phase_4/models/parties/partyDecorations")
        pos = self.partyPlanner.gui.find(
            "**/step_05_activitiesIcon_locator").getPos()
        self.elementList = DirectScrolledList(
            parent=self.parent,
            relief=None,
            # inc and dec are DirectButtons
            decButton_image=(
                self.partyPlanner.gui.find("**/activitiesButtonUp_up"),
                self.partyPlanner.gui.find("**/activitiesButtonUp_down"),
                self.partyPlanner.gui.find("**/activitiesButtonUp_rollover"),
                self.partyPlanner.gui.find("**/activitiesButtonUp_inactive"),
            ),
            decButton_relief=None,
            decButton_pos=(-0.05, 0.0, -0.38),
            incButton_image=(
                self.partyPlanner.gui.find("**/activitiesButtonDown_up"),
                self.partyPlanner.gui.find("**/activitiesButtonDown_down"),
                self.partyPlanner.gui.find("**/activitiesButtonDown_rollover"),
                self.partyPlanner.gui.find("**/activitiesButtonDown_inactive"),
            ),
            incButton_relief=None,
            incButton_pos=(-0.05, 0.0, -0.94),

            # itemFrame is a DirectFrame
            itemFrame_pos=(pos[0], pos[1], pos[2] + 0.04),
            itemFrame_relief=None,
            # each item is a button with text on it
            numItemsVisible=1,
            items=[],
        )

        for activityId in PartyGlobals.PartyEditorActivityOrder:
            if activityId in PartyGlobals.VictoryPartyActivityIds:
                holidayIds = base.cr.newsManager.getHolidayIdList()
                if ToontownGlobals.VICTORY_PARTY_HOLIDAY in holidayIds:
                    pele = PartyEditorListElement(self, activityId)
                    self.elementList.addItem(pele)
            elif activityId in PartyGlobals.VictoryPartyReplacementActivityIds:
                holidayIds = base.cr.newsManager.getHolidayIdList()
                if not ToontownGlobals.VICTORY_PARTY_HOLIDAY in holidayIds:
                    pele = PartyEditorListElement(self, activityId)
                    self.elementList.addItem(pele)
            else:
                pele = PartyEditorListElement(self, activityId)
                self.elementList.addItem(pele)
                if activityId == PartyGlobals.ActivityIds.PartyClock:
                    self.partyClockElement = pele

        for decorationId in PartyGlobals.DecorationIds:
            decorName = PartyGlobals.DecorationIds.getString(decorationId)
            if (decorName == "HeartTarget") \
            or (decorName == "HeartBanner") \
            or (decorName == "FlyingHeart"):
                holidayIds = base.cr.newsManager.getHolidayIdList()
                if ToontownGlobals.VALENTINES_DAY in holidayIds:
                    pele = PartyEditorListElement(self,
                                                  decorationId,
                                                  isDecoration=True)
                    self.elementList.addItem(pele)
            elif decorationId in PartyGlobals.VictoryPartyDecorationIds:
                holidayIds = base.cr.newsManager.getHolidayIdList()
                if ToontownGlobals.VICTORY_PARTY_HOLIDAY in holidayIds:
                    pele = PartyEditorListElement(self,
                                                  decorationId,
                                                  isDecoration=True)
                    self.elementList.addItem(pele)
            elif decorationId in PartyGlobals.VictoryPartyReplacementDecorationIds:
                holidayIds = base.cr.newsManager.getHolidayIdList()
                if not ToontownGlobals.VICTORY_PARTY_HOLIDAY in holidayIds:
                    pele = PartyEditorListElement(self,
                                                  decorationId,
                                                  isDecoration=True)
                    self.elementList.addItem(pele)
            else:
                pele = PartyEditorListElement(self,
                                              decorationId,
                                              isDecoration=True)
                self.elementList.addItem(pele)
        self.elementList.refresh()
        self.elementList['command'] = self.scrollItemChanged

    def initPartyClock(self):
        self.partyClockElement.buyButtonClicked((8, 7))

    def initTrashCan(self):
        trashcanGui = loader.loadModel("phase_3/models/gui/trashcan_gui")
        self.trashCanButton = DirectButton(
            parent=self.parent,
            relief=None,
            pos=Point3(*PartyGlobals.TrashCanPosition),
            scale=PartyGlobals.TrashCanScale,
            geom=(
                trashcanGui.find("**/TrashCan_CLSD"),
                trashcanGui.find("**/TrashCan_OPEN"),
                trashcanGui.find("**/TrashCan_RLVR"),
                trashcanGui.find("**/TrashCan_RLVR"),
            ),
            command=self.trashCanClicked,
        )
        self.trashCanButton.bind(DirectGuiGlobals.ENTER, self.mouseEnterTrash)
        self.trashCanButton.bind(DirectGuiGlobals.EXIT, self.mouseExitTrash)
        self.mouseOverTrash = False
        self.oldInstructionText = ""
        self.trashCanLastClickedTime = 0

    def scrollItemChanged(self):
        if not self.elementList["items"]:
            # we are probably closing the gui, do nothing
            return
        self.currentElement = self.elementList["items"][
            self.elementList.getSelectedIndex()]
        self.elementList["items"][
            self.elementList.getSelectedIndex()].elementSelectedFromList()
        if self.elementList["items"][
                self.elementList.getSelectedIndex()].isDecoration:
            self.partyPlanner.instructionLabel[
                "text"] = TTLocalizer.PartyPlannerEditorInstructionsClickedElementDecoration
        else:
            self.partyPlanner.instructionLabel[
                "text"] = TTLocalizer.PartyPlannerEditorInstructionsClickedElementActivity

    def listElementClicked(self):
        self.request("DraggingElement")

    def listElementReleased(self):
        self.request("Idle", True)

    def trashCanClicked(self):
        currentTime = time.time()
        # Check for double click, if so, clear the party grounds
        if currentTime - self.trashCanLastClickedTime < 0.2:
            self.clearPartyGrounds()
        self.trashCanLastClickedTime = time.time()

    def clearPartyGrounds(self):
        for item in self.elementList["items"]:
            item.clearPartyGrounds()
        self.initPartyClock()
        if self.currentElement:
            self.currentElement.checkSoldOutAndPaidStatusAndAffordability()

    def buyCurrentElement(self):
        if self.currentElement:
            purchaseSuccessful = self.currentElement.buyButtonClicked()
            if purchaseSuccessful:
                # The buying and placement of the item was successful
                self.handleMutuallyExclusiveActivities()
                pass
            else:
                # The buying and placement of the item was not successful
                self.partyPlanner.instructionLabel[
                    "text"] = TTLocalizer.PartyPlannerEditorInstructionsNoRoom

    def mouseEnterTrash(self, mouseEvent):
        self.mouseOverTrash = True
        self.oldInstructionText = self.partyPlanner.instructionLabel["text"]
        self.partyPlanner.instructionLabel[
            "text"] = TTLocalizer.PartyPlannerEditorInstructionsTrash

    def mouseExitTrash(self, mouseEvent):
        self.mouseOverTrash = False
        self.partyPlanner.instructionLabel["text"] = self.oldInstructionText

    ### FSM Methods ###

    def enterHidden(self):
        PartyEditor.notify.debug("Enter Hidden")

    def exitHidden(self):
        PartyEditor.notify.debug("Exit Hidden")

    def enterIdle(self, fromDragging=False):
        PartyEditor.notify.debug("Enter Idle")
        if not fromDragging:
            self.elementList.scrollTo(0)
            self.elementList["items"][0].elementSelectedFromList()
            self.currentElement = self.elementList["items"][
                self.elementList.getSelectedIndex()]
            self.currentElement.checkSoldOutAndPaidStatusAndAffordability()
        self.partyPlanner.instructionLabel[
            "text"] = TTLocalizer.PartyPlannerEditorInstructionsIdle
        self.updateCostsAndBank()
        self.handleMutuallyExclusiveActivities()

    def handleMutuallyExclusiveActivities(self):
        """Smartly removed the older activity and inform the user."""
        mutSet = self.getMutuallyExclusiveActivities()
        if not mutSet:
            return
        # our mutset doesn't tell us which one is older
        currentActivities = self.partyEditorGrid.getActivitiesElementsOnGrid()
        lastActivity = self.partyEditorGrid.lastActivityIdPlaced
        for act in currentActivities:
            if (act.id in mutSet) and not (lastActivity == act.id):
                act.removeFromGrid()
                removedName = TTLocalizer.PartyActivityNameDict[
                    act.id]["editor"]
                addedName = TTLocalizer.PartyActivityNameDict[lastActivity][
                    "editor"]
                instr = TTLocalizer.PartyPlannerEditorInstructionsRemoved % \
                        {"removed" : removedName, "added" : addedName}
                self.partyPlanner.instructionLabel["text"] = instr
                self.updateCostsAndBank()
                # deliberately no break here, in case they manage to
                # get 3 jukeboxes into the editor somehow

    def getMutuallyExclusiveActivities(self):
        """Return the set of activities on the grid that are mutually exclusive, None otherwise."""
        # create a set of activity Ids
        currentActivities = self.partyEditorGrid.getActivitiesOnGrid()
        actSet = Set([])
        for act in currentActivities:
            actSet.add(act[0])
        result = None
        for mutuallyExclusiveTuples in PartyGlobals.MutuallyExclusiveActivities:
            mutSet = Set(mutuallyExclusiveTuples)
            inter = mutSet.intersection(actSet)
            if len(inter) > 1:
                result = inter
                break
        return result

    def updateCostsAndBank(self):
        """
        We need to update the total cost of the party and what they will have
        left in their bank.
        """
        currentActivities = self.partyEditorGrid.getActivitiesOnGrid()
        currentDecorations = self.partyEditorGrid.getDecorationsOnGrid()
        newCost = 0
        for elementTuple in currentActivities:
            newCost += PartyGlobals.ActivityInformationDict[
                elementTuple[0]]["cost"]
        for elementTuple in currentDecorations:
            newCost += PartyGlobals.DecorationInformationDict[
                elementTuple[0]]["cost"]
        self.partyPlanner.costLabel[
            "text"] = TTLocalizer.PartyPlannerTotalCost % newCost
        if len(currentActivities) > 0 or len(currentDecorations) > 0:
            self.partyPlanner.setNextButtonState(enabled=True)
        else:
            self.partyPlanner.setNextButtonState(enabled=False)
        self.partyPlanner.totalCost = newCost
        self.partyPlanner.beanBank["text"] = str(
            int(self.partyPlanner.totalMoney - self.partyPlanner.totalCost))

    def exitIdle(self):
        PartyEditor.notify.debug("Exit Idle")

    def enterDraggingElement(self):
        PartyEditor.notify.debug("Enter DraggingElement")
        if self.currentElement.isDecoration:
            self.partyPlanner.instructionLabel[
                "text"] = TTLocalizer.PartyPlannerEditorInstructionsDraggingDecoration
        else:
            self.partyPlanner.instructionLabel[
                "text"] = TTLocalizer.PartyPlannerEditorInstructionsDraggingActivity

    def exitDraggingElement(self):
        PartyEditor.notify.debug("Exit DraggingElement")

    def enterCleanup(self):
        PartyEditor.notify.debug("Enter Cleanup")
        self.partyEditorGrid.destroy()
        self.elementList.removeAndDestroyAllItems()
        self.elementList.destroy()
        self.trashCanButton.unbind(DirectGuiGlobals.ENTER)
        self.trashCanButton.unbind(DirectGuiGlobals.EXIT)
        self.trashCanButton.destroy()

    def exitCleanup(self):
        PartyEditor.notify.debug("Exit Cleanup")
예제 #51
0
 def destroy(self):
     self.unbind(DirectGuiGlobals.B1PRESS)
     self.unbind(DirectGuiGlobals.B1RELEASE)
     self.unbind(DirectGuiGlobals.ENTER)
     self.unbind(DirectGuiGlobals.EXIT)
     DirectButton.destroy(self)
예제 #52
0
class CalendarGuiMonth(DirectFrame):
    __module__ = __name__
    notify = directNotify.newCategory('CalendarGuiMonth')

    def __init__(self,
                 parent,
                 startingDateTime,
                 scale=1.0,
                 pos=(0, 0, -0.1),
                 dayClickCallback=None,
                 onlyFutureDaysClickable=False,
                 onlyFutureMonthsClickable=False):
        self.startDate = startingDateTime
        self.curDate = startingDateTime
        self.dayClickCallback = dayClickCallback
        self.onlyFutureDaysClickable = onlyFutureDaysClickable
        self.onlyFutureMonthsClickable = onlyFutureMonthsClickable
        if self.onlyFutureDaysClickable:
            self.onlyFutureMonthsClickable = True
        DirectFrame.__init__(self, parent=parent, scale=scale, pos=pos)
        self.showMarkers = base.config.GetBool('show-calendar-markers', 0)
        self.load()
        self.createGuiObjects()
        self.lastSelectedDate = None
        self.accept('clickedOnDay', self.clickedOnDay)
        return

    def createDummyLocators(self):
        self.monthLocator = self.attachNewNode('monthLocator')
        self.monthLocator.setZ(0.6)
        self.weekDayLocators = []
        for i in xrange(7):
            self.weekDayLocators.append(
                self.attachNewNode('weekDayLocator-%d' % i))
            self.weekDayLocators[i].setZ(0.5)
            self.weekDayLocators[i].setX(i * 0.24 + -0.75)

        dayTopLeftX = -0.8
        dayTopLeftZ = 0.4
        self.dayLocators = []
        for row in xrange(6):
            oneWeek = []
            for col in xrange(7):
                newDayLoc = self.attachNewNode('dayLocator-row-%d-col-%d' %
                                               (row, col))
                newDayLoc.setX(col * 0.24 + dayTopLeftX)
                newDayLoc.setZ(row * -0.18 + dayTopLeftZ)
                oneWeek.append(newDayLoc)

            self.dayLocators.append(oneWeek)

        self.monthLeftLocator = self.attachNewNode('monthLeft')
        self.monthLeftLocator.setPos(-0.3, 0, 0.65)
        self.monthRightLocator = self.attachNewNode('monthRight')
        self.monthRightLocator.setPos(0.3, 0, 0.65)

    def attachMarker(self, parent, scale=0.01, color=(1, 0, 0)):
        if self.showMarkers:
            marker = loader.loadModel('phase_3/models/misc/sphere')
            marker.reparentTo(parent)
            marker.setScale(scale)
            marker.setColor(*color)

    def load(self):
        monthAsset = loader.loadModel(
            'phase_4/models/parties/tt_m_gui_sbk_calendar')
        monthAsset.reparentTo(self)
        self.monthLocator = self.find('**/locator_month/locator_month')
        self.attachMarker(self.monthLocator)
        self.weekDayLocators = []
        for weekday in ('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'):
            weekDayLoc = self.find('**/loc_%s' % weekday)
            self.weekDayLocators.append(weekDayLoc)
            self.attachMarker(weekDayLoc)

        self.dayLocators = []
        for row in xrange(6):
            oneWeek = []
            for col in xrange(7):
                newDayLoc = self.find('**/loc_box_%s_%s' % (row, col))
                oneWeek.append(newDayLoc)

            self.dayLocators.append(oneWeek)

        self.monthLeftLocator = self.find('**/locator_month_arrowL')
        self.monthRightLocator = self.find('**/locator_month_arrowR')
        self.filterLocator = self.find('**/locator_filter')
        self.filterLocatorArrowUp = self.find('**/locator_filter_arrowTop')
        self.filterLocatorArrowDown = self.find(
            '**/locator_filter_arrowBottom')
        self.yearLocator = self.attachNewNode('yearLocator')
        self.yearLocator.setPos(self.monthLocator, 0, 0, -0.03)

    def createGuiObjects(self):
        self.monthLabel = DirectLabel(
            parent=self.monthLocator,
            relief=None,
            text=TTLocalizer.Months[self.startDate.month],
            text_scale=0.075,
            text_font=ToontownGlobals.getMinnieFont(),
            text_fg=(40 / 255.0, 140 / 255.0, 246 / 255.0, 1.0))
        self.yearLabel = DirectLabel(parent=self.yearLocator,
                                     relief=None,
                                     text=str(self.startDate.year),
                                     text_scale=0.03,
                                     text_font=ToontownGlobals.getMinnieFont(),
                                     text_fg=(140 / 255.0, 140 / 255.0,
                                              246 / 255.0, 1.0))
        self.weekdayLabels = []
        for posIndex in xrange(7):
            adjustedNameIndex = (posIndex - 1) % 7
            self.weekdayLabels.append(
                DirectLabel(parent=self.weekDayLocators[posIndex],
                            relief=None,
                            text=TTLocalizer.DayNamesAbbrev[adjustedNameIndex],
                            text_font=ToontownGlobals.getInterfaceFont(),
                            text_fg=(255 / 255.0, 146 / 255.0, 113 / 255.0,
                                     1.0),
                            text_scale=0.05))

        self.createGuiDays()
        arrowUp = self.find('**/month_arrowR_up')
        arrowDown = self.find('**/month_arrowR_down')
        arrowHover = self.find('**/month_arrowR_hover')
        self.monthLeftArrow = DirectButton(parent=self.monthLeftLocator,
                                           relief=None,
                                           image=(arrowUp, arrowDown,
                                                  arrowHover, arrowUp),
                                           image3_color=Vec4(1, 1, 1, 0.5),
                                           scale=(-1.0, 1.0, 1.0),
                                           command=self.__doMonthLeft)
        if self.onlyFutureMonthsClickable:
            self.monthLeftArrow.hide()
        self.monthRightArrow = DirectButton(parent=self.monthRightLocator,
                                            relief=None,
                                            image=(arrowUp, arrowDown,
                                                   arrowHover, arrowUp),
                                            image3_color=Vec4(1, 1, 1, 0.5),
                                            command=self.__doMonthRight)

        def makeLabel(itemName, itemNum, *extraArgs):
            return DirectLabel(text=itemName,
                               frameColor=(0, 0, 0, 0),
                               text_scale=0.04)

        gui = loader.loadModel(
            'phase_4/models/parties/tt_m_gui_sbk_calendar_box')
        arrowUp = gui.find('**/downScroll_up')
        arrowDown = gui.find('**/downScroll_down')
        arrowHover = gui.find('**/downScroll_hover')
        filterLocatorUpPos = self.filterLocatorArrowUp.getPos(
            self.filterLocator)
        filterLocatorDownPos = self.filterLocatorArrowDown.getPos(
            self.filterLocator)
        self.filterList = DirectScrolledList(
            parent=self.filterLocator,
            relief=None,
            pos=(0, 0, 0),
            image=None,
            text_scale=0.025,
            incButton_image=(arrowUp, arrowDown, arrowHover, arrowUp),
            incButton_relief=None,
            incButton_pos=filterLocatorDownPos,
            incButton_image3_color=Vec4(1, 1, 1, 0.2),
            incButtonCallback=self.filterChanged,
            decButton_image=(arrowUp, arrowDown, arrowHover, arrowUp),
            decButton_relief=None,
            decButton_pos=filterLocatorUpPos,
            decButton_scale=(1, 1, -1),
            decButton_image3_color=Vec4(1, 1, 1, 0.2),
            decButtonCallback=self.filterChanged,
            numItemsVisible=1,
            itemMakeFunction=makeLabel,
            items=[
                TTLocalizer.CalendarShowAll,
                TTLocalizer.CalendarShowOnlyHolidays,
                TTLocalizer.CalendarShowOnlyParties
            ],
            itemFrame_frameSize=(-0.2, 0.2, -0.02, 0.05),
            itemFrame_frameColor=(0, 0, 0, 0))
        gui.removeNode()
        return

    def getTopLeftDate(self):
        firstOfTheMonth = self.curDate.replace(day=1)
        daysAwayFromSunday = (firstOfTheMonth.weekday() - 6) % 7
        topLeftDate = firstOfTheMonth + timedelta(days=-daysAwayFromSunday)
        return topLeftDate

    def createGuiDays(self):
        topLeftDate = self.getTopLeftDate()
        curDate = topLeftDate
        self.guiDays = []
        for row in self.dayLocators:
            for oneLocator in row:
                self.guiDays.append(
                    CalendarGuiDay(oneLocator, curDate, self.curDate,
                                   self.dayClickCallback,
                                   self.onlyFutureDaysClickable))
                curDate += timedelta(days=1)

    def changeDateForGuiDays(self):
        topLeftDate = self.getTopLeftDate()
        guiDayDate = topLeftDate
        for guiDay in self.guiDays:
            guiDay.changeDate(self.curDate, guiDayDate)
            guiDayDate += timedelta(days=1)

    def changeMonth(self, monthChange):
        if monthChange != 0:
            newMonth = self.curDate.month + monthChange
            newYear = self.curDate.year
            while newMonth > 12:
                newYear += 1
                newMonth -= 12

            while newMonth < 1:
                if newYear - 1 > 1899:
                    newMonth += 12
                    newYear -= 1
                else:
                    newMonth += 1

            self.curDate = datetime(newYear, newMonth, 1,
                                    self.curDate.time().hour,
                                    self.curDate.time().minute,
                                    self.curDate.time().second,
                                    self.curDate.time().microsecond,
                                    self.curDate.tzinfo)
        self.monthLabel['text'] = (TTLocalizer.Months[self.curDate.month], )
        self.yearLabel['text'] = (str(self.curDate.year), )
        startTime = globalClock.getRealTime()
        self.changeDateForGuiDays()
        endTime = globalClock.getRealTime()
        self.notify.debug('changeDate took %f seconds' % (endTime - startTime))
        self.updateSelectedDate()
        if monthChange != 0:
            if self.onlyFutureMonthsClickable and newMonth == self.startDate.month and newYear == self.startDate.year:
                self.monthLeftArrow.hide()

    def __doMonthLeft(self):
        self.changeMonth(-1)

    def __doMonthRight(self):
        self.monthLeftArrow.show()
        self.changeMonth(1)

    def destroy(self):
        self.ignoreAll()
        self.dayClickCallback = None
        self.monthLeftArrow.destroy()
        self.monthRightArrow.destroy()
        for day in self.guiDays:
            if day is not None:
                day.destroy()
            day = None

        self.filterList.destroy()
        DirectFrame.destroy(self)
        return

    def clickedOnDay(self, dayDate):
        self.lastSelectedDate = dayDate
        self.updateSelectedDate()

    def updateSelectedDate(self):
        if self.lastSelectedDate:
            for oneGuiDay in self.guiDays:
                if oneGuiDay.myDate.date() == self.lastSelectedDate:
                    oneGuiDay.updateSelected(True)
                else:
                    oneGuiDay.updateSelected(False)

    def clearSelectedDay(self):
        for oneGuiDay in self.guiDays:
            oneGuiDay.updateSelected(False)

    def filterChanged(self):
        newFilter = self.filterList.getSelectedIndex()
        for guiDay in self.guiDays:
            guiDay.changeFilter(newFilter)
예제 #53
0
class EventsPage(ShtikerPage.ShtikerPage):
    notify = DirectNotifyGlobal.directNotify.newCategory('EventsPage')

    def __init__(self):
        ShtikerPage.ShtikerPage.__init__(self)
        self.mode = EventsPage_Calendar
        self.setMode(self.mode)
        self.noTeleport = config.GetBool('Parties-page-disable', 0)
        self.isPrivate = True
        self.hostedPartyInfo = None
        return

    def load(self):
        self.scrollButtonGui = loader.loadModel(
            'phase_3.5/models/gui/friendslist_gui')
        self.hostingGui = loader.loadModel(
            'phase_4/models/parties/schtickerbookHostingGUI')
        self.invitationGui = loader.loadModel(
            'phase_4/models/parties/schtickerbookInvitationGUI')
        self.activityIconsModel = loader.loadModel(
            'phase_4/models/parties/eventSignIcons')
        self.decorationModels = loader.loadModel(
            'phase_4/models/parties/partyDecorations')
        self.loadTabs()
        self.loadHostingTab()
        self.loadInvitationsTab()
        self.loadCalendarTab()
        self.titleLabel = DirectLabel(
            parent=self,
            relief=None,
            text=TTLocalizer.EventsPageHostTabTitle,
            text_scale=TTLocalizer.EPtitleLabel,
            textMayChange=True,
            pos=self.hostingGui.find('**/myNextParty_text_locator').getPos())
        return

    def loadTabs(self):
        normalColor = (1.0, 1.0, 1.0, 1.0)
        clickColor = (0.8, 0.8, 0.0, 1.0)
        rolloverColor = (0.15, 0.82, 1.0, 1.0)
        diabledColor = (1.0, 0.98, 0.15, 1.0)
        gui = loader.loadModel('phase_3.5/models/gui/fishingBook')
        self.hostTab = DirectButton(parent=self,
                                    relief=None,
                                    text=TTLocalizer.EventsPageHostTabName,
                                    text_scale=TTLocalizer.EPhostTab,
                                    text_align=TextNode.ACenter,
                                    text_pos=(0.12, 0.0),
                                    image=gui.find('**/tabs/polySurface1'),
                                    image_pos=(0.55, 1, -0.91),
                                    image_hpr=(0, 0, -90),
                                    image_scale=(0.033, 0.033, 0.035),
                                    image_color=normalColor,
                                    image1_color=clickColor,
                                    image2_color=rolloverColor,
                                    image3_color=diabledColor,
                                    text_fg=Vec4(0.2, 0.1, 0, 1),
                                    command=self.setMode,
                                    extraArgs=[EventsPage_Host],
                                    pos=(-0.13, 0, 0.775))
        self.invitedTab = DirectButton(
            parent=self,
            relief=None,
            text=TTLocalizer.EventsPageInvitedTabName,
            text_scale=TTLocalizer.EPinvitedTab,
            text_pos=(0.12, 0.0),
            text_align=TextNode.ACenter,
            image=gui.find('**/tabs/polySurface2'),
            image_pos=(0.12, 1, -0.91),
            image_hpr=(0, 0, -90),
            image_scale=(0.033, 0.033, 0.035),
            image_color=normalColor,
            image1_color=clickColor,
            image2_color=rolloverColor,
            image3_color=diabledColor,
            text_fg=Vec4(0.2, 0.1, 0, 1),
            command=self.setMode,
            extraArgs=[EventsPage_Invited],
            pos=(0.28, 0, 0.775))
        self.calendarTab = DirectButton(
            parent=self,
            relief=None,
            text=TTLocalizer.EventsPageCalendarTabName,
            text_scale=TTLocalizer.EPcalendarTab,
            text_pos=(0.12, 0.0),
            text_align=TextNode.ACenter,
            image=gui.find('**/tabs/polySurface2'),
            image_pos=(0.12, 1, -0.91),
            image_hpr=(0, 0, -90),
            image_scale=(0.033, 0.033, 0.035),
            image_color=normalColor,
            image1_color=clickColor,
            image2_color=rolloverColor,
            image3_color=diabledColor,
            text_fg=Vec4(0.2, 0.1, 0, 1),
            command=self.setMode,
            extraArgs=[EventsPage_Calendar],
            pos=(-0.55, 0, 0.775))
        return

    def loadHostingTab(self):
        self.hostedPartyDisplay = self.attachNewNode('Hosting')
        self.hostedPartyDisplay.setPos(0.0, 0.0, 0.04)
        self.hostingBackgroundFlat = DirectFrame(
            parent=self.hostedPartyDisplay,
            relief=None,
            geom=self.hostingGui.find('**/background_flat'))
        self.hostingGuestList, self.hostingGuestLabel = self.createListAndLabel(
            self.hostedPartyDisplay, self.hostingGui, 'guests', 7)
        self.hostingActivityList, self.hostingActivityLabel = self.createListAndLabel(
            self.hostedPartyDisplay, self.hostingGui, 'activities', 1)
        self.hostingDecorationList, self.hostingDecorationLabel = self.createListAndLabel(
            self.hostedPartyDisplay, self.hostingGui, 'decorations', 1)
        self.hostingDateLabel = DirectLabel(
            parent=self.hostedPartyDisplay,
            relief=None,
            text='',
            scale=TTLocalizer.EPhostingDateLabel,
            text_align=TextNode.ACenter,
            text_wordwrap=10,
            textMayChange=True,
            pos=self.hostingGui.find('**/date_locator').getPos())
        pos = self.hostingGui.find('**/cancel_text_locator').getPos()
        self.hostingCancelButton = DirectButton(
            parent=self.hostedPartyDisplay,
            relief=None,
            geom=(self.hostingGui.find('**/cancelPartyButton_up'),
                  self.hostingGui.find('**/cancelPartyButton_down'),
                  self.hostingGui.find('**/cancelPartyButton_rollover'),
                  self.hostingGui.find('**/cancelPartyButton_inactive')),
            text=TTLocalizer.EventsPageHostTabCancelButton,
            text_scale=TTLocalizer.EPhostingCancelButton,
            text_pos=(pos[0], pos[2]),
            command=self.__doCancelParty)
        pos = self.hostingGui.find('**/startParty_text_locator').getPos()
        self.partyGoButton = DirectButton(
            parent=self.hostedPartyDisplay,
            relief=None,
            geom=(self.hostingGui.find('**/startPartyButton_up'),
                  self.hostingGui.find('**/startPartyButton_down'),
                  self.hostingGui.find('**/startPartyButton_rollover'),
                  self.hostingGui.find('**/startPartyButton_inactive')),
            text=TTLocalizer.EventsPageGoButton,
            text_scale=TTLocalizer.EPpartyGoButton,
            text_pos=(pos[0], pos[2]),
            textMayChange=True,
            command=self._startParty)
        self.publicPrivateLabel = DirectLabel(
            parent=self.hostedPartyDisplay,
            relief=None,
            text=TTLocalizer.EventsPageHostTabPublicPrivateLabel,
            text_scale=TTLocalizer.EPpublicPrivateLabel,
            text_align=TextNode.ACenter,
            pos=self.hostingGui.find('**/thisPartyIs_text_locator').getPos())
        pos = self.hostingGui.find('**/public_text_locator').getPos()
        checkedImage = self.hostingGui.find('**/checked_button')
        uncheckedImage = self.hostingGui.find('**/unchecked_button')
        self.publicButton = DirectCheckButton(
            parent=self.hostedPartyDisplay,
            relief=None,
            scale=0.1,
            boxBorder=0.08,
            boxImage=(uncheckedImage, checkedImage, None),
            boxImageScale=10,
            boxRelief=None,
            text=TTLocalizer.EventsPageHostTabToggleToPublic,
            text_align=TextNode.ALeft,
            text_scale=TTLocalizer.EPpublicButton,
            pos=pos,
            command=self.__changePublicPrivate,
            indicator_pos=(-0.7, 0, 0.2))
        pos = self.hostingGui.find('**/private_text_locator').getPos()
        self.privateButton = DirectCheckButton(
            parent=self.hostedPartyDisplay,
            relief=None,
            scale=0.1,
            boxBorder=0.08,
            boxImage=(uncheckedImage, checkedImage, None),
            boxImageScale=10,
            boxRelief=None,
            text=TTLocalizer.EventsPageHostTabToggleToPrivate,
            text_align=TextNode.ALeft,
            text_scale=TTLocalizer.EPprivateButton,
            pos=pos,
            command=self.__changePublicPrivate,
            indicator_pos=(-0.7, 0, 0.2))
        self.confirmCancelPartyEvent = 'confirmCancelPartyEvent'
        self.accept(self.confirmCancelPartyEvent, self.confirmCancelOfParty)
        self.confirmCancelPartyGui = TTDialog.TTGlobalDialog(
            dialogName=self.uniqueName('confirmCancelPartyGui'),
            doneEvent=self.confirmCancelPartyEvent,
            message=TTLocalizer.EventsPageConfirmCancel %
            int(PartyGlobals.PartyRefundPercentage * 100.0),
            style=TTDialog.YesNo,
            okButtonText=OTPLocalizer.DialogYes,
            cancelButtonText=OTPLocalizer.DialogNo)
        self.confirmCancelPartyGui.doneStatus = ''
        self.confirmCancelPartyGui.hide()
        self.confirmTooLatePartyEvent = 'confirmTooLatePartyEvent'
        self.accept(self.confirmTooLatePartyEvent, self.confirmTooLateParty)
        self.confirmTooLatePartyGui = TTDialog.TTGlobalDialog(
            dialogName=self.uniqueName('confirmTooLatePartyGui'),
            doneEvent=self.confirmTooLatePartyEvent,
            message=TTLocalizer.EventsPageTooLateToStart,
            style=TTDialog.Acknowledge)
        self.confirmTooLatePartyGui.hide()
        self.confirmPublicPrivateChangeEvent = 'confirmPublicPrivateChangeEvent'
        self.accept(self.confirmPublicPrivateChangeEvent,
                    self.confirmPublicPrivateChange)
        self.confirmPublicPrivateGui = TTDialog.TTGlobalDialog(
            dialogName=self.uniqueName('confirmPublicPrivateGui'),
            doneEvent=self.confirmPublicPrivateChangeEvent,
            message=TTLocalizer.EventsPagePublicPrivateNoGo,
            style=TTDialog.Acknowledge)
        self.confirmPublicPrivateGui.hide()
        self.cancelPartyResultGuiEvent = 'cancelPartyResultGuiEvent'
        self.accept(self.cancelPartyResultGuiEvent,
                    self.cancelPartyResultGuiCommand)
        self.cancelPartyResultGui = TTDialog.TTGlobalDialog(
            dialogName=self.uniqueName('cancelPartyResultGui'),
            doneEvent=self.cancelPartyResultGuiEvent,
            message=TTLocalizer.EventsPageCancelPartyResultOk % 0,
            style=TTDialog.Acknowledge)
        self.cancelPartyResultGui.doneStatus = ''
        self.cancelPartyResultGui.hide()
        self.__setPublicPrivateButton()
        return

    def loadInvitationsTab(self):
        self.invitationDisplay = self.attachNewNode('invitations')
        self.invitationDisplay.setPos(0.0, 0.0, 0.04)
        self.invitationBackgroundFlat = DirectFrame(
            parent=self.invitationDisplay,
            relief=None,
            geom=self.invitationGui.find('**/background_flat'))
        self.invitationPartiesFlat = DirectFrame(
            parent=self.invitationDisplay,
            relief=None,
            geom=self.invitationGui.find('**/parties_background'))
        self.invitationActivtiesFlat = DirectFrame(
            parent=self.invitationDisplay,
            relief=None,
            geom=self.invitationGui.find('**/activities_background'))
        self.invitationPartyList, self.invitationPartyLabel = self.createListAndLabel(
            self.invitationDisplay, self.invitationGui, 'parties', 7,
            'ButtonDown', 'ButtonUp', 'Text_locator')
        self.invitationActivityList, self.invitationActivityLabel = self.createListAndLabel(
            self.invitationDisplay, self.invitationGui, 'activities', 1,
            'ButtonDown', 'ButtonUp', 'Text_locator')
        pos = self.invitationGui.find('**/startText_locator').getPos()
        self.invitePartyGoButton = DirectButton(
            parent=self.invitationDisplay,
            relief=None,
            geom=(self.invitationGui.find('**/startButton_up'),
                  self.invitationGui.find('**/startButton_down'),
                  self.invitationGui.find('**/startButton_rollover'),
                  self.invitationGui.find('**/startButton_inactive')),
            text=TTLocalizer.EventsPageInviteGoButton,
            text_scale=TTLocalizer.EPinvitePartyGoButton,
            text_pos=(pos[0], pos[2]),
            textMayChange=True,
            command=self._inviteStartParty)
        self.invitationDateTimeLabel = DirectLabel(
            parent=self.invitationDisplay,
            relief=None,
            text='',
            textMayChange=True,
            text_scale=0.07,
            pos=(0, 0, -0.65))
        return

    def loadCalendarTab(self):
        self.calendarDisplay = self.attachNewNode('calendar')
        self.toontownTimeLabel = DirectLabel(
            parent=self.calendarDisplay,
            pos=(0.175, 0, -0.69),
            text_align=TextNode.ARight,
            relief=None,
            text=TTLocalizer.EventsPageToontownTimeIs,
            text_scale=0.065,
            text_font=ToontownGlobals.getMinnieFont(),
            text_fg=(255 / 255.0, 146 / 255.0, 113 / 255.0, 1),
            textMayChange=0)
        self.calendarGuiMonth = None  # To be set upon tab's first opening.
        pos = (0.35, 0, -0.69)
        self.toontownTimeGui = ServerTimeGui(self.calendarDisplay, pos)
        return

    def getGuestItem(self, name, inviteStatus):
        label = DirectLabel(relief=None,
                            text=name,
                            text_scale=0.045,
                            text_align=TextNode.ALeft,
                            textMayChange=True)
        dot = DirectFrame(relief=None,
                          geom=self.hostingGui.find('**/questionMark'),
                          pos=(0.5, 0.0, 0.01))
        if inviteStatus == PartyGlobals.InviteStatus.Accepted:
            dot['geom'] = (self.hostingGui.find('**/checkmark'), )
        elif inviteStatus == PartyGlobals.InviteStatus.Rejected:
            dot['geom'] = (self.hostingGui.find('**/x'), )
        PartyUtils.truncateTextOfLabelBasedOnWidth(
            label, name, PartyGlobals.EventsPageGuestNameMaxWidth)
        dot.reparentTo(label)
        return label

    def getActivityItem(self, activityBase, count=1):
        activityName = TTLocalizer.PartyActivityNameDict[
            activityBase.activityId]['generic']
        if count == 1:
            textForActivity = activityName
        else:
            textForActivity = '%s x %d' % (activityName, count)
        iconString = PartyGlobals.ActivityIds.getString(
            activityBase.activityId)
        geom = getPartyActivityIcon(self.activityIconsModel, iconString)
        label = DirectLabel(relief=None,
                            geom=geom,
                            geom_scale=0.38,
                            geom_pos=Vec3(0.0, 0.0, -0.17),
                            text=textForActivity,
                            text_scale=TTLocalizer.EPactivityItemLabel,
                            text_align=TextNode.ACenter,
                            text_pos=(-0.01, -0.43),
                            text_wordwrap=7.0)
        return label

    def getDecorationItem(self, decorBase, count=1):
        decorationName = TTLocalizer.PartyDecorationNameDict[
            decorBase.decorId]['editor']
        if count == 1:
            textForDecoration = decorationName
        else:
            textForDecoration = decorationName + ' x ' + str(count)
        assetName = PartyGlobals.DecorationIds.getString(decorBase.decorId)
        label = DirectLabel(relief=None,
                            geom=self.decorationModels.find(
                                '**/partyDecoration_%s' % assetName),
                            text=textForDecoration,
                            text_scale=TTLocalizer.EPdecorationItemLabel,
                            text_align=TextNode.ACenter,
                            text_pos=(-0.01, -0.43),
                            text_wordwrap=7.0)
        label['geom_scale'] = (2.6, 0.01, 0.05)
        label['geom_pos'] = (0.0, 0.0, -0.33)
        return label

    def getToonNameFromAvId(self, avId):
        result = TTLocalizer.EventsPageUnknownToon
        sender = base.cr.identifyAvatar(avId)
        if sender:
            result = sender.getName()
        return result

    def loadInvitations(self):
        EventsPage.notify.debug('loadInvitations')
        self.selectedInvitationItem = None
        self.invitationPartyList.removeAndDestroyAllItems()
        self.invitationActivityList.removeAndDestroyAllItems()
        self.invitePartyGoButton['state'] = DirectGuiGlobals.DISABLED
        for partyInfo in base.localAvatar.partiesInvitedTo:
            if partyInfo.status == PartyGlobals.PartyStatus.Cancelled or partyInfo.status == PartyGlobals.PartyStatus.Finished:
                continue
            inviteInfo = None
            for inviteInfo in base.localAvatar.invites:
                if partyInfo.partyId == inviteInfo.partyId:
                    break

            if inviteInfo is None:
                EventsPage.notify.error('No invitation info for party id %d' %
                                        partyInfo.partyId)
                return
            if inviteInfo.status == PartyGlobals.InviteStatus.NotRead:
                continue
            hostName = self.getToonNameFromAvId(partyInfo.hostId)
            item = DirectButton(relief=None,
                                text=hostName,
                                text_align=TextNode.ALeft,
                                text_bg=Vec4(0.0, 0.0, 0.0, 0.0),
                                text_scale=0.045,
                                textMayChange=True,
                                command=self.invitePartyClicked)
            PartyUtils.truncateTextOfLabelBasedOnWidth(
                item, hostName, PartyGlobals.EventsPageHostNameMaxWidth)
            item['extraArgs'] = [item]
            item.setPythonTag('activityIds', partyInfo.getActivityIds())
            item.setPythonTag('partyStatus', partyInfo.status)
            item.setPythonTag('hostId', partyInfo.hostId)
            item.setPythonTag('startTime', partyInfo.startTime)
            self.invitationPartyList.addItem(item)

        return

    def invitePartyClicked(self, item):
        if item.getPythonTag(
                'partyStatus') == PartyGlobals.PartyStatus.Started:
            self.invitePartyGoButton['state'] = DirectGuiGlobals.NORMAL
        else:
            self.invitePartyGoButton['state'] = DirectGuiGlobals.DISABLED
        if self.selectedInvitationItem is not None:
            self.selectedInvitationItem['state'] = DirectGuiGlobals.NORMAL
            self.selectedInvitationItem['text_bg'] = Vec4(0.0, 0.0, 0.0, 0.0)
        self.selectedInvitationItem = item
        self.selectedInvitationItem['state'] = DirectGuiGlobals.DISABLED
        self.selectedInvitationItem['text_bg'] = Vec4(1.0, 1.0, 0.0, 1.0)
        self.fillInviteActivityList(item.getPythonTag('activityIds'))
        startTime = item.getPythonTag('startTime')
        self.invitationDateTimeLabel[
            'text'] = TTLocalizer.EventsPageInvitedTabTime % (
                PartyUtils.formatDate(startTime.year, startTime.month,
                                      startTime.day),
                PartyUtils.formatTime(startTime.hour, startTime.minute))
        return

    def fillInviteActivityList(self, activityIds):
        self.invitationActivityList.removeAndDestroyAllItems()
        countDict = {}
        for actId in activityIds:
            if actId not in countDict:
                countDict[actId] = 1
            else:
                countDict[actId] += 1

        for activityId in countDict:
            if countDict[activityId] == 1:
                textOfActivity = TTLocalizer.PartyActivityNameDict[activityId][
                    'generic']
            else:
                textOfActivity = TTLocalizer.PartyActivityNameDict[activityId][
                    'generic'] + ' x ' + str(countDict[activityId])
            geom = getPartyActivityIcon(
                self.activityIconsModel,
                PartyGlobals.ActivityIds.getString(activityId))
            item = DirectLabel(relief=None,
                               text=textOfActivity,
                               text_align=TextNode.ACenter,
                               text_scale=0.05,
                               text_pos=(0.0, -0.15),
                               geom_scale=0.3,
                               geom_pos=Vec3(0.0, 0.0, 0.07),
                               geom=geom)
            self.invitationActivityList.addItem(item)

        return

    def _inviteStartParty(self):
        if self.selectedInvitationItem is None:
            self.invitePartyGoButton['state'] = DirectGuiGlobals.DISABLED
            return
        self.doneStatus = {
            'mode': 'startparty',
            'firstStart': False,
            'hostId': self.selectedInvitationItem.getPythonTag('hostId')
        }
        messenger.send(self.doneEvent)
        return

    def loadHostedPartyInfo(self):
        self.unloadGuests()
        self.unloadActivities()
        self.unloadDecorations()
        self.hostedPartyInfo = None
        self.confirmCancelPartyGui.doneStatus = ''
        self.confirmCancelPartyGui.hide()
        self.cancelPartyResultGui.doneStatus = ''
        self.cancelPartyResultGui.hide()
        if base.localAvatar.hostedParties is not None and len(
                base.localAvatar.hostedParties) > 0:
            for partyInfo in base.localAvatar.hostedParties:
                if partyInfo.status == PartyGlobals.PartyStatus.Pending or partyInfo.status == PartyGlobals.PartyStatus.CanStart or partyInfo.status == PartyGlobals.PartyStatus.NeverStarted or partyInfo.status == PartyGlobals.PartyStatus.Started:
                    self.hostedPartyInfo = partyInfo
                    self.loadGuests()
                    self.loadActivities()
                    self.loadDecorations()
                    self.hostingDateLabel[
                        'text'] = TTLocalizer.EventsPageHostTabDateTimeLabel % (
                            PartyUtils.formatDate(partyInfo.startTime.year,
                                                  partyInfo.startTime.month,
                                                  partyInfo.startTime.day),
                            PartyUtils.formatTime(partyInfo.startTime.hour,
                                                  partyInfo.startTime.minute))
                    self.isPrivate = partyInfo.isPrivate
                    self.__setPublicPrivateButton()
                    if partyInfo.status == PartyGlobals.PartyStatus.CanStart:
                        self.partyGoButton['state'] = DirectGuiGlobals.NORMAL
                        self.partyGoButton['text'] = (
                            TTLocalizer.EventsPageGoButton, )
                    elif partyInfo.status == PartyGlobals.PartyStatus.Started:
                        place = base.cr.playGame.getPlace()
                        if isinstance(place, Party):
                            if hasattr(base, 'distributedParty'):
                                if base.distributedParty.partyInfo.hostId == base.localAvatar.doId:
                                    self.partyGoButton[
                                        'state'] = DirectGuiGlobals.DISABLED
                                else:
                                    self.partyGoButton[
                                        'state'] = DirectGuiGlobals.NORMAL
                            else:
                                self.partyGoButton[
                                    'state'] = DirectGuiGlobals.NORMAL
                                self.notify.warning(
                                    'base.distributedParty is not defined when base.cr.playGame.getPlace is party. This should never happen.'
                                )
                        else:
                            self.partyGoButton[
                                'state'] = DirectGuiGlobals.NORMAL
                        self.partyGoButton['text'] = (
                            TTLocalizer.EventsPageGoBackButton, )
                    else:
                        self.partyGoButton['text'] = (
                            TTLocalizer.EventsPageGoButton, )
                        self.partyGoButton['state'] = DirectGuiGlobals.DISABLED
                    if partyInfo.status not in (
                            PartyGlobals.PartyStatus.Pending,
                            PartyGlobals.PartyStatus.CanStart):
                        self.hostingCancelButton[
                            'state'] = DirectGuiGlobals.DISABLED
                    else:
                        self.hostingCancelButton[
                            'state'] = DirectGuiGlobals.NORMAL
                    self.hostingDateLabel.show()
                    self.hostedPartyDisplay.show()
                    return

        self.hostingDateLabel['text'] = TTLocalizer.EventsPageHostingTabNoParty
        self.hostingCancelButton['state'] = DirectGuiGlobals.DISABLED
        self.partyGoButton['state'] = DirectGuiGlobals.DISABLED
        self.publicButton['state'] = DirectGuiGlobals.DISABLED
        self.privateButton['state'] = DirectGuiGlobals.DISABLED
        self.hostedPartyDisplay.show()
        return

    def checkCanStartHostedParty(self):
        result = True
        if self.hostedPartyInfo.endTime < base.cr.toontownTimeManager.getCurServerDateTime(
        ) and self.hostedPartyInfo.status == PartyGlobals.PartyStatus.CanStart:
            result = False
            self.confirmTooLatePartyGui.show()
        return result

    def confirmTooLateParty(self):
        if hasattr(self, 'confirmTooLatePartyGui'):
            self.confirmTooLatePartyGui.hide()

    def confirmPublicPrivateChange(self):
        if hasattr(self, 'confirmPublicPrivateGui'):
            self.confirmPublicPrivateGui.hide()

    def _startParty(self):
        if not self.checkCanStartHostedParty():
            return
        if self.hostedPartyInfo.status == PartyGlobals.PartyStatus.CanStart:
            firstStart = True
        else:
            firstStart = False
        self.doneStatus = {
            'mode': 'startparty',
            'firstStart': firstStart,
            'hostId': None
        }
        messenger.send(self.doneEvent)
        return

    def loadGuests(self):
        for partyReplyInfoBase in base.localAvatar.partyReplyInfoBases:
            if partyReplyInfoBase.partyId == self.hostedPartyInfo.partyId:
                for singleReply in partyReplyInfoBase.replies:
                    toonName = self.getToonNameFromAvId(singleReply.inviteeId)
                    self.hostingGuestList.addItem(
                        self.getGuestItem(toonName, singleReply.status))

    def loadActivities(self):
        countDict = {}
        for activityBase in self.hostedPartyInfo.activityList:
            if activityBase.activityId not in countDict:
                countDict[activityBase.activityId] = 1
            else:
                countDict[activityBase.activityId] += 1

        idsUsed = []
        for activityBase in self.hostedPartyInfo.activityList:
            if activityBase.activityId not in idsUsed:
                idsUsed.append(activityBase.activityId)
                count = countDict[activityBase.activityId]
                self.hostingActivityList.addItem(
                    self.getActivityItem(activityBase, count))

    def loadDecorations(self):
        countDict = {}
        for decorBase in self.hostedPartyInfo.decors:
            if decorBase.decorId not in countDict:
                countDict[decorBase.decorId] = 1
            else:
                countDict[decorBase.decorId] += 1

        idsUsed = []
        for decorBase in self.hostedPartyInfo.decors:
            if decorBase.decorId not in idsUsed:
                count = countDict[decorBase.decorId]
                self.hostingDecorationList.addItem(
                    self.getDecorationItem(decorBase, count))
                idsUsed.append(decorBase.decorId)

    def unloadGuests(self):
        self.hostingGuestList.removeAndDestroyAllItems()

    def unloadActivities(self):
        self.hostingActivityList.removeAndDestroyAllItems()

    def unloadDecorations(self):
        self.hostingDecorationList.removeAndDestroyAllItems()

    def unload(self):
        self.scrollButtonGui.removeNode()
        self.hostingGui.removeNode()
        self.invitationGui.removeNode()
        self.activityIconsModel.removeNode()
        self.decorationModels.removeNode()
        del self.titleLabel
        self.hostingGuestList.removeAndDestroyAllItems()
        self.hostingGuestList.destroy()
        del self.hostingGuestList
        self.hostingActivityList.removeAndDestroyAllItems()
        self.hostingActivityList.destroy()
        del self.hostingActivityList
        self.hostingDecorationList.removeAndDestroyAllItems()
        self.hostingDecorationList.destroy()
        del self.hostingDecorationList
        self.invitationPartyList.removeAndDestroyAllItems()
        self.invitationPartyList.destroy()
        del self.invitationPartyList
        self.invitationActivityList.removeAndDestroyAllItems()
        self.invitationActivityList.destroy()
        del self.invitationActivityList
        self.confirmCancelPartyGui.cleanup()
        del self.confirmCancelPartyGui
        self.confirmTooLatePartyGui.cleanup()
        del self.confirmTooLatePartyGui
        self.confirmPublicPrivateGui.cleanup()
        del self.confirmPublicPrivateGui
        self.ignore('changePartyPrivateResponseReceived')
        taskMgr.remove('changePartyPrivateResponseReceivedTimeOut')
        self.cancelPartyResultGui.cleanup()
        del self.cancelPartyResultGui
        self.ignore(self.confirmCancelPartyEvent)
        self.ignore(self.cancelPartyResultGuiEvent)
        self.avatar = None
        self.hostingCancelButton.destroy()
        del self.hostingCancelButton
        self.partyGoButton.destroy()
        del self.partyGoButton
        self.publicButton.destroy()
        del self.publicButton
        self.privateButton.destroy()
        del self.privateButton
        self.invitePartyGoButton.destroy()
        del self.invitePartyGoButton
        self.hostTab.destroy()
        self.invitedTab.destroy()
        self.calendarTab.destroy()
        if self.calendarGuiMonth:
            self.calendarGuiMonth.destroy()
        self.toontownTimeGui.destroy()
        taskMgr.remove('EventsPageUpdateTask-doLater')
        ShtikerPage.ShtikerPage.unload(self)
        return

    def enter(self):
        self.updatePage()
        ShtikerPage.ShtikerPage.enter(self)

    def exit(self):
        ShtikerPage.ShtikerPage.exit(self)
        self.unloadGuests()
        self.unloadActivities()
        self.unloadDecorations()

    def __handleConfirm(self):
        self.ignore('confirmDone')
        self.confirm.cleanup()
        del self.confirm

    def createListAndLabel(self,
                           parent,
                           gui,
                           typeString,
                           itemsVisible,
                           downString='DownArrow',
                           upString='UpArrow',
                           textString='_text_locator'):
        list = DirectScrolledList(
            parent=parent,
            relief=None,
            incButton_image=(gui.find('**/%s%s_up' % (typeString, downString)),
                             gui.find('**/%s%s_down' %
                                      (typeString, downString)),
                             gui.find('**/%s%s_rollover' %
                                      (typeString, downString)),
                             gui.find('**/%s%s_inactive' %
                                      (typeString, downString))),
            incButton_relief=None,
            decButton_image=(gui.find('**/%s%s_up' % (typeString, upString)),
                             gui.find('**/%s%s_down' % (typeString, upString)),
                             gui.find('**/%s%s_rollover' %
                                      (typeString, upString)),
                             gui.find('**/%s%s_inactive' %
                                      (typeString, upString))),
            decButton_relief=None,
            itemFrame_pos=gui.find('**/%s_locator' % typeString).getPos(),
            itemFrame_relief=None,
            numItemsVisible=itemsVisible,
            forceHeight=0.07)
        strings = {
            'guests': TTLocalizer.EventsPageHostingTabGuestListTitle,
            'activities': TTLocalizer.EventsPageHostingTabActivityListTitle,
            'decorations':
            TTLocalizer.EventsPageHostingTabDecorationsListTitle,
            'parties': TTLocalizer.EventsPageHostingTabPartiesListTitle
        }
        label = DirectLabel(parent=parent,
                            relief=None,
                            text=strings[typeString],
                            text_scale=TTLocalizer.EPcreateListAndLabel,
                            pos=gui.find('**/%s%s' %
                                         (typeString, textString)).getPos())
        return (list, label)

    def setMode(self, mode, updateAnyways=0):
        messenger.send('wakeup')
        if updateAnyways == False:
            if self.mode == mode:
                return
            else:
                self.mode = mode
        self.show()
        self.updatePage()

    def getMode(self):
        return self.mode

    def updatePage(self):
        if self.mode == EventsPage_Host:
            self.hostTab['state'] = DirectGuiGlobals.DISABLED
            self.invitedTab['state'] = DirectGuiGlobals.NORMAL
            self.calendarTab['state'] = DirectGuiGlobals.NORMAL
            self.invitationDisplay.hide()
            self.hostedPartyDisplay.show()
            self.calendarDisplay.hide()
            self.loadHostedPartyInfo()
            if self.hostedPartyInfo is None:
                self.titleLabel[
                    'text'] = TTLocalizer.EventsPageHostTabTitleNoParties
            else:
                self.titleLabel['text'] = TTLocalizer.EventsPageHostTabTitle
        elif self.mode == EventsPage_Invited:
            self.titleLabel['text'] = TTLocalizer.EventsPageInvitedTabTitle
            self.hostTab['state'] = DirectGuiGlobals.NORMAL
            self.invitedTab['state'] = DirectGuiGlobals.DISABLED
            self.calendarTab['state'] = DirectGuiGlobals.NORMAL
            self.hostedPartyDisplay.hide()
            self.invitationDisplay.show()
            self.calendarDisplay.hide()
            self.loadInvitations()
        elif self.mode == EventsPage_Calendar:
            self.titleLabel['text'] = ''
            self.hostTab['state'] = DirectGuiGlobals.NORMAL
            self.invitedTab['state'] = DirectGuiGlobals.NORMAL
            self.calendarTab['state'] = DirectGuiGlobals.DISABLED
            self.hostedPartyDisplay.hide()
            self.invitationDisplay.hide()
            self.calendarDisplay.show()
            if not self.calendarGuiMonth:
                curServerDate = base.cr.toontownTimeManager.getCurServerDateTime(
                )
                self.calendarGuiMonth = CalendarGuiMonth(
                    self.calendarDisplay,
                    curServerDate,
                    onlyFutureMonthsClickable=True)
            self.calendarGuiMonth.changeMonth(0)
        return

    def __setPublicPrivateButton(self):
        if self.isPrivate:
            self.privateButton['indicatorValue'] = True
            self.publicButton['indicatorValue'] = False
            self.privateButton['state'] = DirectGuiGlobals.DISABLED
            self.publicButton['state'] = DirectGuiGlobals.NORMAL
        else:
            self.privateButton['indicatorValue'] = False
            self.publicButton['indicatorValue'] = True
            self.privateButton['state'] = DirectGuiGlobals.NORMAL
            self.publicButton['state'] = DirectGuiGlobals.DISABLED

    def __changePublicPrivate(self, indicator):
        self.__setPublicPrivateButton()
        self.confirmPublicPrivateGui[
            'text'] = TTLocalizer.EventsPagePublicPrivateChange
        self.confirmPublicPrivateGui.buttonList[0].hide()
        self.confirmPublicPrivateGui.show()
        base.cr.partyManager.sendChangePrivateRequest(
            self.hostedPartyInfo.partyId, not self.isPrivate)
        self.accept('changePartyPrivateResponseReceived',
                    self.changePartyPrivateResponseReceived)
        taskMgr.doMethodLater(
            5.0, self.changePartyPrivateResponseReceived,
            'changePartyPrivateResponseReceivedTimeOut',
            [0, 0, PartyGlobals.ChangePartyFieldErrorCode.DatabaseError])

    def changePartyPrivateResponseReceived(self, partyId, newPrivateStatus,
                                           errorCode):
        EventsPage.notify.debug(
            'changePartyPrivateResponseReceived called with partyId = %d, newPrivateStatus = %d, errorCode = %d'
            % (partyId, newPrivateStatus, errorCode))
        taskMgr.remove('changePartyPrivateResponseReceivedTimeOut')
        self.ignore('changePartyPrivateResponseReceived')
        if errorCode == PartyGlobals.ChangePartyFieldErrorCode.AllOk:
            self.isPrivate = newPrivateStatus
            self.confirmPublicPrivateGui.hide()
        else:
            self.confirmPublicPrivateGui.buttonList[0].show()
            if errorCode == PartyGlobals.ChangePartyFieldErrorCode.AlreadyStarted:
                self.confirmPublicPrivateGui[
                    'text'] = TTLocalizer.EventsPagePublicPrivateAlreadyStarted
            else:
                self.confirmPublicPrivateGui[
                    'text'] = TTLocalizer.EventsPagePublicPrivateNoGo
        self.__setPublicPrivateButton()

    def __doCancelParty(self):
        if self.hostedPartyInfo:
            if self.hostedPartyInfo.status == PartyGlobals.PartyStatus.Pending or self.hostedPartyInfo.status == PartyGlobals.PartyStatus.CanStart or self.hostedPartyInfo.status == PartyGlobals.PartyStatus.NeverStarted:
                self.hostingCancelButton['state'] = DirectGuiGlobals.DISABLED
                self.confirmCancelPartyGui.show()

    def confirmCancelOfParty(self):
        self.confirmCancelPartyGui.hide()
        if self.confirmCancelPartyGui.doneStatus == 'ok':
            base.cr.partyManager.sendChangePartyStatusRequest(
                self.hostedPartyInfo.partyId,
                PartyGlobals.PartyStatus.Cancelled)
            self.accept('changePartyStatusResponseReceived',
                        self.changePartyStatusResponseReceived)
        else:
            self.hostingCancelButton['state'] = DirectGuiGlobals.NORMAL

    def changePartyStatusResponseReceived(self, partyId, newPartyStatus,
                                          errorCode, beansRefunded):
        EventsPage.notify.debug(
            'changePartyStatusResponseReceived called with partyId = %d, newPartyStatus = %d, errorCode = %d'
            % (partyId, newPartyStatus, errorCode))
        if errorCode == PartyGlobals.ChangePartyFieldErrorCode.AllOk:
            if newPartyStatus == PartyGlobals.PartyStatus.Cancelled:
                self.loadHostedPartyInfo()
                self.cancelPartyResultGui[
                    'text'] = TTLocalizer.EventsPageCancelPartyResultOk % beansRefunded
                self.cancelPartyResultGui.show()
        elif errorCode == PartyGlobals.ChangePartyFieldErrorCode.AlreadyRefunded and newPartyStatus == PartyGlobals.PartyStatus.NeverStarted:
            self.loadHostedPartyInfo()
            self.cancelPartyResultGui[
                'text'] = TTLocalizer.EventsPageCancelPartyAlreadyRefunded
            self.cancelPartyResultGui.show()
        else:
            self.cancelPartyResultGui[
                'text'] = TTLocalizer.EventsPageCancelPartyResultError
            self.cancelPartyResultGui.show()
            self.hostingCancelButton['state'] = DirectGuiGlobals.NORMAL

    def cancelPartyResultGuiCommand(self):
        self.cancelPartyResultGui.hide()

    def updateToontownTime(self):
        self.toontownTimeGui.updateTime()
예제 #54
0
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 BackpackGUI(DirectFrame):
    notify = directNotify.newCategory('BackpackGUI')
    InLoadoutColor = Vec4(1, 0.6, 0.5, 1)
    DefaultColor = Vec4(0, 0.6, 1, 1)
    DisabledColor = Vec4(0.5, 0.5, 0.5, 1)

    def __init__(self):
        DirectFrame.__init__(self)
        self.trackByName = {}
        self.gagButtonByName = {}
        self.editButton = None
        self.fsm = ClassicFSM.ClassicFSM('BackpackGUI', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('idle', self.enterIdle, self.exitIdle),
            State.State('edit', self.enterEditGags, self.exitEditGags)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.editFSM = ClassicFSM.ClassicFSM('BPGUIEdit', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('add', self.enterAddGags, self.exitAddGags),
            State.State('remove', self.enterRemoveGags, self.exitRemoveGags)
        ], 'off', 'off')
        self.editFSM.enterInitialState()
        self.gm = GagManager.GagManager()

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def __addGagToLoadout(self, gagName):
        gagId = GagGlobals.gagIdByName[gagName]
        self.newLoadout.append(gagId)
        self.__updateButtons_add()

    def __removeGagFromLoadout(self, gagName):
        gagId = GagGlobals.gagIdByName[gagName]
        self.newLoadout.remove(gagId)
        self.__updateButtons_remove()

    def __updateButtons_add(self):
        for gagName, button in self.gagButtonByName.items():
            if self.isInLoadoutNew(gagName):
                button['state'] = DGG.DISABLED
                button['image_color'] = self.InLoadoutColor
            else:
                button['state'] = DGG.NORMAL
                button['command'] = self.__addGagToLoadout
                button['extraArgs'] = [gagName]
                button['image_color'] = self.DefaultColor

    def __updateButtons_remove(self):
        for gagName, button in self.gagButtonByName.items():
            if self.isInLoadoutNew(gagName):
                button['state'] = DGG.NORMAL
                button['command'] = self.__removeGagFromLoadout
                button['extraArgs'] = [gagName]
                button['image_color'] = self.InLoadoutColor
            else:
                button['state'] = DGG.DISABLED
                button['image_color'] = self.DisabledColor

    def enterAddGags(self):
        self.switchButton['text'] = 'Remove Gags'
        self.switchButton['command'] = self.editFSM.request
        self.switchButton['extraArgs'] = ['remove']
        self.__updateButtons_add()

    def exitAddGags(self):
        pass

    def enterRemoveGags(self):
        self.switchButton['text'] = 'Add Gags'
        self.switchButton['command'] = self.editFSM.request
        self.switchButton['extraArgs'] = ['add']
        self.__updateButtons_remove()

    def exitRemoveGags(self):
        pass

    def enterEditGags(self):
        self.initialLoadout = []
        for instance in base.localAvatar.backpack.loadout:
            self.initialLoadout.append(instance.getID())
        self.newLoadout = list(self.initialLoadout)
        self.editButton['text'] = 'Stop Editing'
        self.editButton['command'] = self.fsm.request
        self.editButton['extraArgs'] = ['idle']
        self.switchButton = DirectButton(relief=None,
                                         image=CIGlobals.getDefaultBtnGeom(),
                                         text='Add Gags',
                                         text_scale=0.045,
                                         text_pos=(0, -0.01),
                                         pos=(0.5, 0, -0.4))
        self.editFSM.request('add')

    def exitEditGags(self):
        self.switchButton.destroy()
        del self.switchButton
        if len(self.newLoadout) > 0:
            base.localAvatar.sendUpdate('requestSetLoadout', [self.newLoadout])
        del self.newLoadout
        del self.initialLoadout

    def isInLoadoutNew(self, gagName):
        gagId = GagGlobals.gagIdByName[gagName]
        return gagId in self.newLoadout

    def isInLoadoutLive(self, gagName):
        for instance in base.localAvatar.backpack.loadout:
            if instance.getName() == gagName:
                return True
        return False

    def enterIdle(self):
        self.editButton['text'] = 'Edit Loadout'
        self.editButton['command'] = self.fsm.request
        self.editButton['extraArgs'] = ['edit']
        for gagName, button in self.gagButtonByName.items():
            button['state'] = DGG.DISABLED
            if self.isInLoadoutLive(gagName):
                button['image_color'] = self.InLoadoutColor
            else:
                button['image_color'] = self.DefaultColor

    def exitIdle(self):
        pass

    def __makeTrack(self, trackName):
        gui = loader.loadModel('phase_3.5/models/gui/inventory_gui.bam')
        color = GagGlobals.TrackColorByName[trackName]
        track = gui.find('**/InventoryRow')
        track.setColor(*color)
        frame = DirectFrame(parent=self)
        frame.setZ(TrackZValueByName[trackName])
        frame['image'] = track
        trackTitle = OnscreenText(text=trackName,
                                  parent=frame,
                                  pos=(-0.63, -0.01, 0),
                                  scale=0.06)
        self.trackByName[trackName] = frame

    def __makeGagButton(self, gagName, trackName):
        gui = loader.loadModel('phase_3.5/models/gui/inventory_gui.bam')
        icons = loader.loadModel('phase_3.5/models/gui/inventory_icons.bam')
        icon = icons.find(GagGlobals.InventoryIconByName[gagName])
        index = GagGlobals.TrackGagNamesByTrackName[trackName].index(gagName)
        xValue = GagButtonXValues[index]
        gagId = GagGlobals.getIDByName(gagName)
        button = DirectButton(
            relief=None,
            image=(gui.find('**/InventoryButtonUp'),
                   gui.find('**/InventoryButtonDown'),
                   gui.find('**/InventoryButtonRollover'),
                   gui.find('**/InventoryButtonFlat')),
            geom=icon,
            geom_scale=0.6,
            parent=self.trackByName[trackName],
            text=str(base.localAvatar.getBackpack().getSupply(gagId)),
            text_align=TextNode.ARight,
            text_scale=0.04,
            text_fg=Vec4(1, 1, 1, 1),
            text_pos=(0.07, -0.04))
        button.setX(xValue)
        self.gagButtonByName[gagName] = button

    def createGUI(self):
        for i in xrange(len(GagGlobals.TrackNameById)):
            trackName = GagGlobals.TrackNameById[i]
            self.__makeTrack(trackName)
            for j in xrange(len(
                    GagGlobals.TrackGagNamesByTrackName[trackName])):
                gagName = GagGlobals.TrackGagNamesByTrackName[trackName][j]
                gagId = GagGlobals.gagIdByName[gagName]
                if base.localAvatar.getBackpack().hasGag(gagId):
                    self.__makeGagButton(gagName, trackName)
        self.editButton = DirectButton(relief=None,
                                       image=CIGlobals.getDefaultBtnGeom(),
                                       text='Edit Loadout',
                                       text_scale=0.045,
                                       text_pos=(0, -0.01),
                                       pos=(-0.5, 0, -0.4))
        self.fsm.request('idle')

    def deleteGUI(self):
        self.editFSM.requestFinalState()
        self.fsm.requestFinalState()
        for button in self.gagButtonByName.values():
            button.destroy()
        self.gagButtonByName = None
        for track in self.trackByName.values():
            track.destroy()
        self.trackByName = None
        self.editButton.destroy()
        self.editButton = None
        self.gm = None
        del self.editFSM
        del self.fsm
예제 #56
0
class DistributedHQNPCToon(DistributedNPCToon.DistributedNPCToon):
    notify = directNotify.newCategory("DistributedHQNPCToon")

    def __init__(self, cr):
        DistributedNPCToon.DistributedNPCToon.__init__(self, cr)
        self.questFrame = None
        self.questBtns = None
        self.questPosters = None
        self.cancelBtn = None
        self.timer = None

    def __getHQOfficerQuestAssignChat(self):
        objective = self.currentQuest.accessibleObjectives[0]

        chat = self.currentQuest.assignSpeech
        if chat is None:
            chat = ''
            if objective.type == Objectives.VisitNPC:
                chat += self.getNPCLocationSpeech()
            else:
                chat = base.localAvatar.questManager.getTaskInfo(
                    objective, True)
                chat += "\x07"
            chat += random.choice(NPCDialogue.QuestAssignGoodbyes)
        if chat.endswith("\x07"):
            if objective.type == Objectives.VisitNPC:
                chat += self.getNPCLocationSpeech()
            chat += random.choice(NPCDialogue.QuestAssignGoodbyes)

        return chat

    def __cancelQuestPicker(self, ranOutOfTime=True):
        self.removePickableQuests()
        if not ranOutOfTime:
            self.b_setChat(NPCDialogue.CancelQuestPicker)
        else:
            self._stopInteraction()
            self.sendUpdate('ranOutOfTime')

    def makePickableQuests(self, questList):
        self.doCameraNPCInteraction(True)

        quests = []

        for questId in questList:
            quest = Quest(questId, base.localAvatar.questManager)
            quest.setupCurrentObjectiveFromData(-1, 0, None)
            quests.append(quest)

        positions = [(0, 0, 0.65), (0, 0, 0.1), (0, 0, -0.45)]

        self.questFrame = DirectFrame(relief=None,
                                      pos=(-0.8, 0, 0),
                                      geom=DGG.getDefaultDialogGeom(),
                                      geom_color=Vec4(0.8, 0.6, 0.4, 1),
                                      geom_scale=(1.85, 1, 0.9),
                                      geom_hpr=(0, 0, -90))

        self.cancelBtn = DirectButton(text="Cancel",
                                      geom=CIGlobals.getDefaultBtnGeom(),
                                      geom_scale=(0.6, 0.75, 0.75),
                                      relief=None,
                                      parent=self.questFrame,
                                      pos=(0.2, 0, -0.8),
                                      text_scale=0.045,
                                      text_pos=(0, -0.015),
                                      scale=1.1,
                                      command=self.__cancelQuestPicker,
                                      extraArgs=[False])

        self.timer = Timer()
        self.timer.load()
        self.timer.setScale(0.3)
        self.timer.reparentTo(self.questFrame)
        self.timer.setPos(-0.1, 0, -0.8)
        self.timer.setInitialTime(20)
        self.timer.setZeroCommand(self.__cancelQuestPicker)
        self.timer.startTiming()

        self.questPosters = []
        self.questBtns = []

        for i in xrange(len(quests)):
            poster = None
            quest = quests[i]
            poster = QuestGlobals.generatePoster(quest, parent=aspect2d)
            poster.setScale(0.85)
            poster.setPos(0, 0, 0)
            poster.progressBar.hide()
            self.questPosters.append(poster)

            # Let's setup the choose button.
            btn = DirectButton(geom=CIGlobals.getDefaultBtnGeom(),
                               parent=poster,
                               pos=(0.35, 0, 0.215),
                               text='Choose',
                               text_scale=0.08,
                               text_pos=(0, -0.025),
                               relief=None,
                               command=self.d_pickedQuest,
                               extraArgs=[quests[i]])
            btn.setScale(0.4)
            btn.setBin('gui-popup', 60)
            btn.initialiseoptions(DirectButton)

            poster.reparentTo(self.questFrame.stateNodePath[0], 20)
            poster.setPos(positions[i])
            poster.show()

            self.questBtns.append(btn)

    def removePickableQuests(self):
        if self.timer:
            self.timer.unload()
            self.timer.cleanup()
            self.timer = None
        if self.questPosters:
            for poster in self.questPosters:
                poster.destroy()
            self.questPosters = None
        if self.questBtns:
            for btn in self.questBtns:
                btn.destroy()
            self.questBtns = None
        if self.questFrame:
            self.questFrame.destroy()
            self.questFrame = None
        if self.cancelBtn:
            self.cancelBtn.destroy()
            self.cancelBtn = None

    def d_pickedQuest(self, quest):
        self.removePickableQuests()
        self.sendUpdate('pickedQuest', [quest.id])
        self.currentQuest = quest
        self.currentQuestId = quest.id
        self.currentQuestObjective = 0
        self.currentChatIndex = 0
        self.b_setChat(self.__getHQOfficerQuestAssignChat())

        self.doCameraNPCInteraction()

    def disable(self):
        self.removePickableQuests()
        DistributedNPCToon.DistributedNPCToon.disable(self)
class Introduction(DirectObject, FSM):
    notify = directNotify.newCategory('Introduction')

    def __init__(self):
        DirectObject.__init__(self)
        FSM.__init__(self, self.__class__.__name__)

        self.label = OnscreenText(
            '', parent=hidden, font=ToontownGlobals.getMinnieFont(),
            fg=Vec4(1, 1, 1, 1), scale=0.06, align=TextNode.ACenter,
            wordwrap=35)
        self.label.setColorScale(Vec4(0, 0, 0, 0))

        gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_mainGui.bam')
        shuffleUp = gui.find('**/tt_t_gui_mat_shuffleUp')
        shuffleDown = gui.find('**/tt_t_gui_mat_shuffleDown')
        okUp = gui.find('**/tt_t_gui_mat_okUp')
        okDown = gui.find('**/tt_t_gui_mat_okDown')
        closeUp = gui.find('**/tt_t_gui_mat_closeUp')
        closeDown = gui.find('**/tt_t_gui_mat_closeDown')
        gui.removeNode()
        del gui

        self.exitButton = DirectButton(
            parent=hidden, relief=None,
            image=(shuffleUp, shuffleDown, shuffleUp),
            image_scale=(0.6, 0.6, 0.6), image1_scale=(0.63, 0.6, 0.6),
            image2_scale=(0.63, 0.6, 0.6),
            text=(TTLocalizer.IntroExitButton, TTLocalizer.IntroExitButton,
                  TTLocalizer.IntroExitButton, ''),
            text_font=ToontownGlobals.getInterfaceFont(),
            text_scale=TTLocalizer.SBshuffleBtn, text_pos=(0, -0.02),
            text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1))

        self.yesButton = DirectButton(
            parent=hidden, relief=None, image=(okUp, okDown, okUp, okDown),
            image_scale=(0.6, 0.6, 0.6), image1_scale=(0.7, 0.7, 0.7),
            image2_scale=(0.7, 0.7, 0.7),
            text=('', TTLocalizer.IntroYesButton, TTLocalizer.IntroYesButton),
            text_font=ToontownGlobals.getInterfaceFont(), text_scale=0.08,
            text_align=TextNode.ACenter, text_pos=(0, -0.175),
            text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1))
        self.noButton = DirectButton(
            parent=hidden, relief=None,
            image=(closeUp, closeDown, closeUp, closeDown),
            image_scale=(0.6, 0.6, 0.6), image1_scale=(0.7, 0.7, 0.7),
            image2_scale=(0.7, 0.7, 0.7),
            text=('', TTLocalizer.IntroNoButton, TTLocalizer.IntroNoButton),
            text_font=ToontownGlobals.getInterfaceFont(), text_scale=0.08,
            text_align=TextNode.ACenter, text_pos=(0, -0.175),
            text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1))

        self.disclaimerTrack = None
        self.presentsTrack = None

    def delete(self):
        if self.presentsTrack is not None:
            self.presentsTrack.finish()
            self.presentsTrack = None

        if self.disclaimerTrack is not None:
            self.disclaimerTrack.finish()
            self.disclaimerTrack = None

        if self.noButton is not None:
            self.noButton.destroy()
            self.noButton = None

        if self.yesButton is not None:
            self.yesButton.destroy()
            self.yesButton = None

        if self.exitButton is not None:
            self.exitButton.destroy()
            self.exitButton = None

        if self.label is not None:
            self.label.destroy()
            self.label = None

    def calcLabelY(self):
        sy = self.label.getScale()[1]
        height = self.label.textNode.getHeight()
        return (height * sy) / 2.0

    def enterOff(self):
        pass

    def enterDisclaimer(self):
        self.label.setText(TTLocalizer.IntroDisclaimer)
        self.label.setPos(0, self.calcLabelY())
        self.label.reparentTo(aspect2d)

        if self.disclaimerTrack is not None:
            self.disclaimerTrack.finish()
            self.disclaimerTrack = None

        self.disclaimerTrack = Sequence(
            LerpColorScaleInterval(
                self.label, 2, Vec4(1, 1, 1, 1), Vec4(0, 0, 0, 0),
                blendType='easeIn'),
            Wait(3),
            LerpColorScaleInterval(
                self.label, 2, Vec4(0, 0, 0, 0), Vec4(1, 1, 1, 1),
                blendType='easeOut'),
        )
        self.disclaimerTrack.start()

    def exitDisclaimer(self):
        if self.disclaimerTrack is not None:
            self.disclaimerTrack.finish()
            self.disclaimerTrack = None

        self.label.reparentTo(hidden)
        self.label.setPos(0, 0)
        self.label.setText('')

    def enterPresents(self):
        self.label.setText(TTLocalizer.IntroPresents)
        self.label.setPos(0, self.calcLabelY())
        self.label.reparentTo(aspect2d)

        if self.presentsTrack is not None:
            self.presentsTrack.finish()
            self.presentsTrack = None

        self.presentsTrack = Sequence(
            LerpColorScaleInterval(
                self.label, 2, Vec4(1, 1, 1, 1), Vec4(0, 0, 0, 0),
                blendType='easeIn'),
            Wait(3),
            LerpColorScaleInterval(
                self.label, 2, Vec4(0, 0, 0, 0), Vec4(1, 1, 1, 1),
                blendType='easeOut'),
        )
        self.presentsTrack.start()

    def exitPresents(self):
        if self.presentsTrack is not None:
            self.presentsTrack.finish()
            self.presentsTrack = None

        self.label.reparentTo(hidden)
        self.label.setPos(0, 0)
        self.label.setText('')

    def enterLabel(self, text):
        self.label.setText(text)
        self.label.setPos(0, self.calcLabelY())
        self.label.reparentTo(aspect2d)
        self.label.setColorScale(Vec4(1, 1, 1, 1))

    def exitLabel(self):
        self.label.setColorScale(Vec4(0, 0, 0, 0))
        self.label.reparentTo(hidden)
        self.label.setPos(0, 0)
        self.label.setText('')

    def enterExitDialog(self, text, exitButtonCommand=None,
                        exitButtonExtraArgs=[]):
        self.label.setText(text)

        sy = self.label.getScale()[1]
        bottom = self.label.textNode.getBottom() * sy
        lineHeight = self.label.textNode.getLineHeight() * sy
        self.exitButton.setPos(0, 0, bottom - (lineHeight * 2))
        self.exitButton['command'] = exitButtonCommand
        self.exitButton['extraArgs'] = exitButtonExtraArgs

        labelY = self.calcLabelY()

        self.label.setPos(0, labelY)

        self.exitButton.setZ(self.exitButton, labelY)

        self.exitButton.reparentTo(aspect2d)
        self.label.reparentTo(aspect2d)

        self.label.setColorScale(Vec4(1, 1, 1, 1))

    def exitExitDialog(self):
        self.label.setColorScale(Vec4(0, 0, 0, 0))

        self.label.reparentTo(hidden)
        self.exitButton.reparentTo(hidden)

        self.label.setPos(0, 0)
        self.label.setText('')

        self.exitButton['command'] = None
        self.exitButton['extraArgs'] = []
        self.exitButton.setPos(0, 0, 0)

    def enterYesNoDialog(self, text, yesButtonCommand=None,
                         yesButtonExtraArgs=[], noButtonCommand=None,
                         noButtonExtraArgs=[]):
        self.label.setText(text)

        sy = self.label.getScale()[1]
        bottom = self.label.textNode.getBottom() * sy
        lineHeight = self.label.textNode.getLineHeight() * sy
        self.yesButton.setPos(-0.1, 0, bottom - (lineHeight * 2))
        self.yesButton['command'] = yesButtonCommand
        self.yesButton['extraArgs'] = yesButtonExtraArgs
        self.noButton.setPos(0.1, 0, bottom - (lineHeight * 2))
        self.noButton['command'] = noButtonCommand
        self.noButton['extraArgs'] = noButtonExtraArgs

        labelY = self.calcLabelY()

        self.label.setPos(0, labelY)

        self.yesButton.setZ(self.yesButton, labelY)
        self.noButton.setZ(self.noButton, labelY)

        self.yesButton.reparentTo(aspect2d)
        self.noButton.reparentTo(aspect2d)
        self.label.reparentTo(aspect2d)

        self.label.setColorScale(Vec4(1, 1, 1, 1))

    def exitYesNoDialog(self):
        self.label.setColorScale(Vec4(0, 0, 0, 0))

        self.label.reparentTo(hidden)
        self.noButton.reparentTo(hidden)
        self.yesButton.reparentTo(hidden)

        self.label.setPos(0, 0)
        self.label.setText('')

        self.noButton['command'] = None
        self.noButton['extraArgs'] = []
        self.noButton.setPos(0, 0, 0)
        self.yesButton['command'] = None
        self.yesButton['extraArgs'] = []
        self.yesButton.setPos(0, 0, 0)

    def enterClickToStart(self):
        base.cr.clickToStart.start()

    def exitClickToStart(self):
        base.cr.clickToStart.stop()
예제 #58
0
class DistributedPartyTrampolineActivity(DistributedPartyActivity):
    notify = DirectNotifyGlobal.directNotify.newCategory('DistributedPartyTrampolineActivity')

    def __init__(self, cr, doJellyBeans = True, doTricks = False, texture = None):
        DistributedPartyTrampolineActivity.notify.debug('__init__')
        DistributedPartyActivity.__init__(self, cr, PartyGlobals.ActivityIds.PartyTrampoline, PartyGlobals.ActivityTypes.GuestInitiated, wantLever=False, wantRewardGui=True)
        self.doJellyBeans = doJellyBeans
        self.doTricks = doTricks
        self.texture = texture
        self.toon = None
        self.trampHeight = 3.6
        self.trampK = 400.0
        self.normalTrampB = 2.5
        self.leavingTrampB = 8.0
        self.trampB = self.normalTrampB
        self.g = -32.0
        self.jumpBoost = 330.0
        self.beginningBoost = 500.0
        self.beginningBoostThreshold = self.trampHeight + 1.5
        self.earlyJumpThreshold = 75.0
        self.boingThreshold = 300.0
        self.turnFactor = 120.0
        self.stepDT = 0.001
        self.targetCameraPos = Point3(0.0, 40.0, 10.0)
        self.cameraSpeed = 2.0
        self.hopOffPos = Point3(16.0, 0.0, 0.0)
        self.indicatorFactor = 0.0095
        self.dropShadowCutoff = 15.0
        self.minHeightForText = 15.0
        self.heightTextOffset = -0.065
        self.beanOffset = 0.5
        self.guiBeanOffset = -0.02
        self.jumpTextShown = False
        self.toonJumped = False
        self.turnLeft = False
        self.turnRight = False
        self.leavingTrampoline = False
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.lastPeak = 0.0
        self.beginRoundInterval = None
        self.hopOnAnim = None
        self.hopOffAnim = None
        self.flashTextInterval = None
        self.numJellyBeans = PartyGlobals.TrampolineNumJellyBeans
        self.jellyBeanBonus = PartyGlobals.TrampolineJellyBeanBonus
        self.jellyBeanStartHeight = 20.0
        self.jellyBeanStopHeight = 90.0
        self.jellyBeanColors = [VBase4(1.0, 0.5, 0.5, 1.0),
         VBase4(0.5, 1.0, 0.5, 1.0),
         VBase4(0.5, 1.0, 1.0, 1.0),
         VBase4(1.0, 1.0, 0.4, 1.0),
         VBase4(0.4, 0.4, 1.0, 1.0),
         VBase4(1.0, 0.5, 1.0, 1.0)]
        delta = (self.jellyBeanStopHeight - self.jellyBeanStartHeight) / (self.numJellyBeans - 1)
        self.jellyBeanPositions = [ self.jellyBeanStartHeight + n * delta for n in xrange(self.numJellyBeans) ]
        self.doSimulateStep = False
        return

    def load(self):
        DistributedPartyTrampolineActivity.notify.debug('load')
        DistributedPartyActivity.load(self)
        self.loadModels()
        self.loadCollision()
        self.loadGUI()
        self.loadSounds()
        self.loadIntervals()
        self.activityFSM = TrampolineActivityFSM(self)
        self.activityFSM.request('Idle')
        self.animFSM = TrampolineAnimFSM(self)
        self.setBestHeightInfo('', 0)

    def loadModels(self):
        self.tramp = self.root.attachNewNode(self.uniqueName('tramp'))
        self.trampActor = Actor('phase_13/models/parties/trampoline_model', {'emptyAnim': 'phase_13/models/parties/trampoline_anim'})
        self.trampActor.reparentTo(self.tramp)
        if self.texture:
            reskinNode = self.tramp.find('**/trampoline/__Actor_modelRoot/-GeomNode')
            reskinNode.setTexture(loader.loadTexture(self.texture), 100)
        self.surface = NodePath(self.uniqueName('trampSurface'))
        self.surface.reparentTo(self.tramp)
        self.surface.setZ(self.trampHeight)
        self.trampActor.controlJoint(self.surface, 'modelRoot', 'trampoline_joint1')
        self.sign.setPos(PartyGlobals.TrampolineSignOffset)
        self.beans = [ loader.loadModelCopy('phase_4/models/props/jellybean4') for i in xrange(self.numJellyBeans) ]
        for bean in self.beans:
            bean.find('**/jellybean').setP(-35.0)
            bean.setScale(3.0)
            bean.setTransparency(True)
            bean.reparentTo(self.tramp)
            bean.stash()

        self.beans[-1].setScale(8.0)

    def loadCollision(self):
        collTube = CollisionTube(0.0, 0.0, 0.0, 0.0, 0.0, 6.0, 5.4)
        collTube.setTangible(True)
        self.trampolineCollision = CollisionNode(self.uniqueName('TrampolineCollision'))
        self.trampolineCollision.addSolid(collTube)
        self.trampolineCollision.setCollideMask(OTPGlobals.CameraBitmask | OTPGlobals.WallBitmask)
        self.trampolineCollisionNP = self.tramp.attachNewNode(self.trampolineCollision)
        collSphere = CollisionSphere(0.0, 0.0, 0.0, 7.0)
        collSphere.setTangible(False)
        self.trampolineTrigger = CollisionNode(self.uniqueName('TrampolineTrigger'))
        self.trampolineTrigger.addSolid(collSphere)
        self.trampolineTrigger.setIntoCollideMask(OTPGlobals.WallBitmask)
        self.trampolineTriggerNP = self.tramp.attachNewNode(self.trampolineTrigger)
        self.accept('enter%s' % self.uniqueName('TrampolineTrigger'), self.onTrampolineTrigger)

    def loadGUI(self):
        self.gui = loader.loadModel('phase_13/models/parties/trampolineGUI')
        self.gui.reparentTo(base.a2dTopLeft)
        self.gui.setPos(0.115, 0, -1)
        self.gui.hide()
        self.toonIndicator = self.gui.find('**/trampolineGUI_MovingBar')
        jumpLineLocator = self.gui.find('**/jumpLine_locator')
        guiBean = self.gui.find('**/trampolineGUI_GreenJellyBean')
        self.gui.find('**/trampolineGUI_GreenJellyBean').stash()
        self.guiBeans = [ guiBean.instanceUnderNode(jumpLineLocator, self.uniqueName('guiBean%d' % i)) for i in xrange(self.numJellyBeans) ]
        self.guiBeans[-1].setScale(1.5)
        heightTextNode = TextNode(self.uniqueName('TrampolineActivity.heightTextNode'))
        heightTextNode.setFont(ToontownGlobals.getSignFont())
        heightTextNode.setAlign(TextNode.ALeft)
        heightTextNode.setText('0.0')
        heightTextNode.setShadow(0.05, 0.05)
        heightTextNode.setShadowColor(0.0, 0.0, 0.0, 1.0)
        heightTextNode.setTextColor(1.0, 1.0, 1.0, 1.0)
        self.heightText = jumpLineLocator.attachNewNode(heightTextNode)
        self.heightText.setX(0.15)
        self.heightText.setScale(0.1)
        self.heightText.setAlphaScale(0.0)
        self.quitEarlyButtonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui')
        quitEarlyUp = self.quitEarlyButtonModels.find('**//InventoryButtonUp')
        quitEarlyDown = self.quitEarlyButtonModels.find('**/InventoryButtonDown')
        quitEarlyRollover = self.quitEarlyButtonModels.find('**/InventoryButtonRollover')
        self.quitEarlyButton = DirectButton(parent=base.a2dTopRight, relief=None, text=TTLocalizer.PartyTrampolineQuitEarlyButton, text_fg=(1, 1, 0.65, 1), text_pos=(0, -0.23), text_scale=0.7, image=(quitEarlyUp, quitEarlyDown, quitEarlyRollover), image_color=(1, 0, 0, 1), image_scale=(20, 1, 11), pos=(-0.183, 0, -0.4), scale=0.09, command=self.leaveTrampoline)
        self.quitEarlyButton.stash()
        self.flashText = OnscreenText(text='', pos=(0.0, -0.45), scale=0.2, fg=(1.0, 1.0, 0.65, 1.0), align=TextNode.ACenter, font=ToontownGlobals.getSignFont(), mayChange=True)
        self.timer = PartyUtils.getNewToontownTimer()
        self.timer.posInTopRightCorner()
        return

    def loadSounds(self):
        self.jellyBeanSound = base.loader.loadSfx('phase_4/audio/sfx/sparkly.ogg')
        self.boingSound = base.loader.loadSfx('phase_4/audio/sfx/target_trampoline_2.ogg')
        self.whistleSound = base.loader.loadSfx('phase_4/audio/sfx/AA_sound_whistle.ogg')

    def loadIntervals(self):

        def prepareHeightText():
            self.heightText.node().setText(TTLocalizer.PartyTrampolineGetHeight % int(self.toon.getZ()))
            self.heightText.setZ(self.indicatorFactor * self.toon.getZ() + self.heightTextOffset)

        self.heightTextInterval = Sequence(Func(prepareHeightText), LerpFunc(self.heightText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0))

    def unload(self):
        DistributedPartyTrampolineActivity.notify.debug('unload')
        if self.hopOnAnim and self.hopOnAnim.isPlaying():
            self.hopOnAnim.finish()
        if self.hopOffAnim and self.hopOffAnim.isPlaying():
            self.hopOffAnim.finish()
        if self.beginRoundInterval and self.beginRoundInterval.isPlaying():
            self.beginRoundInterval.finish()
        if self.flashTextInterval and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        if self.heightTextInterval and self.heightTextInterval.isPlaying():
            self.heightTextInterval.finish()
        self.timer.stop()
        DistributedPartyActivity.unload(self)
        taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask'))
        taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask'))
        self.ignoreAll()
        del self.heightTextInterval
        del self.beginRoundInterval
        del self.hopOnAnim
        del self.hopOffAnim
        del self.flashTextInterval
        if hasattr(self, 'beanAnims'):
            self.cleanupJellyBeans()
        self.quitEarlyButton.destroy()
        del self.quitEarlyButton
        del self.gui
        del self.activityFSM
        del self.animFSM
        return

    def setBestHeightInfo(self, toonName, height):
        self.bestHeightInfo = (toonName, height)
        DistributedPartyTrampolineActivity.notify.debug('%s has the best height of %d' % (toonName, height))
        if height > 0:
            self.setSignNote(TTLocalizer.PartyTrampolineBestHeight % self.bestHeightInfo)
        else:
            self.setSignNote(TTLocalizer.PartyTrampolineNoHeightYet)

    def leaveTrampoline(self):
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self._showFlashMessage(TTLocalizer.PartyTrampolineTimesUp)
            self.leavingTrampoline = True
            self.timer.reset()
            self.trampB = self.leavingTrampB
            self.ignore('control')
            self.quitEarlyButton.stash()
            self.gui.hide()
        return

    def requestAnim(self, request):
        self.animFSM.request(request)

    def b_requestAnim(self, request):
        self.requestAnim(request)
        self.sendUpdate('requestAnim', [request])

    def requestAnimEcho(self, request):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.requestAnim(request)
        return

    def removeBeans(self, beansToRemove):
        for i in beansToRemove:
            height, bean, guiBean, beanAnim = self.beanDetails[i]
            guiBean.stash()
            if i in self.beansToCollect:
                self.beansToCollect.remove(i)
            else:
                self.notify.warning('removeBeans avoided a crash, %d not in self.beansToCollect' % i)
            self.poofBean(bean, beanAnim)

    def b_removeBeans(self, beansToRemove):
        self.removeBeans(beansToRemove)
        self.sendUpdate('removeBeans', [beansToRemove])

    def removeBeansEcho(self, beansToRemove):
        if self.toon != None and self.toon.doId != base.localAvatar.doId:
            self.removeBeans(beansToRemove)
        return

    def joinRequestDenied(self, reason):
        DistributedPartyActivity.joinRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultJoinDeny)
        base.cr.playGame.getPlace().fsm.request('walk')

    def exitRequestDenied(self, reason):
        DistributedPartyActivity.exitRequestDenied(self, reason)
        self.showMessage(TTLocalizer.PartyActivityDefaultExitDeny)

    def setState(self, newState, timestamp):
        DistributedPartyTrampolineActivity.notify.debug('setState( newState=%s, ... )' % newState)
        DistributedPartyActivity.setState(self, newState, timestamp)
        self.activityFSM.request(newState)

    def startIdle(self):
        DistributedPartyTrampolineActivity.notify.debug('startIdle')

    def finishIdle(self):
        DistributedPartyTrampolineActivity.notify.debug('finishIdle')

    def startRules(self):
        DistributedPartyTrampolineActivity.notify.debug('startRules')
        if self.doJellyBeans:
            self.setupJellyBeans()
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            self.acquireToon()
        return

    def startActive(self):
        DistributedPartyTrampolineActivity.notify.debug('startActive')
        if self.toon != None and self.toon.doId == base.localAvatar.doId:
            base.setCellsActive(base.bottomCells, True)
            self.accept('arrow_left', self.onLeft)
            self.accept('arrow_left-up', self.onLeftUp)
            self.accept('arrow_right', self.onRight)
            self.accept('arrow_right-up', self.onRightUp)
            self.beginRoundInterval = Sequence(Func(self._showFlashMessage, TTLocalizer.PartyTrampolineReady), Wait(1.2), Func(self.flashMessage, TTLocalizer.PartyTrampolineGo), Func(self.beginRound))
            self.beginRoundInterval.start()
        return

    def finishActive(self):
        DistributedPartyTrampolineActivity.notify.debug('finishActive')
        if self.doJellyBeans:
            self.cleanupJellyBeans()

    def setupJellyBeans(self):
        self.beanAnims = []
        self.beansToCollect = []
        self.beanDetails = []
        self.numBeansCollected = 0
        for i in xrange(self.numJellyBeans):
            bean = self.beans[i]
            guiBean = self.guiBeans[i]
            height = self.jellyBeanPositions[i]
            color = random.choice(self.jellyBeanColors)
            bean.find('**/jellybean').setColor(color)
            if self.toon.doId == base.localAvatar.doId:
                bean.setAlphaScale(1.0)
            else:
                bean.setAlphaScale(0.5)
            guiBean.setColor(color)
            bean.setZ(height + self.toon.getHeight() + self.beanOffset)
            guiBean.setZ(height * self.indicatorFactor + self.guiBeanOffset)
            bean.setH(0.0)
            bean.unstash()
            guiBean.unstash()
            beanAnim = bean.hprInterval(1.5, VBase3((i % 2 * 2 - 1) * 360.0, 0.0, 0.0))
            beanAnim.loop()
            self.beanAnims.append(beanAnim)
            self.beanDetails.append((height,
             bean,
             guiBean,
             beanAnim))

        self.beansToCollect = range(self.numJellyBeans)

    def cleanupJellyBeans(self):
        for bean in self.beans:
            bean.stash()

        for guiBean in self.guiBeans:
            guiBean.stash()

        if hasattr(self, 'beanAnims'):
            for beanAnim in self.beanAnims:
                beanAnim.finish()

            del self.beanAnims
            del self.beansToCollect

    def beginRound(self):
        base.playSfx(self.whistleSound)
        self.timer.setTime(PartyGlobals.TrampolineDuration)
        self.timer.countdown(PartyGlobals.TrampolineDuration)
        self.timer.show()
        self.gui.show()
        self.quitEarlyButton.unstash()
        self.notify.debug('Accepting contorl')
        self.accept('control', self.onJump)
        self.notify.debug('setting simulate step to true')
        self.doSimulateStep = True

    def acquireToon(self):
        self.toon.disableSmartCameraViews()
        self.toon.stopUpdateSmartCamera()
        camera.wrtReparentTo(render)
        self.toon.dropShadow.reparentTo(hidden)
        self.toon.startPosHprBroadcast(period=0.2)
        self.toonAcceleration = 0.0
        self.toonVelocity = 0.0
        self.topHeight = 0.0
        self.trampB = self.normalTrampB
        self.leavingTrampoline = False
        self.hopOnAnim = Sequence(Func(self.toon.b_setAnimState, 'jump', 1.0), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, Point3(0.0, 0.0, self.trampHeight), 5.0, self.tramp), Func(self.postHopOn))
        self.hopOnAnim.start()

    def postHopOn(self):
        self.toon.setH(self.toon.getH() + 90.0)
        self.toon.dropShadow.reparentTo(self.surface)
        self.timeLeftToSimulate = 0.0
        self.doSimulateStep = False
        taskMgr.add(self.updateTask, self.uniqueName('TrampolineActivity.updateTask'))
        base.setCellsActive(base.leftCells, False)
        base.setCellsActive(base.bottomCells, False)
        DistributedPartyActivity.startRules(self)

    def releaseToon(self):
        self._hideFlashMessage()
        self.ignore('arrow_left')
        self.ignore('arrow_left-up')
        self.ignore('arrow_right')
        self.ignore('arrow_right-up')
        taskMgr.remove(self.uniqueName('TrampolineActivity.updateTask'))
        self.hopOffAnim = Sequence(self.toon.hprInterval(0.5, VBase3(-90.0, 0.0, 0.0), other=self.tramp), Func(self.toon.b_setAnimState, 'jump', 1.0), Func(self.toon.dropShadow.reparentTo, hidden), Wait(0.4), PartyUtils.arcPosInterval(0.75, self.toon, self.hopOffPos, 5.0, self.tramp), Func(self.postHopOff))
        self.hopOffAnim.start()

    def postHopOff(self):
        base.setCellsActive(base.leftCells, True)
        self.timer.stop()
        self.timer.hide()
        self.toon.dropShadow.reparentTo(self.toon.getShadowJoint())
        self.toon.dropShadow.setAlphaScale(1.0)
        self.toon.dropShadow.setScale(1.0)
        self.b_requestAnim('Off')
        camera.reparentTo(base.localAvatar)
        base.localAvatar.startUpdateSmartCamera()
        base.localAvatar.enableSmartCameraViews()
        base.localAvatar.setCameraPositionByIndex(base.localAvatar.cameraIndex)
        place = base.cr.playGame.getPlace()
        if self.doJellyBeans:
            self.sendUpdate('awardBeans', [self.numBeansCollected, int(self.topHeight)])
            if int(self.topHeight) > self.bestHeightInfo[1]:
                self.sendUpdate('reportHeightInformation', [int(self.topHeight)])
        self.d_toonExitDemand()

    def onTrampolineTrigger(self, collEntry):
        if self.activityFSM.state == 'Idle' and self.toon == None and base.cr.playGame.getPlace().fsm.getCurrentState().getName() == 'walk':
            base.cr.playGame.getPlace().fsm.request('activity')
            self.d_toonJoinRequest()
        else:
            self.flashMessage(TTLocalizer.PartyTrampolineActivityOccupied, duration=2.0)
        return

    def onJump(self):
        self.notify.debug('got onJump')
        if self.toon != None and self.toon.getZ() < self.trampHeight:
            self.toonJumped = True
            self.b_requestAnim('Jump')
        else:
            self.notify.debug('z is less than tramp height')
        return

    def onLeft(self):
        self.turnLeft = True

    def onLeftUp(self):
        self.turnLeft = False

    def onRight(self):
        self.turnRight = True

    def onRightUp(self):
        self.turnRight = False

    def handleToonJoined(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonJoined')
        self.toon = self.getAvatar(toonId)
        if self.toon != None and not self.toon.isEmpty():
            self.oldJumpSquatPlayRate = self.toon.getPlayRate('jump-squat')
            self.oldJumpLandPlayRate = self.toon.getPlayRate('jump-land')
            self.toon.setPlayRate(2.5, 'jump-squat')
            self.toon.setPlayRate(2.0, 'jump-land')
            self.turnLeft = False
            self.turnRight = False
            self.activityFSM.request('Rules')
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.add(self.remoteUpdateTask, self.uniqueName('TrampolineActivity.remoteUpdateTask'))
        else:
            self.notify.warning('handleToonJoined could not get toon %d' % toonId)
        return

    def handleToonExited(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonExited')
        if self.toon != None:
            if self.toon.doId != base.localAvatar.doId:
                taskMgr.remove(self.uniqueName('TrampolineActivity.remoteUpdateTask'))
            self.surface.setZ(self.trampHeight)
            self.toon.setPlayRate(self.oldJumpSquatPlayRate, 'jump-squat')
            self.toon.setPlayRate(self.oldJumpLandPlayRate, 'jump-land')
            self.toon = None
        return

    def handleToonDisabled(self, toonId):
        DistributedPartyTrampolineActivity.notify.debug('handleToonDisabled')
        DistributedPartyTrampolineActivity.notify.debug('avatar ' + str(toonId) + ' disabled')
        if base.localAvatar.doId == toonId:
            self.releaseToon()

    def handleRulesDone(self):
        self.sendUpdate('toonReady')
        self.finishRules()

    def getTitle(self):
        if self.doJellyBeans:
            return TTLocalizer.PartyTrampolineJellyBeanTitle
        elif self.doTricks:
            return TTLocalizer.PartyTrampolineTricksTitle
        else:
            return DistributedPartyActivity.getTitle(self)

    def getInstructions(self):
        return TTLocalizer.PartyTrampolineActivityInstructions

    def updateTask(self, task):
        z = self.toon.getZ()
        dt = globalClock.getDt()
        if self.doSimulateStep:
            self.timeLeftToSimulate += dt
            while self.timeLeftToSimulate >= self.stepDT:
                z, a = self.simulateStep(z)
                self.timeLeftToSimulate -= self.stepDT

        self.toon.setZ(z)
        if z <= self.trampHeight:
            self.surface.setZ(z)
        else:
            self.surface.setZ(self.trampHeight)
        self.toonIndicator.setZ((z - self.trampHeight) * self.indicatorFactor)
        if self.turnLeft:
            self.toon.setH(self.toon.getH() + self.turnFactor * dt)
        if self.turnRight:
            self.toon.setH(self.toon.getH() - self.turnFactor * dt)
        currentPos = base.camera.getPos(self.toon)
        vec = self.targetCameraPos - currentPos
        newPos = currentPos + vec * (dt * self.cameraSpeed)
        base.camera.setPos(self.toon, newPos)
        base.camera.lookAt(self.toon)
        #if z > self.trampHeight:
        #    heightFactor = 1.0 - min(1.0, (z - self.trampHeight) / self.dropShadowCutoff)
        #    self.toon.dropShadow.setAlphaScale(heightFactor)
        #    self.toon.dropShadow.setScale(max(0.1, heightFactor))
        #else:
        #    self.toon.dropShadow.setAlphaScale(1.0)
        #    self.toon.dropShadow.setScale(1.0)
        if self.leavingTrampoline and z < self.trampHeight and abs(a) < 0.1:
            self.releaseToon()
        return Task.cont

    def simulateStep(self, z):
        if z >= self.trampHeight:
            a = self.g
            self.toonJumped = False
        else:
            a = self.g + self.trampK * (self.trampHeight - z) - self.trampB * self.toonVelocity
            if self.toonJumped:
                if self.lastPeak > self.earlyJumpThreshold or self.toonVelocity >= -300000.0:
                    a += self.jumpBoost
                    if self.lastPeak < self.beginningBoostThreshold:
                        a += self.beginningBoost
        lastVelocity = self.toonVelocity
        self.toonVelocity += a * self.stepDT
        if lastVelocity > 0.0 and self.toonVelocity <= 0.0:
            topOfJump = True
            bottomOfJump = False
        elif lastVelocity < 0.0 and self.toonVelocity >= 0.0:
            topOfJump = False
            bottomOfJump = True
        else:
            topOfJump = False
            bottomOfJump = False
        newZ = z + self.toonVelocity * self.stepDT
        if newZ > self.topHeight:
            self.topHeight = newZ
            if self.doJellyBeans:
                self.collectJellyBeans(newZ)
        if topOfJump:
            self.lastPeak = newZ
            if newZ >= self.minHeightForText:
                self.heightTextInterval.start()
        if topOfJump:
            if newZ > self.trampHeight + 20.0:
                self.b_requestAnim('Falling')
            elif self.animFSM.state == 'Jump':
                self.b_requestAnim('Falling')
        if newZ <= self.trampHeight and z > self.trampHeight:
            if self.animFSM.state == 'Falling':
                self.b_requestAnim('Land')
            elif self.animFSM.state != 'Neutral':
                self.b_requestAnim('Neutral')
        if bottomOfJump and a > self.boingThreshold:
            base.playSfx(self.boingSound)
        return (newZ, a)

    def collectJellyBeans(self, z):
        beansToRemove = []
        for i in self.beansToCollect:
            height = self.beanDetails[i][0]
            if height <= z:
                beansToRemove.append(i)

        if len(beansToRemove) > 0:
            base.playSfx(self.jellyBeanSound)
            self.numBeansCollected += len(beansToRemove)
            self.b_removeBeans(beansToRemove)

    def remoteUpdateTask(self, task):
        if self.toon != None and not self.toon.isEmpty():
            z = self.toon.getZ()
            if z <= self.trampHeight:
                self.surface.setZ(z)
            else:
                self.surface.setZ(self.trampHeight)
        return Task.cont

    def poofBean(self, bean, beanAnim):
        if bean == None:
            self.notify.warning('poofBean, returning immediately as bean is None')
            return
        if bean.isEmpty():
            self.notify.warning('poofBean, returning immediately as bean is empty')
            return
        currentAlpha = bean.getColorScale()[3]
        currentScale = bean.getScale()
        poofAnim = Sequence(Parallel(LerpFunc(bean.setAlphaScale, fromData=currentAlpha, toData=0.0, duration=0.25), LerpFunc(bean.setScale, fromData=currentScale, toData=currentScale * 5.0, duration=0.25)), Func(bean.stash), Func(beanAnim.finish), Func(bean.setAlphaScale, currentAlpha), Func(bean.setScale, currentScale))
        poofAnim.start()
        return

    def _showFlashMessage(self, message):
        if self.isDisabled():
            return
        if self.flashTextInterval is not None and self.flashTextInterval.isPlaying():
            self.flashTextInterval.finish()
        self.flashText.setText(message)
        self.flashText.setAlphaScale(1.0)
        self.flashText.unstash()
        return

    def _hideFlashMessage(self, duration = 0.0):
        if self.isDisabled():
            pass
        self.flashTextInterval = Sequence(Wait(duration), LerpFunc(self.flashText.setAlphaScale, fromData=1.0, toData=0.0, duration=1.0), Func(self.flashText.stash))
        self.flashTextInterval.start()

    def flashMessage(self, message, duration = 0.5):
        self._showFlashMessage(message)
        self._hideFlashMessage(duration)
예제 #59
0
class DistributedElevator(DistributedObject):
    notify = directNotify.newCategory('DistributedElevator')

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg')
        self.closeSfx = base.loadSfx(
            'phase_5/audio/sfx/elevator_door_close.ogg')
        self.elevatorPoints = ElevatorPoints
        self.type = ELEVATOR_NORMAL
        self.countdownTime = ElevatorData[self.type]['countdown']
        self.localAvOnElevator = False
        self.thebldg = None
        self.bldgDoId = None
        self.toZoneId = None
        self.elevatorModel = None
        self.countdownTextNP = None
        self.toonsInElevator = []
        self.hopOffButton = None
        self.fsm = ClassicFSM.ClassicFSM('DistributedElevator', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('opening', self.enterOpening, self.exitOpening),
            State.State('waitEmpty', self.enterWaitEmpty, self.exitWaitEmpty),
            State.State('waitCountdown', self.enterWaitCountdown,
                        self.exitWaitCountdown),
            State.State('closing', self.enterClosing, self.exitClosing),
            State.State('closed', self.enterClosed, self.exitClosed)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        return

    def setElevatorType(self, etype):
        self.type = etype

    def getElevatorType(self):
        return self.type

    def setBldgDoId(self, doId):
        self.bldgDoId = doId

    def getBldgDoId(self):
        return self.bldgDoId

    def setToZoneId(self, zoneId):
        self.toZoneId = zoneId

    def getToZoneId(self):
        return self.toZoneId

    def enterOpening(self, ts=0):
        self.openDoors.start(ts)

    def exitOpening(self):
        self.openDoors.finish()

    def enterClosing(self, ts=0):
        if self.localAvOnElevator:
            self.hideHopOffButton()
        self.closeDoors.start(ts)

    def exitClosing(self):
        self.closeDoors.finish()

    def enterClosed(self, ts=0):
        closeDoors(self.getLeftDoor(), self.getRightDoor())

    def exitClosed(self):
        pass

    def __handleElevatorTrigger(self, entry):
        if not self.localAvOnElevator:
            self.cr.playGame.getPlace().fsm.request('stop')
            self.sendUpdate('requestEnter')

    def enterWaitEmpty(self, ts=0):
        if not self.localAvOnElevator:
            self.acceptOnce('enter' + self.uniqueName('elevatorSphere'),
                            self.__handleElevatorTrigger)
        openDoors(self.getLeftDoor(), self.getRightDoor())

    def exitWaitEmpty(self):
        self.ignore('enter' + self.uniqueName('elevatorSphere'))

    def enterWaitCountdown(self, ts=0):
        if not self.localAvOnElevator:
            self.acceptOnce('enter' + self.uniqueName('elevatorSphere'),
                            self.__handleElevatorTrigger)
        openDoors(self.getLeftDoor(), self.getRightDoor())
        if self.countdownTextNP:
            self.countdownTextNP.show()
            self.countdownTrack = Sequence()
            time = int(ElevatorData[self.type]['countdown'])
            for i in range(time):
                self.countdownTrack.append(
                    Func(self.countdownTextNP.node().setText, str(time - i)))
                self.countdownTrack.append(Wait(1.0))

            self.countdownTrack.start(ts)

    def exitWaitCountdown(self):
        if self.countdownTextNP:
            self.countdownTextNP.hide()
        self.countdownTrack.finish()
        del self.countdownTrack

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def getLeftDoor(self):
        return self.thebldg.leftDoor

    def getRightDoor(self):
        return self.thebldg.rightDoor

    def startPoll(self):
        taskMgr.add(self.__pollBuilding, self.uniqueName('pollBuilding'))

    def __pollBuilding(self, task):
        self.getTheBldg()
        if self.thebldg:
            self.postAnnounceGenerate()
            return task.done
        return task.cont

    def stopPoll(self):
        taskMgr.remove(self.uniqueName('pollBuilding'))

    def announceGenerate(self):
        DistributedObject.announceGenerate(self)
        self.getTheBldg()
        if not self.thebldg:
            self.startPoll()
            return
        self.postAnnounceGenerate()

    def postAnnounceGenerate(self):
        self.leftDoor = self.getLeftDoor()
        self.rightDoor = self.getRightDoor()
        self.setupElevator()
        self.setupCountdownText()
        self.sendUpdate('requestStateAndTimestamp')

    def setState(self, state, timestamp):
        if not self.thebldg:
            return
        self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])

    def stateAndTimestamp(self, state, timestamp):
        self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])

    def setupCountdownText(self):
        tn = TextNode('countdownText')
        tn.setFont(CIGlobals.getMickeyFont())
        tn.setTextColor(VBase4(0.5, 0.5, 0.5, 1.0))
        tn.setAlign(TextNode.ACenter)
        self.countdownTextNP = self.getElevatorModel().attachNewNode(tn)
        self.countdownTextNP.setScale(2)
        self.countdownTextNP.setPos(0, 1, 7)

    def setupElevator(self):
        collisionRadius = ElevatorData[self.type]['collRadius']
        self.elevatorSphere = CollisionSphere(0, 5, 0, collisionRadius)
        self.elevatorSphere.setTangible(0)
        self.elevatorSphereNode = CollisionNode(
            self.uniqueName('elevatorSphere'))
        self.elevatorSphereNode.setIntoCollideMask(CIGlobals.WallBitmask)
        self.elevatorSphereNode.addSolid(self.elevatorSphere)
        self.elevatorSphereNodePath = self.getElevatorModel().attachNewNode(
            self.elevatorSphereNode)
        self.elevatorSphereNodePath.reparentTo(self.getElevatorModel())
        self.openDoors = getOpenInterval(self, self.getLeftDoor(),
                                         self.getRightDoor(), self.openSfx,
                                         None, self.type)
        self.closeDoors = getCloseInterval(self, self.getLeftDoor(),
                                           self.getRightDoor(), self.closeSfx,
                                           None, self.type)
        self.closeDoors = Sequence(self.closeDoors,
                                   Func(self.onDoorCloseFinish))
        return

    def disable(self):
        self.stopPoll()
        if hasattr(self, 'openDoors'):
            self.openDoors.pause()
        if hasattr(self, 'closeDoors'):
            self.closeDoors.pause()
        self.ignore('enter' + self.uniqueName('elevatorSphere'))
        self.elevatorSphereNodePath.removeNode()
        del self.elevatorSphereNodePath
        del self.elevatorSphereNode
        del self.elevatorSphere
        self.fsm.request('off')
        self.openSfx = None
        self.closeSfx = None
        self.elevatorPoints = None
        self.type = None
        self.countdownTime = None
        self.localAvOnElevator = None
        self.thebldg = None
        self.bldgDoId = None
        self.toZoneId = None
        self.elevatorModel = None
        self.toonsInElevator = None
        self.hopOffButton = None
        self.leftDoor = None
        self.rightDoor = None
        self.openDoors = None
        self.closeDoors = None
        if self.countdownTextNP:
            self.countdownTextNP.removeNode()
            self.countdownTextNP = None
        DistributedObject.disable(self)
        return

    def onDoorCloseFinish(self):
        if self.localAvOnElevator:
            base.transitions.fadeScreen(1.0)
            base.localAvatar.wrtReparentTo(render)
            loader = 'suitInterior'
            where = 'suitInterior'
            how = 'IDK'
            world = base.cr.playGame.getCurrentWorldName()
            if self.thebldg.fsm.getCurrentState().getName() == 'bldgComplete':
                loader = 'townLoader'
                where = 'street'
                how = 'elevatorIn'
                world = CIGlobals.CogTropolis
            requestStatus = {
                'zoneId': self.getToZoneId(),
                'hoodId': self.cr.playGame.hood.hoodId,
                'where': where,
                'avId': base.localAvatar.doId,
                'loader': loader,
                'shardId': None,
                'wantLaffMeter': 1,
                'world': world,
                'how': how
            }
            self.cr.playGame.getPlace().doneStatus = requestStatus
            messenger.send(self.cr.playGame.getPlace().doneEvent)
        return

    def doMusic(self):
        self.elevMusic = base.loadMusic('phase_7/audio/bgm/tt_elevator.mid')
        base.playMusic(self.elevMusic, looping=1, volume=0.8)

    def fillSlot(self, index, avId):
        toon = self.cr.doId2do.get(avId)
        if toon:
            point = ElevatorPoints[index]
            toon.stopSmooth()
            toon.wrtReparentTo(self.getElevatorModel())
            toon.headsUp(point)
            track = Sequence()
            track.append(Func(toon.animFSM.request, 'run'))
            track.append(
                LerpPosInterval(toon,
                                duration=0.5,
                                pos=point,
                                startPos=toon.getPos(self.getElevatorModel())))
            track.append(
                LerpHprInterval(toon,
                                duration=0.1,
                                hpr=(180, 0, 0),
                                startHpr=toon.getHpr(self.getElevatorModel())))
            track.append(Func(toon.animFSM.request, 'neutral'))
            if avId == base.localAvatar.doId:
                self.localAvOnElevator = True
                track.append(Func(self.showHopOffButton))
                base.localAvatar.stopSmartCamera()
                base.localAvatar.walkControls.setCollisionsActive(0)
                base.camera.wrtReparentTo(self.getElevatorModel())
                cameraBoardTrack = LerpPosHprInterval(camera, 1.5,
                                                      Point3(0, -16, 5.5),
                                                      Point3(0, 0, 0))
                cameraBoardTrack.start()
            track.start()

    def emptySlot(self, index, avId):
        toon = self.cr.doId2do.get(avId)
        if toon:
            OutPoint = ElevatorOutPoints[index]
            InPoint = ElevatorPoints[index]
            toon.stopSmooth()
            toon.headsUp(OutPoint)
            track = Sequence(
                Func(toon.animFSM.request, 'run'),
                LerpPosInterval(toon,
                                duration=0.5,
                                pos=OutPoint,
                                startPos=InPoint),
                Func(toon.animFSM.request, 'neutral'), Func(toon.startSmooth))
            if avId == base.localAvatar.doId:
                self.localAvOnElevator = False
                track.append(Func(self.freedom))
            track.start()

    def freedom(self):
        if self.fsm.getCurrentState().getName() in ('waitEmpty',
                                                    'waitCountdown'):
            self.acceptOnce('enter' + self.uniqueName('elevatorSphere'),
                            self.__handleElevatorTrigger)
        base.localAvatar.walkControls.setCollisionsActive(1)
        self.cr.playGame.getPlace().fsm.request('walk')

    def setToonsInElevator(self, toonsInElevator):
        for i in xrange(len(toonsInElevator)):
            avId = toonsInElevator[i]
            toon = self.cr.doId2do.get(avId)
            if toon:
                toon.reparentTo(self.getElevatorModel())
                toon.stopSmooth()
                point = ElevatorPoints[i]
                toon.setPos(point)
                toon.setHpr(180, 0, 0)
                toon.animFSM.request('neutral')

    def getTheBldg(self):
        self.thebldg = self.cr.doId2do.get(self.bldgDoId)

    def getElevatorModel(self):
        return self.thebldg.getElevatorModel()

    def enterRejected(self):
        self.cr.playGame.getPlace().fsm.request('walk')

    def showHopOffButton(self):
        gui = loader.loadModel('phase_3.5/models/gui/inventory_gui.bam')
        upButton = gui.find('**/InventoryButtonUp')
        downButton = gui.find('**/InventoryButtonDown')
        rlvrButton = gui.find('**/InventoryButtonRollover')
        self.hopOffBtn = DirectButton(relief=None,
                                      text='Hop off',
                                      text_fg=(0.9, 0.9, 0.9, 1),
                                      text_pos=(0, -0.23),
                                      text_scale=0.75,
                                      image=(upButton, downButton, rlvrButton),
                                      image_color=(0.5, 0.5, 0.5, 1),
                                      image_scale=(20, 1, 11),
                                      pos=(0, 0, 0.8),
                                      scale=0.15,
                                      command=self.handleHopOffButton)
        return

    def hideHopOffButton(self):
        if hasattr(self, 'hopOffBtn'):
            self.hopOffBtn.destroy()
            del self.hopOffBtn

    def handleHopOffButton(self):
        self.hideHopOffButton()
        self.sendUpdate('requestExit')