def on_copy(result: bool) -> None:
     if not result:
         screenmessage(Language.SUCCESS)
         with ba.Context('ui'):
             watch_window._my_replay_selected = None
             watch_window._refresh_my_replays()
     elif result == 1:
         screenmessage(Language.UNSUCCESS)
示例#2
0
 def handle_result(result: Optional[Dict[str, Any]]) -> None:
     with ba.Context('ui'):
         if result is None:
             ba.screenmessage(ba.Lstr(resource='errorText'),
                              color=(1, 0, 0))
             ba.playsound(ba.getsound('error'))
         else:
             ShowFriendCodeWindow(result)
示例#3
0
    def _start_preloads(self) -> None:
        # FIXME: The func that calls us back doesn't save/restore state
        #  or check for a dead activity so we have to do that ourself.
        if self.expired:
            return
        with ba.Context(self):
            _preload1()

        ba.timer(0.5, lambda: ba.setmusic(ba.MusicType.MENU))
示例#4
0
 def _import_replay_press(self) -> None:
     from bastd.ui.fileselector import FileSelectorWindow
     user_dir = _ba.app.python_directory_user
     import_dir = (user_dir + '/replays')
     if not os.path.exists(import_dir):
         os.mkdir(import_dir)
     with ba.Context('ui'):
         FileSelectorWindow(import_dir, self._import_my_replay, True,
                            ['brp'], False)
def screenmessage(message: Language) -> None:
    if message not in Language:
        raise ValueError()
    if message == Language.SUCCESS:
        color = (0, 1.0, 0)
    elif message == Language.UNSUCCESS:
        color = (1.0, 0, 0)
    else:
        color = (1.0, 1.0, 1.0)
    with ba.Context('ui'):
        ba.screenmessage(message=message.value, color=color)
    def _launch(self) -> None:
        if self._launched:
            return
        self._launched = True
        launched = False

        # If they gave us an existing activity, just restart it.
        if self._tournament_activity is not None:
            try:
                ba.timer(0.1,
                         lambda: ba.playsound(ba.getsound('cashRegister')),
                         timetype=ba.TimeType.REAL)
                with ba.Context(self._tournament_activity):
                    self._tournament_activity.end({'outcome': 'restart'},
                                                  force=True)
                ba.timer(0.3, self._transition_out, timetype=ba.TimeType.REAL)
                launched = True
                ba.screenmessage(ba.Lstr(translate=('serverResponses',
                                                    'Entering tournament...')),
                                 color=(0, 1, 0))

            # We can hit exceptions here if _tournament_activity ends before
            # our restart attempt happens.
            # In this case we'll fall back to launching a new session.
            # This is not ideal since players will have to rejoin, etc.,
            # but it works for now.
            except Exception:
                ba.print_exception('Error restarting tournament activity.')

        # If we had no existing activity (or were unable to restart it)
        # launch a new session.
        if not launched:
            ba.timer(0.1,
                     lambda: ba.playsound(ba.getsound('cashRegister')),
                     timetype=ba.TimeType.REAL)
            ba.timer(
                1.0,
                lambda: ba.app.launch_coop_game(
                    self._tournament_info['game'],
                    args={
                        'min_players': self._tournament_info['minPlayers'],
                        'max_players': self._tournament_info['maxPlayers'],
                        'tournament_id': self._tournament_id
                    }),
                timetype=ba.TimeType.REAL)
            ba.timer(0.7, self._transition_out, timetype=ba.TimeType.REAL)
            ba.screenmessage(ba.Lstr(translate=('serverResponses',
                                                'Entering tournament...')),
                             color=(0, 1, 0))
示例#7
0
            def _got_news(self, news: str) -> None:
                # Run this stuff in the context of our activity since we
                # need to make nodes and stuff.. should fix the serverget
                # call so it.
                activity = self._activity()
                if activity is None or activity.expired:
                    return
                with ba.Context(activity):

                    self._phrases: List[str] = []

                    # Show upcoming achievements in non-vr versions
                    # (currently too hard to read in vr).
                    self._used_phrases = (
                        ['__ACH__'] if not ba.app.vr_mode else
                        []) + [s for s in news.split('<br>\n') if s != '']
                    self._phrase_change_timer = ba.Timer(
                        (self._message_duration + self._message_spacing),
                        ba.WeakCall(self._change_phrase),
                        repeat=True)

                    scl = 1.2 if (ba.app.ui.uiscale is ba.UIScale.SMALL
                                  or ba.app.vr_mode) else 0.8

                    color2 = ((1, 1, 1, 1) if ba.app.vr_mode else
                              (0.7, 0.65, 0.75, 1.0))
                    shadow = (1.0 if ba.app.vr_mode else 0.4)
                    self._text = ba.NodeActor(
                        ba.newnode('text',
                                   attrs={
                                       'v_attach': 'top',
                                       'h_attach': 'center',
                                       'h_align': 'center',
                                       'vr_depth': -20,
                                       'shadow': shadow,
                                       'flatness': 0.8,
                                       'v_align': 'top',
                                       'color': color2,
                                       'scale': scl,
                                       'maxwidth': 900.0 / scl,
                                       'position': (0, -10)
                                   }))
                    self._change_phrase()
def _notify_handlers(cmd: str, playerdata: PlayerData):
    args = cmd.split()
    for handler in _handlers:
        if args[0] in handler.commands and playerdata.status in handler.statuses:
            if _lastrun.get(playerdata.id, {}).get(
                    args[0], 0) + handler.statuses[playerdata.status] < int(
                        datetime.now().timestamp()):
                try:
                    with ba.Context(get_foreground_host_activity()):
                        handler.callback(playerdata, args)
                except Exception:
                    ba.print_exception(
                        f'Error while processing command {cmd} from {playerdata.id}'
                    )
                    chatmessage(get_locale('command_some_error'))
                lastrun = _lastrun.get(playerdata.id, {})
                lastrun[args[0]] = int(datetime.now().timestamp())
                _lastrun[playerdata.id] = lastrun
            else:
                chatmessage(get_locale('commands_too_many'))
示例#9
0
    def _smooth_update(self) -> None:
        if not self._ticket_count_text:
            self._smooth_update_timer = None
            return

        finished = False

        # if we're going down, do it immediately
        assert self._smooth_ticket_count is not None
        if int(self._smooth_ticket_count) >= self._ticket_count:
            self._smooth_ticket_count = float(self._ticket_count)
            finished = True
        else:
            # we're going up; start a sound if need be
            self._smooth_ticket_count = min(
                self._smooth_ticket_count + 1.0 * self._smooth_increase_speed,
                self._ticket_count)
            if int(self._smooth_ticket_count) >= self._ticket_count:
                finished = True
                self._smooth_ticket_count = float(self._ticket_count)
            elif self._ticking_node is None:
                with ba.Context('ui'):
                    self._ticking_node = ba.newnode(
                        'sound',
                        attrs={
                            'sound': ba.getsound('scoreIncrease'),
                            'positional': False
                        })

        ba.textwidget(edit=self._ticket_count_text,
                      text=str(int(self._smooth_ticket_count)))

        # if we've reached the target, kill the timer/sound/etc
        if finished:
            self._smooth_update_timer = None
            if self._ticking_node is not None:
                self._ticking_node.delete()
                self._ticking_node = None
                ba.playsound(ba.getsound('cashRegister2'))
示例#10
0
def show_offer() -> bool:
    """(internal)"""
    try:
        from bastd.ui import feedback
        app = ba.app

        # Space things out a bit so we don't hit the poor user with an ad and
        # then an in-game offer.
        has_been_long_enough_since_ad = True
        if (app.ads.last_ad_completion_time is not None and
            (ba.time(ba.TimeType.REAL) - app.ads.last_ad_completion_time <
             30.0)):
            has_been_long_enough_since_ad = False

        if app.special_offer is not None and has_been_long_enough_since_ad:

            # Special case: for pro offers, store this in our prefs so we
            # can re-show it if the user kills us (set phasers to 'NAG'!!!).
            if app.special_offer.get('item') == 'pro_fullprice':
                cfg = app.config
                cfg['pendingSpecialOffer'] = {
                    'a': _ba.get_public_login_id(),
                    'o': app.special_offer
                }
                cfg.commit()

            with ba.Context('ui'):
                if app.special_offer['item'] == 'rating':
                    feedback.ask_for_rating()
                else:
                    SpecialOfferWindow(app.special_offer)

            app.special_offer = None
            return True
    except Exception:
        ba.print_exception('Error showing offer.')

    return False
示例#11
0
 def _die(self, immediate: bool = False) -> None:
     session = self._session()
     if session is None and self.node:
         # If session is gone, our node should be too,
         # since it was part of the session's scene.
         # Let's make sure that's the case.
         # (since otherwise we have no way to kill it)
         ba.print_error('got None session on Background _die'
                        ' (and node still exists!)')
     elif session is not None:
         with ba.Context(session):
             if not self._dying and self.node:
                 self._dying = True
                 if immediate:
                     self.node.delete()
                 else:
                     ba.animate(self.node,
                                'opacity', {
                                    0.0: 1.0,
                                    self.fade_time: 0.0
                                },
                                loop=False)
                     ba.timer(self.fade_time + 0.1, self.node.delete)
示例#12
0
    def on_transition_in(self) -> None:
        super().on_transition_in()
        random.seed(123)
        self._logo_node: Optional[ba.Node] = None
        self._custom_logo_tex_name: Optional[str] = None
        self._word_actors: List[ba.Actor] = []
        app = ba.app

        # FIXME: We shouldn't be doing things conditionally based on whether
        #  the host is VR mode or not (clients may differ in that regard).
        #  Any differences need to happen at the engine level so everyone
        #  sees things in their own optimal way.
        vr_mode = ba.app.vr_mode

        if not ba.app.toolbar_test:
            color = ((1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6))
            # FIXME: Need a node attr for vr-specific-scale.
            scale = (0.9 if
                     (app.ui.uiscale is ba.UIScale.SMALL or vr_mode) else 0.7)
            self.my_name = ba.NodeActor(
                ba.newnode('text',
                           attrs={
                               'v_attach': 'bottom',
                               'h_align': 'center',
                               'color': color,
                               'flatness': 1.0,
                               'shadow': 1.0 if vr_mode else 0.5,
                               'scale': scale,
                               'position': (0, 10),
                               'vr_depth': -10,
                               'text': '\xa9 2011-2020 Eric Froemling'
                           }))

        # Throw up some text that only clients can see so they know that the
        # host is navigating menus while they're just staring at an
        # empty-ish screen.
        tval = ba.Lstr(resource='hostIsNavigatingMenusText',
                       subs=[('${HOST}', _ba.get_account_display_string())])
        self._host_is_navigating_text = ba.NodeActor(
            ba.newnode('text',
                       attrs={
                           'text': tval,
                           'client_only': True,
                           'position': (0, -200),
                           'flatness': 1.0,
                           'h_align': 'center'
                       }))
        if not ba.app.main_menu_did_initial_transition and hasattr(
                self, 'my_name'):
            assert self.my_name.node
            ba.animate(self.my_name.node, 'opacity', {2.3: 0, 3.0: 1.0})

        # FIXME: We shouldn't be doing things conditionally based on whether
        #  the host is vr mode or not (clients may not be or vice versa).
        #  Any differences need to happen at the engine level so everyone sees
        #  things in their own optimal way.
        vr_mode = app.vr_mode
        uiscale = app.ui.uiscale

        # In cases where we're doing lots of dev work lets always show the
        # build number.
        force_show_build_number = False

        if not ba.app.toolbar_test:
            if app.debug_build or app.test_build or force_show_build_number:
                if app.debug_build:
                    text = ba.Lstr(value='${V} (${B}) (${D})',
                                   subs=[
                                       ('${V}', app.version),
                                       ('${B}', str(app.build_number)),
                                       ('${D}', ba.Lstr(resource='debugText')),
                                   ])
                else:
                    text = ba.Lstr(value='${V} (${B})',
                                   subs=[
                                       ('${V}', app.version),
                                       ('${B}', str(app.build_number)),
                                   ])
            else:
                text = ba.Lstr(value='${V}', subs=[('${V}', app.version)])
            scale = 0.9 if (uiscale is ba.UIScale.SMALL or vr_mode) else 0.7
            color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7)
            self.version = ba.NodeActor(
                ba.newnode(
                    'text',
                    attrs={
                        'v_attach': 'bottom',
                        'h_attach': 'right',
                        'h_align': 'right',
                        'flatness': 1.0,
                        'vr_depth': -10,
                        'shadow': 1.0 if vr_mode else 0.5,
                        'color': color,
                        'scale': scale,
                        'position': (-260, 10) if vr_mode else (-10, 10),
                        'text': text
                    }))
            if not ba.app.main_menu_did_initial_transition:
                assert self.version.node
                ba.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0})

        # Show the iircade logo on our iircade build.
        if app.iircade_mode:
            img = ba.NodeActor(
                ba.newnode('image',
                           attrs={
                               'texture': ba.gettexture('iircadeLogo'),
                               'attach': 'center',
                               'scale': (250, 250),
                               'position': (0, 0),
                               'tilt_translate': 0.21,
                               'absolute_scale': True
                           })).autoretain()
            imgdelay = 0.0 if app.main_menu_did_initial_transition else 1.0
            ba.animate(img.node, 'opacity', {
                imgdelay + 1.5: 0.0,
                imgdelay + 2.5: 1.0
            })

        # Throw in test build info.
        self.beta_info = self.beta_info_2 = None
        if app.test_build and not (app.demo_mode or app.arcade_mode):
            pos = ((230, 125) if (app.demo_mode or app.arcade_mode) else
                   (230, 35))
            self.beta_info = ba.NodeActor(
                ba.newnode('text',
                           attrs={
                               'v_attach': 'center',
                               'h_align': 'center',
                               'color': (1, 1, 1, 1),
                               'shadow': 0.5,
                               'flatness': 0.5,
                               'scale': 1,
                               'vr_depth': -60,
                               'position': pos,
                               'text': ba.Lstr(resource='testBuildText')
                           }))
            if not ba.app.main_menu_did_initial_transition:
                assert self.beta_info.node
                ba.animate(self.beta_info.node, 'opacity', {1.3: 0, 1.8: 1.0})

        model = ba.getmodel('thePadLevel')
        trees_model = ba.getmodel('trees')
        bottom_model = ba.getmodel('thePadLevelBottom')
        color_texture = ba.gettexture('thePadLevelColor')
        trees_texture = ba.gettexture('treesColor')
        bgtex = ba.gettexture('menuBG')
        bgmodel = ba.getmodel('thePadBG')

        # Load these last since most platforms don't use them.
        vr_bottom_fill_model = ba.getmodel('thePadVRFillBottom')
        vr_top_fill_model = ba.getmodel('thePadVRFillTop')

        gnode = self.globalsnode
        gnode.camera_mode = 'rotate'

        tint = (1.14, 1.1, 1.0)
        gnode.tint = tint
        gnode.ambient_color = (1.06, 1.04, 1.03)
        gnode.vignette_outer = (0.45, 0.55, 0.54)
        gnode.vignette_inner = (0.99, 0.98, 0.98)

        self.bottom = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': bottom_model,
                           'lighting': False,
                           'reflection': 'soft',
                           'reflection_scale': [0.45],
                           'color_texture': color_texture
                       }))
        self.vr_bottom_fill = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': vr_bottom_fill_model,
                           'lighting': False,
                           'vr_only': True,
                           'color_texture': color_texture
                       }))
        self.vr_top_fill = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': vr_top_fill_model,
                           'vr_only': True,
                           'lighting': False,
                           'color_texture': bgtex
                       }))
        self.terrain = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': model,
                           'color_texture': color_texture,
                           'reflection': 'soft',
                           'reflection_scale': [0.3]
                       }))
        self.trees = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': trees_model,
                           'lighting': False,
                           'reflection': 'char',
                           'reflection_scale': [0.1],
                           'color_texture': trees_texture
                       }))
        self.bgterrain = ba.NodeActor(
            ba.newnode('terrain',
                       attrs={
                           'model': bgmodel,
                           'color': (0.92, 0.91, 0.9),
                           'lighting': False,
                           'background': True,
                           'color_texture': bgtex
                       }))

        self._ts = 0.86

        self._language: Optional[str] = None
        self._update_timer = ba.Timer(1.0, self._update, repeat=True)
        self._update()

        # Hopefully this won't hitch but lets space these out anyway.
        _ba.add_clean_frame_callback(ba.WeakCall(self._start_preloads))

        random.seed()

        # On the main menu, also show our news.
        class News:
            """Wrangles news display."""

            def __init__(self, activity: ba.Activity):
                self._valid = True
                self._message_duration = 10.0
                self._message_spacing = 2.0
                self._text: Optional[ba.NodeActor] = None
                self._activity = weakref.ref(activity)

                # If we're signed in, fetch news immediately.
                # Otherwise wait until we are signed in.
                self._fetch_timer: Optional[ba.Timer] = ba.Timer(
                    1.0, ba.WeakCall(self._try_fetching_news), repeat=True)
                self._try_fetching_news()

            # We now want to wait until we're signed in before fetching news.
            def _try_fetching_news(self) -> None:
                if _ba.get_account_state() == 'signed_in':
                    self._fetch_news()
                    self._fetch_timer = None

            def _fetch_news(self) -> None:
                ba.app.main_menu_last_news_fetch_time = time.time()

                # UPDATE - We now just pull news from MRVs.
                news = _ba.get_account_misc_read_val('n', None)
                if news is not None:
                    self._got_news(news)

            def _change_phrase(self) -> None:
                from bastd.actor.text import Text

                # If our news is way out of date, lets re-request it;
                # otherwise, rotate our phrase.
                assert ba.app.main_menu_last_news_fetch_time is not None
                if time.time() - ba.app.main_menu_last_news_fetch_time > 600.0:
                    self._fetch_news()
                    self._text = None
                else:
                    if self._text is not None:
                        if not self._phrases:
                            for phr in self._used_phrases:
                                self._phrases.insert(0, phr)
                        val = self._phrases.pop()
                        if val == '__ACH__':
                            vrmode = app.vr_mode
                            Text(ba.Lstr(resource='nextAchievementsText'),
                                 color=((1, 1, 1, 1) if vrmode else
                                        (0.95, 0.9, 1, 0.4)),
                                 host_only=True,
                                 maxwidth=200,
                                 position=(-300, -35),
                                 h_align=Text.HAlign.RIGHT,
                                 transition=Text.Transition.FADE_IN,
                                 scale=0.9 if vrmode else 0.7,
                                 flatness=1.0 if vrmode else 0.6,
                                 shadow=1.0 if vrmode else 0.5,
                                 h_attach=Text.HAttach.CENTER,
                                 v_attach=Text.VAttach.TOP,
                                 transition_delay=1.0,
                                 transition_out_delay=self._message_duration
                                 ).autoretain()
                            achs = [
                                a for a in app.achievements if not a.complete
                            ]
                            if achs:
                                ach = achs.pop(
                                    random.randrange(min(4, len(achs))))
                                ach.create_display(
                                    -180,
                                    -35,
                                    1.0,
                                    outdelay=self._message_duration,
                                    style='news')
                            if achs:
                                ach = achs.pop(
                                    random.randrange(min(8, len(achs))))
                                ach.create_display(
                                    180,
                                    -35,
                                    1.25,
                                    outdelay=self._message_duration,
                                    style='news')
                        else:
                            spc = self._message_spacing
                            keys = {
                                spc: 0.0,
                                spc + 1.0: 1.0,
                                spc + self._message_duration - 1.0: 1.0,
                                spc + self._message_duration: 0.0
                            }
                            assert self._text.node
                            ba.animate(self._text.node, 'opacity', keys)
                            # {k: v
                            #  for k, v in list(keys.items())})
                            self._text.node.text = val

            def _got_news(self, news: str) -> None:
                # Run this stuff in the context of our activity since we
                # need to make nodes and stuff.. should fix the serverget
                # call so it.
                activity = self._activity()
                if activity is None or activity.expired:
                    return
                with ba.Context(activity):

                    self._phrases: List[str] = []

                    # Show upcoming achievements in non-vr versions
                    # (currently too hard to read in vr).
                    self._used_phrases = (
                        ['__ACH__'] if not ba.app.vr_mode else
                        []) + [s for s in news.split('<br>\n') if s != '']
                    self._phrase_change_timer = ba.Timer(
                        (self._message_duration + self._message_spacing),
                        ba.WeakCall(self._change_phrase),
                        repeat=True)

                    scl = 1.2 if (ba.app.ui.uiscale is ba.UIScale.SMALL
                                  or ba.app.vr_mode) else 0.8

                    color2 = ((1, 1, 1, 1) if ba.app.vr_mode else
                              (0.7, 0.65, 0.75, 1.0))
                    shadow = (1.0 if ba.app.vr_mode else 0.4)
                    self._text = ba.NodeActor(
                        ba.newnode('text',
                                   attrs={
                                       'v_attach': 'top',
                                       'h_attach': 'center',
                                       'h_align': 'center',
                                       'vr_depth': -20,
                                       'shadow': shadow,
                                       'flatness': 0.8,
                                       'v_align': 'top',
                                       'color': color2,
                                       'scale': scl,
                                       'maxwidth': 900.0 / scl,
                                       'position': (0, -10)
                                   }))
                    self._change_phrase()

        if not (app.demo_mode or app.arcade_mode) and not app.toolbar_test:
            self._news = News(self)

        # Bring up the last place we were, or start at the main menu otherwise.
        with ba.Context('ui'):
            from bastd.ui import specialoffer
            if bool(False):
                uicontroller = ba.app.ui.controller
                assert uicontroller is not None
                uicontroller.show_main_menu()
            else:
                main_menu_location = ba.app.ui.get_main_menu_location()

                # When coming back from a kiosk-mode game, jump to
                # the kiosk start screen.
                if ba.app.demo_mode or ba.app.arcade_mode:
                    # pylint: disable=cyclic-import
                    from bastd.ui.kiosk import KioskWindow
                    ba.app.ui.set_main_menu_window(
                        KioskWindow().get_root_widget())
                # ..or in normal cases go back to the main menu
                else:
                    if main_menu_location == 'Gather':
                        # pylint: disable=cyclic-import
                        from bastd.ui.gather import GatherWindow
                        ba.app.ui.set_main_menu_window(
                            GatherWindow(transition=None).get_root_widget())
                    elif main_menu_location == 'Watch':
                        # pylint: disable=cyclic-import
                        from bastd.ui.watch import WatchWindow
                        ba.app.ui.set_main_menu_window(
                            WatchWindow(transition=None).get_root_widget())
                    elif main_menu_location == 'Team Game Select':
                        # pylint: disable=cyclic-import
                        from bastd.ui.playlist.browser import (
                            PlaylistBrowserWindow)
                        ba.app.ui.set_main_menu_window(
                            PlaylistBrowserWindow(
                                sessiontype=ba.DualTeamSession,
                                transition=None).get_root_widget())
                    elif main_menu_location == 'Free-for-All Game Select':
                        # pylint: disable=cyclic-import
                        from bastd.ui.playlist.browser import (
                            PlaylistBrowserWindow)
                        ba.app.ui.set_main_menu_window(
                            PlaylistBrowserWindow(
                                sessiontype=ba.FreeForAllSession,
                                transition=None).get_root_widget())
                    elif main_menu_location == 'Coop Select':
                        # pylint: disable=cyclic-import
                        from bastd.ui.coop.browser import CoopBrowserWindow
                        ba.app.ui.set_main_menu_window(
                            CoopBrowserWindow(
                                transition=None).get_root_widget())
                    else:
                        # pylint: disable=cyclic-import
                        from bastd.ui.mainmenu import MainMenuWindow
                        ba.app.ui.set_main_menu_window(
                            MainMenuWindow(transition=None).get_root_widget())

                # attempt to show any pending offers immediately.
                # If that doesn't work, try again in a few seconds
                # (we may not have heard back from the server)
                # ..if that doesn't work they'll just have to wait
                # until the next opportunity.
                if not specialoffer.show_offer():

                    def try_again() -> None:
                        if not specialoffer.show_offer():
                            # Try one last time..
                            ba.timer(2.0,
                                     specialoffer.show_offer,
                                     timetype=ba.TimeType.REAL)

                    ba.timer(2.0, try_again, timetype=ba.TimeType.REAL)
        ba.app.main_menu_did_initial_transition = True
示例#13
0
 def __init__(self,
              fade_time: float = 0.5,
              start_faded: bool = False,
              show_logo: bool = False):
     super().__init__()
     self._dying = False
     self.fade_time = fade_time
     # We're special in that we create our node in the session
     # scene instead of the activity scene.
     # This way we can overlap multiple activities for fades
     # and whatnot.
     session = ba.getsession()
     self._session = weakref.ref(session)
     with ba.Context(session):
         self.node = ba.newnode('image',
                                delegate=self,
                                attrs={
                                    'fill_screen': True,
                                    'texture': ba.gettexture('bg'),
                                    'tilt_translate': -0.3,
                                    'has_alpha_channel': False,
                                    'color': (1, 1, 1)
                                })
         if not start_faded:
             ba.animate(self.node,
                        'opacity', {
                            0.0: 0.0,
                            self.fade_time: 1.0
                        },
                        loop=False)
         if show_logo:
             logo_texture = ba.gettexture('logo')
             logo_model = ba.getmodel('logo')
             logo_model_transparent = ba.getmodel('logoTransparent')
             self.logo = ba.newnode('image',
                                    owner=self.node,
                                    attrs={
                                        'texture': logo_texture,
                                        'model_opaque': logo_model,
                                        'model_transparent':
                                        logo_model_transparent,
                                        'scale': (0.7, 0.7),
                                        'vr_depth': -250,
                                        'color': (0.15, 0.15, 0.15),
                                        'position': (0, 0),
                                        'tilt_translate': -0.05,
                                        'absolute_scale': False
                                    })
             self.node.connectattr('opacity', self.logo, 'opacity')
             # add jitter/pulse for a stop-motion-y look unless we're in VR
             # in which case stillness is better
             if not ba.app.vr_mode:
                 self.cmb = ba.newnode('combine',
                                       owner=self.node,
                                       attrs={'size': 2})
                 for attr in ['input0', 'input1']:
                     ba.animate(self.cmb,
                                attr, {
                                    0.0: 0.693,
                                    0.05: 0.7,
                                    0.5: 0.693
                                },
                                loop=True)
                 self.cmb.connectattr('output', self.logo, 'scale')
                 cmb = ba.newnode('combine',
                                  owner=self.node,
                                  attrs={'size': 2})
                 cmb.connectattr('output', self.logo, 'position')
                 # Gen some random keys for that stop-motion-y look.
                 keys = {}
                 timeval = 0.0
                 for _i in range(10):
                     keys[timeval] = (random.random() - 0.5) * 0.0015
                     timeval += random.random() * 0.1
                 ba.animate(cmb, 'input0', keys, loop=True)
                 keys = {}
                 timeval = 0.0
                 for _i in range(10):
                     keys[timeval] = (random.random() - 0.5) * 0.0015 + 0.05
                     timeval += random.random() * 0.1
                 ba.animate(cmb, 'input1', keys, loop=True)
 def on_copy(result: bool = False) -> None:
     if result:
         with ba.Context('ui'):
             self._my_replay_selected = None
             self._refresh_my_replays()
def open_fileselector(path: str, callback: Callable = None) -> None:
    with ba.Context('ui'):
        FileSelectorWindow(path, callback, True, ['brp'], False)
示例#16
0
def set_next_map(session, game_map):
    session._next_game_spec = game_map
    with ba.Context(session):
        session._instantiate_next_game()
示例#17
0
    def _smooth_update(self) -> None:
        # pylint: disable=too-many-branches
        # pylint: disable=too-many-statements
        try:
            if not self._button:
                return
            if self._ticking_node is None:
                with ba.Context('ui'):
                    self._ticking_node = ba.newnode(
                        'sound',
                        attrs={
                            'sound': ba.getsound('scoreIncrease'),
                            'positional': False
                        })
            self._bg_flash = (not self._bg_flash)
            color_used = ((self._color[0] * 2, self._color[1] * 2,
                           self._color[2] *
                           2) if self._bg_flash else self._color)
            textcolor_used = ((1, 1, 1) if self._bg_flash else self._textcolor)
            header_color_used = ((1, 1,
                                  1) if self._bg_flash else self._header_color)

            if self._rank is not None:
                assert self._smooth_rank is not None
                self._smooth_rank -= 1.0 * self._smooth_increase_speed
                finished = (int(self._smooth_rank) <= self._rank)
            elif self._smooth_percent is not None:
                self._smooth_percent += 1.0 * self._smooth_increase_speed
                assert self._percent is not None
                finished = (int(self._smooth_percent) >= self._percent)
            else:
                finished = True
            if finished:
                if self._rank is not None:
                    self._smooth_rank = float(self._rank)
                elif self._percent is not None:
                    self._smooth_percent = float(self._percent)
                color_used = self._color
                textcolor_used = self._textcolor
                self._smooth_update_timer = None
                if self._ticking_node is not None:
                    self._ticking_node.delete()
                    self._ticking_node = None
                ba.playsound(ba.getsound('cashRegister2'))
                assert self._improvement_text is not None
                diff_text = ba.textwidget(
                    parent=self._parent,
                    size=(0, 0),
                    h_align='center',
                    v_align='center',
                    text='+' + self._improvement_text + '!',
                    position=(self._position[0] +
                              self._size[0] * 0.5 * self._scale,
                              self._position[1] +
                              self._size[1] * -0.2 * self._scale),
                    color=(0, 1, 0),
                    flatness=1.0,
                    shadow=0.0,
                    scale=self._scale * 0.7)

                def safe_delete(widget: ba.Widget) -> None:
                    if widget:
                        widget.delete()

                ba.timer(2.0,
                         ba.Call(safe_delete, diff_text),
                         timetype=ba.TimeType.REAL)
            status_text: Union[str, ba.Lstr]
            if self._rank is not None:
                assert self._smooth_rank is not None
                status_text = ba.Lstr(resource='numberText',
                                      subs=[('${NUMBER}',
                                             str(int(self._smooth_rank)))])
            elif self._smooth_percent is not None:
                status_text = str(int(self._smooth_percent)) + '%'
            else:
                status_text = '-'
            ba.textwidget(edit=self._value_text,
                          text=status_text,
                          color=textcolor_used)
            ba.textwidget(edit=self._title_text, color=header_color_used)
            ba.buttonwidget(edit=self._button, color=color_used)

        except Exception:
            ba.print_exception('Error doing smooth update.')
            self._smooth_update_timer = None
示例#18
0
    def _on_public_party_query_result(
            self, result: Optional[Dict[str, Any]]) -> None:
        with ba.Context('ui'):
            # Any time we get any result at all, kill our loading status.
            status_text = self._join_status_text
            if status_text:
                # Don't show results if not signed in
                # (probably didn't get any anyway).
                if _ba.get_account_state() != 'signed_in':
                    ba.textwidget(edit=status_text,
                                  text=ba.Lstr(resource='notSignedInText'))
                else:
                    if result is None:
                        ba.textwidget(edit=status_text,
                                      text=ba.Lstr(resource='errorText'))
                    else:
                        ba.textwidget(edit=status_text, text='')

            if result is not None:
                self._have_valid_server_list = True
                parties_in = result['l']
            else:
                self._have_valid_server_list = False
                parties_in = []

            for partyval in list(self._parties.values()):
                partyval.claimed = False

            for party_in in parties_in:
                addr = party_in['a']
                assert isinstance(addr, str)
                port = party_in['p']
                assert isinstance(port, int)
                party_key = f'{addr}_{port}'
                party = self._parties.get(party_key)
                if party is None:
                    # If this party is new to us, init it.
                    party = self._parties[party_key] = PartyEntry(
                        address=addr,
                        next_ping_time=ba.time(ba.TimeType.REAL) +
                        0.001 * party_in['pd'],
                        index=self._next_entry_index)
                    self._next_entry_index += 1
                    assert isinstance(party.address, str)
                    assert isinstance(party.next_ping_time, float)

                # Now, new or not, update its values.
                party.queue = party_in.get('q')
                assert isinstance(party.queue, (str, type(None)))
                party.port = port
                party.name = party_in['n']
                assert isinstance(party.name, str)
                party.size = party_in['s']
                assert isinstance(party.size, int)
                party.size_max = party_in['sm']
                assert isinstance(party.size_max, int)
                party.claimed = True
                # (server provides this in milliseconds; we use seconds)
                party.ping_interval = 0.001 * party_in['pi']
                assert isinstance(party.ping_interval, float)
                party.stats_addr = party_in['sa']
                assert isinstance(party.stats_addr, (str, type(None)))

            # Prune unclaimed party entries.
            self._parties = {
                key: val
                for key, val in list(self._parties.items()) if val.claimed
            }
            self._update_server_list()
示例#19
0
    def _update_server_list(self) -> None:
        cur_time = ba.time(ba.TimeType.REAL)
        if self._first_server_list_rebuild_time is None:
            self._first_server_list_rebuild_time = cur_time

        # We get called quite often (for each ping response, etc) so we want
        # to limit our rebuilds to keep the UI responsive.
        # Let's update faster for the first few seconds,
        # then ease off to keep the list from jumping around.
        since_first = cur_time - self._first_server_list_rebuild_time
        wait_time = (1.0 if since_first < 2.0 else
                     2.5 if since_first < 10.0 else 5.0)
        if (not self._server_list_dirty
                and self._last_server_list_update_time is not None
                and cur_time - self._last_server_list_update_time < wait_time):
            return

        # If we somehow got here without the required UI being in place...
        columnwidget = self._join_list_column
        if not columnwidget:
            return

        self._last_server_list_update_time = cur_time
        self._server_list_dirty = False

        with ba.Context('ui'):

            # Now kill and recreate all widgets.
            for widget in columnwidget.get_children():
                widget.delete()

            ordered_parties = self._get_ordered_parties()

            # If we've got a filter, filter them.
            if self._filter_value:
                # Let's do case-insensitive searching.
                filterval = self._filter_value.lower()
                ordered_parties = [
                    p for p in ordered_parties if filterval in p.name.lower()
                ]

            sub_scroll_width = 830
            lineheight = 42
            sub_scroll_height = lineheight * len(ordered_parties) + 50
            ba.containerwidget(edit=columnwidget,
                               size=(sub_scroll_width, sub_scroll_height))

            # Ew; this rebuilding generates deferred selection callbacks
            # so we need to generated deferred ignore notices for ourself.
            def refresh_on() -> None:
                self._refreshing_list = True

            ba.pushcall(refresh_on)

            # Janky - allow escaping if there's nothing in us.
            ba.containerwidget(edit=self._host_scrollwidget,
                               claims_up_down=(len(ordered_parties) > 0))

            self._build_server_entry_lines(lineheight, ordered_parties,
                                           sub_scroll_height, sub_scroll_width)

            # So our selection callbacks can start firing..
            def refresh_off() -> None:
                self._refreshing_list = False

            ba.pushcall(refresh_off)