Пример #1
0
    def _add_chosen_player(self, chooser: ba.Chooser) -> ba.SessionPlayer:
        from ba._team import SessionTeam
        sessionplayer = chooser.getplayer()
        assert sessionplayer in self.sessionplayers, (
            'SessionPlayer not found in session '
            'player-list after chooser selection.')

        activity = self._activity_weak()
        assert activity is not None

        # Reset the player's input here, as it is probably
        # referencing the chooser which could inadvertently keep it alive.
        sessionplayer.resetinput()

        # We can pass it to the current activity if it has already begun
        # (otherwise it'll get passed once begin is called).
        pass_to_activity = (activity.has_begun()
                            and not activity.is_joining_activity)

        # However, if we're not allowing mid-game joins, don't actually pass;
        # just announce the arrival and say they'll partake next round.
        if pass_to_activity:
            if not self.allow_mid_activity_joins:
                pass_to_activity = False
                with _ba.Context(self):
                    _ba.screenmessage(
                        Lstr(resource='playerDelayedJoinText',
                             subs=[('${PLAYER}',
                                    sessionplayer.getname(full=True))]),
                        color=(0, 1, 0),
                    )

        # If we're a non-team session, each player gets their own team.
        # (keeps mini-game coding simpler if we can always deal with teams).
        if self.use_teams:
            sessionteam = chooser.sessionteam
        else:
            our_team_id = self._next_team_id
            self._next_team_id += 1
            sessionteam = SessionTeam(
                team_id=our_team_id,
                color=chooser.get_color(),
                name=chooser.getplayer().getname(full=True, icon=False),
            )

            # Add player's team to the Session.
            self.sessionteams.append(sessionteam)

            with _ba.Context(self):
                try:
                    self.on_team_join(sessionteam)
                except Exception:
                    print_exception(f'Error in on_team_join for {self}.')

            # Add player's team to the Activity.
            if pass_to_activity:
                activity.add_team(sessionteam)

        assert sessionplayer not in sessionteam.players
        sessionteam.players.append(sessionplayer)
        sessionplayer.setdata(team=sessionteam,
                              character=chooser.get_character_name(),
                              color=chooser.get_color(),
                              highlight=chooser.get_highlight())

        self.stats.register_sessionplayer(sessionplayer)
        if pass_to_activity:
            activity.add_player(sessionplayer)
        return sessionplayer
Пример #2
0
    def on_app_launch(self) -> None:
        """Runs after the app finishes bootstrapping.

        (internal)"""
        # FIXME: Break this up.
        # pylint: disable=too-many-statements
        # pylint: disable=too-many-locals
        # pylint: disable=cyclic-import
        from ba import _apputils
        from ba import _appconfig
        from ba.ui import UIController, ui_upkeep
        from ba import _achievement
        from ba import _map
        from ba import _meta
        from ba import _campaign
        from bastd import appdelegate
        from bastd import maps as stdmaps
        from bastd.actor import spazappearance
        from ba._enums import TimeType, UIScale

        cfg = self.config

        self.delegate = appdelegate.AppDelegate()

        self.uicontroller = UIController()
        _achievement.init_achievements()
        spazappearance.register_appearances()
        _campaign.init_campaigns()

        # FIXME: This should not be hard-coded.
        for maptype in [
                stdmaps.HockeyStadium, stdmaps.FootballStadium,
                stdmaps.Bridgit, stdmaps.BigG, stdmaps.Roundabout,
                stdmaps.MonkeyFace, stdmaps.ZigZag, stdmaps.ThePad,
                stdmaps.DoomShroom, stdmaps.LakeFrigid, stdmaps.TipTop,
                stdmaps.CragCastle, stdmaps.TowerD, stdmaps.HappyThoughts,
                stdmaps.StepRightUp, stdmaps.Courtyard, stdmaps.Rampage
        ]:
            _map.register_map(maptype)

        # Non-test, non-debug builds should generally be blessed; warn if not.
        # (so I don't accidentally release a build that can't play tourneys)
        if (not self.debug_build and not self.test_build
                and not _ba.is_blessed()):
            _ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0))

        # Kick off our periodic UI upkeep.
        # FIXME: Can probably kill this if we do immediate UI death checks.
        self.uiupkeeptimer = _ba.Timer(2.6543,
                                       ui_upkeep,
                                       timetype=TimeType.REAL,
                                       repeat=True)

        # IMPORTANT: If tweaking UI stuff, make sure it behaves for small,
        # medium, and large UI modes. (doesn't run off screen, etc).
        # The overrides below can be used to test with different sizes.
        # Generally small is used on phones, medium is used on tablets/tvs,
        # and large is on desktop computers or perhaps large tablets. When
        # possible, run in windowed mode and resize the window to assure
        # this holds true at all aspect ratios.

        # UPDATE: A better way to test this is now by setting the environment
        # variable BA_FORCE_UI_SCALE to "small", "medium", or "large".
        # This will affect system UIs not covered by the values below such
        # as screen-messages. The below values remain functional, however,
        # for cases such as Android where environment variables can't be set
        # easily.

        if bool(False):  # force-test ui scale
            self._uiscale = UIScale.SMALL
            with _ba.Context('ui'):
                _ba.pushcall(lambda: _ba.screenmessage(
                    f'FORCING UISCALE {self._uiscale.name} FOR TESTING',
                    color=(1, 0, 1),
                    log=True))

        # If there's a leftover log file, attempt to upload it to the
        # master-server and/or get rid of it.
        _apputils.handle_leftover_log_file()

        # Only do this stuff if our config file is healthy so we don't
        # overwrite a broken one or whatnot and wipe out data.
        if not self.config_file_healthy:
            if self.platform in ('mac', 'linux', 'windows'):
                from bastd.ui import configerror
                configerror.ConfigErrorWindow()
                return

            # For now on other systems we just overwrite the bum config.
            # At this point settings are already set; lets just commit them
            # to disk.
            _appconfig.commit_app_config(force=True)

        self.music.on_app_launch()

        launch_count = cfg.get('launchCount', 0)
        launch_count += 1

        # So we know how many times we've run the game at various
        # version milestones.
        for key in ('lc14173', 'lc14292'):
            cfg.setdefault(key, launch_count)

        # Debugging - make note if we're using the local test server so we
        # don't accidentally leave it on in a release.
        # FIXME - should move this to the native layer.
        server_addr = _ba.get_master_server_address()
        if 'localhost' in server_addr:
            _ba.timer(2.0,
                      lambda: _ba.screenmessage('Note: using local server',
                                                (1, 1, 0),
                                                log=True),
                      timetype=TimeType.REAL)
        elif 'test' in server_addr:
            _ba.timer(
                2.0,
                lambda: _ba.screenmessage('Note: using test server-module',
                                          (1, 1, 0),
                                          log=True),
                timetype=TimeType.REAL)

        cfg['launchCount'] = launch_count
        cfg.commit()

        # Run a test in a few seconds to see if we should pop up an existing
        # pending special offer.
        def check_special_offer() -> None:
            from bastd.ui import specialoffer
            config = self.config
            if ('pendingSpecialOffer' in config and _ba.get_public_login_id()
                    == config['pendingSpecialOffer']['a']):
                self.special_offer = config['pendingSpecialOffer']['o']
                specialoffer.show_offer()

        if not self.headless_build:
            _ba.timer(3.0, check_special_offer, timetype=TimeType.REAL)

        # Start scanning for things exposed via ba_meta.
        _meta.start_scan()

        # Auto-sign-in to a local account in a moment if we're set to.
        def do_auto_sign_in() -> None:
            if self.headless_build or cfg.get('Auto Account State') == 'Local':
                _ba.sign_in('Local')

        _ba.pushcall(do_auto_sign_in)

        self.ran_on_app_launch = True
Пример #3
0
    def on_app_launch(self) -> None:
        """Runs after the app finishes bootstrapping.

        (internal)"""
        # pylint: disable=too-many-locals
        # pylint: disable=cyclic-import
        # pylint: disable=too-many-statements
        from ba import _apputils
        from ba import _appconfig
        from ba import _achievement
        from ba import _map
        from ba import _meta
        from ba import _campaign
        from bastd import appdelegate
        from bastd import maps as stdmaps
        from bastd.actor import spazappearance
        from ba._enums import TimeType

        cfg = self.config

        self.delegate = appdelegate.AppDelegate()

        self.ui.on_app_launch()

        _achievement.init_achievements()
        spazappearance.register_appearances()
        _campaign.init_campaigns()

        # FIXME: This should not be hard-coded.
        for maptype in [
                stdmaps.HockeyStadium, stdmaps.FootballStadium,
                stdmaps.Bridgit, stdmaps.BigG, stdmaps.Roundabout,
                stdmaps.MonkeyFace, stdmaps.ZigZag, stdmaps.ThePad,
                stdmaps.DoomShroom, stdmaps.LakeFrigid, stdmaps.TipTop,
                stdmaps.CragCastle, stdmaps.TowerD, stdmaps.HappyThoughts,
                stdmaps.StepRightUp, stdmaps.Courtyard, stdmaps.Rampage
        ]:
            _map.register_map(maptype)

        # Non-test, non-debug builds should generally be blessed; warn if not.
        # (so I don't accidentally release a build that can't play tourneys)
        if (not self.debug_build and not self.test_build
                and not _ba.is_blessed()):
            _ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0))

        # If there's a leftover log file, attempt to upload it to the
        # master-server and/or get rid of it.
        _apputils.handle_leftover_log_file()

        # Only do this stuff if our config file is healthy so we don't
        # overwrite a broken one or whatnot and wipe out data.
        if not self.config_file_healthy:
            if self.platform in ('mac', 'linux', 'windows'):
                from bastd.ui import configerror
                configerror.ConfigErrorWindow()
                return

            # For now on other systems we just overwrite the bum config.
            # At this point settings are already set; lets just commit them
            # to disk.
            _appconfig.commit_app_config(force=True)

        self.music.on_app_launch()

        launch_count = cfg.get('launchCount', 0)
        launch_count += 1

        # So we know how many times we've run the game at various
        # version milestones.
        for key in ('lc14173', 'lc14292'):
            cfg.setdefault(key, launch_count)

        # Debugging - make note if we're using the local test server so we
        # don't accidentally leave it on in a release.
        # FIXME - should move this to the native layer.
        server_addr = _ba.get_master_server_address()
        if 'localhost' in server_addr:
            _ba.timer(2.0,
                      lambda: _ba.screenmessage('Note: using local server',
                                                (1, 1, 0),
                                                log=True),
                      timetype=TimeType.REAL)
        elif 'test' in server_addr:
            _ba.timer(
                2.0,
                lambda: _ba.screenmessage('Note: using test server-module',
                                          (1, 1, 0),
                                          log=True),
                timetype=TimeType.REAL)

        cfg['launchCount'] = launch_count
        cfg.commit()

        # Run a test in a few seconds to see if we should pop up an existing
        # pending special offer.
        def check_special_offer() -> None:
            from bastd.ui import specialoffer
            config = self.config
            if ('pendingSpecialOffer' in config and _ba.get_public_login_id()
                    == config['pendingSpecialOffer']['a']):
                self.special_offer = config['pendingSpecialOffer']['o']
                specialoffer.show_offer()

        if not self.headless_mode:
            _ba.timer(3.0, check_special_offer, timetype=TimeType.REAL)

        # Start scanning for things exposed via ba_meta.
        _meta.start_scan()

        # Auto-sign-in to a local account in a moment if we're set to.
        def do_auto_sign_in() -> None:
            if self.headless_mode or cfg.get('Auto Account State') == 'Local':
                _ba.sign_in('Local')

        _ba.pushcall(do_auto_sign_in)

        # Load up our plugins and go ahead and call their on_app_launch calls.
        self.load_plugins()
        for plugin in self.active_plugins.values():
            try:
                plugin.on_app_launch()
            except Exception:
                from ba import _error
                _error.print_exception('Error in plugin on_app_launch()')

        self.ran_on_app_launch = True
Пример #4
0
def setlanguage(language: Optional[str],
                print_change: bool = True,
                store_to_config: bool = True) -> None:
    """Set the active language used for the game.

    category: General Utility Functions

    Pass None to use OS default language.
    """
    # pylint: disable=too-many-locals
    # pylint: disable=too-many-branches
    cfg = _ba.app.config
    cur_language = cfg.get('Lang', None)

    # Store this in the config if its changing.
    if language != cur_language and store_to_config:
        if language is None:
            if 'Lang' in cfg:
                del cfg['Lang']  # Clear it out for default.
        else:
            cfg['Lang'] = language
        cfg.commit()
        switched = True
    else:
        switched = False

    with open('ba_data/data/languages/english.json') as infile:
        lenglishvalues = json.loads(infile.read())

    # None implies default.
    if language is None:
        language = _ba.app.default_language
    try:
        if language == 'English':
            lmodvalues = None
        else:
            lmodfile = 'ba_data/data/languages/' + language.lower() + '.json'
            with open(lmodfile) as infile:
                lmodvalues = json.loads(infile.read())
    except Exception:
        from ba import _error
        _error.print_exception('Exception importing language:', language)
        _ba.screenmessage("Error setting language to '" + language +
                          "'; see log for details",
                          color=(1, 0, 0))
        switched = False
        lmodvalues = None

    # Create an attrdict of *just* our target language.
    _ba.app.language_target = AttrDict()
    langtarget = _ba.app.language_target
    assert langtarget is not None
    _add_to_attr_dict(langtarget,
                      lmodvalues if lmodvalues is not None else lenglishvalues)

    # Create an attrdict of our target language overlaid on our base (english).
    languages = [lenglishvalues]
    if lmodvalues is not None:
        languages.append(lmodvalues)
    lfull = AttrDict()
    for lmod in languages:
        _add_to_attr_dict(lfull, lmod)
    _ba.app.language_merged = lfull

    # Pass some keys/values in for low level code to use;
    # start with everything in their 'internal' section.
    internal_vals = [
        v for v in list(lfull['internal'].items()) if isinstance(v[1], str)
    ]

    # Cherry-pick various other values to include.
    # (should probably get rid of the 'internal' section
    # and do everything this way)
    for value in [
            'replayNameDefaultText', 'replayWriteErrorText',
            'replayVersionErrorText', 'replayReadErrorText'
    ]:
        internal_vals.append((value, lfull[value]))
    internal_vals.append(
        ('axisText', lfull['configGamepadWindow']['axisText']))
    lmerged = _ba.app.language_merged
    assert lmerged is not None
    random_names = [
        n.strip() for n in lmerged['randomPlayerNamesText'].split(',')
    ]
    random_names = [n for n in random_names if n != '']
    _ba.set_internal_language_keys(internal_vals, random_names)
    if switched and print_change:
        _ba.screenmessage(Lstr(resource='languageSetText',
                               subs=[('${LANGUAGE}',
                                      Lstr(translate=('languages', language)))
                                     ]),
                          color=(0, 1, 0))
Пример #5
0
def in_progress_message() -> None:
    from ba._lang import Lstr
    _ba.playsound(_ba.getsound('error'))
    _ba.screenmessage(Lstr(resource='getTicketsWindow.inProgressText'),
                      color=(1, 0, 0))
Пример #6
0
    def player_scored(self,
                      player: ba.Player,
                      base_points: int = 1,
                      target: Sequence[float] = None,
                      kill: bool = False,
                      victim_player: ba.Player = None,
                      scale: float = 1.0,
                      color: Sequence[float] = None,
                      title: Union[str, ba.Lstr] = None,
                      screenmessage: bool = True,
                      display: bool = True,
                      importance: int = 1,
                      showpoints: bool = True,
                      big_message: bool = False) -> int:
        """Register a score for the player.

        Return value is actual score with multipliers and such factored in.
        """
        # FIXME: Tidy this up.
        # pylint: disable=cyclic-import
        # pylint: disable=too-many-branches
        # pylint: disable=too-many-locals
        # pylint: disable=too-many-statements
        from bastd.actor.popuptext import PopupText
        from ba import _math
        from ba._gameactivity import GameActivity
        from ba._lang import Lstr
        del victim_player  # Currently unused.
        name = player.get_name()
        s_player = self._player_records[name]

        if kill:
            s_player.submit_kill(showpoints=showpoints)

        display_color: Sequence[float] = (1.0, 1.0, 1.0, 1.0)

        if color is not None:
            display_color = color
        elif importance != 1:
            display_color = (1.0, 1.0, 0.4, 1.0)
        points = base_points

        # If they want a big announcement, throw a zoom-text up there.
        if display and big_message:
            try:
                assert self._activity is not None
                activity = self._activity()
                if isinstance(activity, GameActivity):
                    name_full = player.get_name(full=True, icon=False)
                    activity.show_zoom_message(
                        Lstr(resource='nameScoresText',
                             subs=[('${NAME}', name_full)]),
                        color=_math.normalized_color(player.team.color))
            except Exception:
                from ba import _error
                _error.print_exception('error showing big_message')

        # If we currently have a actor, pop up a score over it.
        if display and showpoints:
            our_pos = player.node.position if player.node else None
            if our_pos is not None:
                if target is None:
                    target = our_pos

                # If display-pos is *way* lower than us, raise it up
                # (so we can still see scores from dudes that fell off cliffs).
                display_pos = (target[0], max(target[1], our_pos[1] - 2.0),
                               min(target[2], our_pos[2] + 2.0))
                activity = self.getactivity()
                if activity is not None:
                    if title is not None:
                        sval = Lstr(value='+${A} ${B}',
                                    subs=[('${A}', str(points)),
                                          ('${B}', title)])
                    else:
                        sval = Lstr(value='+${A}',
                                    subs=[('${A}', str(points))])
                    PopupText(sval,
                              color=display_color,
                              scale=1.2 * scale,
                              position=display_pos).autoretain()

        # Tally kills.
        if kill:
            s_player.accum_kill_count += 1
            s_player.kill_count += 1

        # Report non-kill scorings.
        try:
            if screenmessage and not kill:
                _ba.screenmessage(Lstr(resource='nameScoresText',
                                       subs=[('${NAME}', name)]),
                                  top=True,
                                  color=player.color,
                                  image=player.get_icon())
        except Exception:
            from ba import _error
            _error.print_exception('error announcing score')

        s_player.score += points
        s_player.accumscore += points

        # Inform a running game of the score.
        if points != 0:
            activity = self._activity() if self._activity is not None else None
            if activity is not None:
                activity.handlemessage(PlayerScoredMessage(score=points))

        return points
Пример #7
0
def purchase_not_valid_error() -> None:
    from ba._lang import Lstr
    _ba.playsound(_ba.getsound('error'))
    _ba.screenmessage(Lstr(resource='store.purchaseNotValidError',
                           subs=[('${EMAIL}', '*****@*****.**')]),
                      color=(1, 0, 0))
Пример #8
0
def connection_failed_message() -> None:
    from ba._lang import Lstr
    _ba.screenmessage(Lstr(resource='internal.connectionFailedText'),
                      color=(1, 0.5, 0))
Пример #9
0
def on_player_join_server(pbid, player_data):
    now = time.time()
    #player_data=pdata.get_info(pbid)
    clid = 113
    for ros in _ba.get_game_roster():
        if ros["account_id"] == pbid:
            clid = ros["client_id"]
    if pbid in serverdata.clients:
        rejoinCount = serverdata.clients[pbid]["rejoincount"]
        spamCount = serverdata.clients[pbid]["spamCount"]
        if now - serverdata.clients[pbid]["lastJoin"] < 15:
            rejoinCount += 1
            if rejoinCount > 2:
                _ba.screenmessage("Joining too fast , slow down dude",
                                  color=(1, 0, 1),
                                  transient=True,
                                  clients=[clid])
                logger.log(pbid + "|| kicked for joining too fast")
                _ba.disconnect_client(clid)

                _thread.start_new_thread(reportSpam, (pbid, ))

                return
        else:
            rejoinCount = 0

        serverdata.clients[pbid]["rejoincount"] = rejoinCount
        serverdata.clients[pbid]["lastJoin"] = now

    if player_data != None:
        device_strin = ""
        if player_data["isBan"] or get_account_age(
                player_data["accountAge"]) < settings["minAgeToJoinInHours"]:
            for ros in _ba.get_game_roster():
                if ros['account_id'] == pbid:
                    if not player_data["isBan"]:
                        _ba.screenmessage(
                            "New Accounts not allowed here , come back later",
                            color=(1, 0, 0),
                            transient=True,
                            clients=[ros['client_id']])
                    logger.log(pbid + " | kicked > reason:Banned account")
                    _ba.disconnect_client(ros['client_id'])

            return
        else:
            if pbid not in serverdata.clients:
                serverdata.clients[pbid] = player_data
                serverdata.clients[pbid]["warnCount"] = 0
                serverdata.clients[pbid]["lastWarned"] = time.time()
                serverdata.clients[pbid]["verified"] = False
                serverdata.clients[pbid]["rejoincount"] = 1
                serverdata.clients[pbid]["lastJoin"] = time.time()
                if not player_data["canStartKickVote"]:
                    _ba.disable_kickvote(pbid)

            verify_account(pbid, player_data)
            cid = 113
            d_st = "xx"
            for ros in _ba.get_game_roster():
                if ros['account_id'] == pbid:
                    cid = ros['client_id']
                    d_st = ros['display_string']
            _ba.screenmessage(settings["regularWelcomeMsg"] + " " + d_st,
                              color=(0.60, 0.8, 0.6),
                              transient=True,
                              clients=[cid])

    else:

        d_string = ""
        cid = 113
        for ros in _ba.get_game_roster():
            if ros['account_id'] == pbid:
                d_string = ros['display_string']
                cid = ros['client_id']

        thread = FetchThread(target=my_acc_age,
                             callback=save_age,
                             pb_id=pbid,
                             display_string=d_string)

        thread.start()
        _ba.screenmessage(settings["firstTimeJoinMsg"],
                          color=(0.6, 0.8, 0.6),
                          transient=True,
                          clients=[cid])
Пример #10
0
def kick_by_pb_id(pb_id, msg):
    for ros in _ba.get_game_roster():
        if ros['account_id'] == pb_id:
            _ba.screenmessage(msg, transient=True, clients=[ros['client_id']])
            _ba.disconnect_client(ros['client_id'])
Пример #11
0
    def _add_chosen_player(self, chooser: ba.Chooser) -> ba.Player:
        # pylint: disable=too-many-statements
        # pylint: disable=too-many-branches
        from ba import _error
        from ba._lang import Lstr
        from ba._team import Team
        from ba import _freeforallsession
        player = chooser.getplayer()
        if player not in self.players:
            _error.print_error('player not found in session '
                               'player-list after chooser selection')

        activity = self._activity_weak()
        assert activity is not None

        # We need to reset the player's input here, as it is currently
        # referencing the chooser which could inadvertently keep it alive.
        player.reset_input()

        # Pass it to the current activity if it has already begun
        # (otherwise it'll get passed once begin is called).
        pass_to_activity = (activity.has_begun()
                            and not activity.is_joining_activity)

        # If we're not allowing mid-game joins, don't pass; just announce
        # the arrival.
        if pass_to_activity:
            if not self._allow_mid_activity_joins:
                pass_to_activity = False
                with _ba.Context(self):
                    _ba.screenmessage(Lstr(resource='playerDelayedJoinText',
                                           subs=[('${PLAYER}',
                                                  player.get_name(full=True))
                                                 ]),
                                      color=(0, 1, 0))

        # If we're a non-team game, each player gets their own team
        # (keeps mini-game coding simpler if we can always deal with teams).
        if self._use_teams:
            team = chooser.get_team()
        else:
            our_team_id = self._next_team_id
            team = Team(team_id=our_team_id,
                        name=chooser.getplayer().get_name(full=True,
                                                          icon=False),
                        color=chooser.get_color())
            self.teams.append(team)
            self._next_team_id += 1
            try:
                with _ba.Context(self):
                    self.on_team_join(team)
            except Exception:
                _error.print_exception(f'exception in on_team_join for {self}')

            if pass_to_activity:
                if team in activity.teams:
                    _error.print_error(
                        "Duplicate team ID in ba.Session._add_chosen_player")
                activity.teams.append(team)
                try:
                    with _ba.Context(activity):
                        activity.on_team_join(team)
                except Exception:
                    _error.print_exception(
                        f'ERROR: exception in on_team_join for {activity}')

        player.set_data(team=team,
                        character=chooser.get_character_name(),
                        color=chooser.get_color(),
                        highlight=chooser.get_highlight())

        self.stats.register_player(player)
        if pass_to_activity:
            if isinstance(self, _freeforallsession.FreeForAllSession):
                if player.team.players:
                    _error.print_error("expected 0 players in FFA team")

            # Don't actually add the player to their team list if we're not
            # in an activity. (players get (re)added to their team lists
            # when the activity begins).
            player.team.players.append(player)
            if player in activity.players:
                _error.print_exception(
                    f'Dup player in ba.Session._add_chosen_player: {player}')
            else:
                activity.players.append(player)
                player.set_activity(activity)
                pnode = activity.create_player_node(player)
                player.set_node(pnode)
                try:
                    with _ba.Context(activity):
                        activity.on_player_join(player)
                except Exception:
                    _error.print_exception(
                        f'Error on on_player_join for {activity}')
        return player
Пример #12
0
    def on_player_leave(self, player: ba.Player) -> None:
        """Called when a previously-accepted ba.Player leaves the session."""
        # pylint: disable=too-many-statements
        # pylint: disable=too-many-branches
        # pylint: disable=cyclic-import
        from ba._freeforallsession import FreeForAllSession
        from ba._lang import Lstr
        from ba import _error

        # Remove them from the game rosters.
        if player in self.players:

            _ba.playsound(_ba.getsound('playerLeft'))

            team: Optional[ba.Team]

            # The player will have no team if they are still in the lobby.
            try:
                team = player.team
            except _error.TeamNotFoundError:
                team = None

            activity = self._activity_weak()

            # If he had no team, he's in the lobby.
            # If we have a current activity with a lobby, ask them to
            # remove him.
            if team is None:
                with _ba.Context(self):
                    try:
                        self.lobby.remove_chooser(player)
                    except Exception:
                        _error.print_exception(
                            'Error in Lobby.remove_chooser()')

            # *If* they were actually in the game, announce their departure.
            if team is not None:
                _ba.screenmessage(
                    Lstr(resource='playerLeftText',
                         subs=[('${PLAYER}', player.get_name(full=True))]))

            # Remove him from his team and session lists.
            # (he may not be on the team list since player are re-added to
            # team lists every activity)
            if team is not None and player in team.players:

                # Testing; can remove this eventually.
                if isinstance(self, FreeForAllSession):
                    if len(team.players) != 1:
                        _error.print_error("expected 1 player in FFA team")
                team.players.remove(player)

            # Remove player from any current activity.
            if activity is not None and player in activity.players:
                activity.players.remove(player)

                # Run the activity callback unless its been expired.
                if not activity.is_expired():
                    try:
                        with _ba.Context(activity):
                            activity.on_player_leave(player)
                    except Exception:
                        _error.print_exception(
                            'exception in on_player_leave for activity',
                            activity)
                else:
                    _error.print_error("expired activity in on_player_leave;"
                                       " shouldn't happen")

                player.set_activity(None)
                player.set_node(None)

                # Reset the player; this will remove its actor-ref and clear
                # its calls/etc
                try:
                    with _ba.Context(activity):
                        player.reset()
                except Exception:
                    _error.print_exception(
                        'exception in player.reset in'
                        ' on_player_leave for player', player)

            # If we're a non-team session, remove the player's team completely.
            if not self._use_teams and team is not None:

                # If the team's in an activity, call its on_team_leave
                # callback.
                if activity is not None and team in activity.teams:
                    activity.teams.remove(team)

                    if not activity.is_expired():
                        try:
                            with _ba.Context(activity):
                                activity.on_team_leave(team)
                        except Exception:
                            _error.print_exception(
                                'exception in on_team_leave for activity',
                                activity)
                    else:
                        _error.print_error(
                            "expired activity in on_player_leave p2"
                            "; shouldn't happen")

                    # Clear the team's game-data (so dying stuff will
                    # have proper context).
                    try:
                        with _ba.Context(activity):
                            team.reset_gamedata()
                    except Exception:
                        _error.print_exception(
                            'exception clearing gamedata for team:', team,
                            'for player:', player, 'in activity:', activity)

                # Remove the team from the session.
                self.teams.remove(team)
                try:
                    with _ba.Context(self):
                        self.on_team_leave(team)
                except Exception:
                    _error.print_exception(
                        'exception in on_team_leave for session', self)

                # Clear the team's session-data (so dying stuff will
                # have proper context).
                try:
                    with _ba.Context(self):
                        team.reset_sessiondata()
                except Exception:
                    _error.print_exception(
                        'exception clearing sessiondata for team:', team,
                        'in session:', self)

            # Now remove them from the session list.
            self.players.remove(player)

        else:
            print('ERROR: Session.on_player_leave called'
                  ' for player not in our list.')
def broadCastShiftMsg(pb_id):
	for ros in _ba.get_game_roster():
		if ros['account_id']==pb_id:
			_ba.screenmessage("Shifted "+ros["display_string"]+" to balance team")
Пример #14
0
def connecting_to_party_message() -> None:
    from ba._lang import Lstr
    _ba.screenmessage(Lstr(resource='internal.connectingToPartyText'),
                      color=(1, 1, 1))
Пример #15
0
def gear_vr_controller_warning() -> None:
    from ba._lang import Lstr
    _ba.playsound(_ba.getsound('error'))
    _ba.screenmessage(Lstr(resource='usesExternalControllerText'),
                      color=(1, 0, 0))
Пример #16
0
def rejecting_invite_already_in_party_message() -> None:
    from ba._lang import Lstr
    _ba.screenmessage(
        Lstr(resource='internal.rejectingInviteAlreadyInPartyText'),
        color=(1, 0.5, 0))
Пример #17
0
def orientation_reset_message() -> None:
    from ba._lang import Lstr
    _ba.screenmessage(Lstr(resource='internal.vrOrientationResetText'),
                      color=(0, 1, 0))
Пример #18
0
def temporarily_unavailable_message() -> None:
    from ba._lang import Lstr
    _ba.playsound(_ba.getsound('error'))
    _ba.screenmessage(
        Lstr(resource='getTicketsWindow.unavailableTemporarilyText'),
        color=(1, 0, 0))
Пример #19
0
def purchases_restored_message() -> None:
    from ba._lang import Lstr
    _ba.screenmessage(Lstr(resource='getTicketsWindow.purchasesRestoredText'),
                      color=(0, 1, 0))
Пример #20
0
def error_message() -> None:
    from ba._lang import Lstr
    _ba.playsound(_ba.getsound('error'))
    _ba.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
Пример #21
0
def unavailable_message() -> None:
    from ba._lang import Lstr
    _ba.screenmessage(Lstr(resource='getTicketsWindow.unavailableText'),
                      color=(1, 0, 0))
Пример #22
0
    def handle_scan_results(self, results: ScanResults) -> None:
        """Called in the game thread with results of a completed scan."""

        from ba._language import Lstr
        from ba._plugin import PotentialPlugin

        # Warnings generally only get printed locally for users' benefit
        # (things like out-of-date scripts being ignored, etc.)
        # Errors are more serious and will get included in the regular log
        # warnings = results.get('warnings', '')
        # errors = results.get('errors', '')
        if results.warnings != '' or results.errors != '':
            import textwrap
            _ba.screenmessage(Lstr(resource='scanScriptsErrorText'),
                              color=(1, 0, 0))
            _ba.playsound(_ba.getsound('error'))
            if results.warnings != '':
                _ba.log(textwrap.indent(results.warnings,
                                        'Warning (meta-scan): '),
                        to_server=False)
            if results.errors != '':
                _ba.log(textwrap.indent(results.errors, 'Error (meta-scan): '))

        # Handle plugins.
        plugs = _ba.app.plugins
        config_changed = False
        found_new = False
        plugstates: dict[str, dict] = _ba.app.config.setdefault('Plugins', {})
        assert isinstance(plugstates, dict)

        # Create a potential-plugin for each class we found in the scan.
        for class_path in results.plugins:
            plugs.potential_plugins.append(
                PotentialPlugin(display_name=Lstr(value=class_path),
                                class_path=class_path,
                                available=True))
            if class_path not in plugstates:
                if _ba.app.headless_mode:
                    # If we running in headless mode, enable plugin by default
                    # to allow server admins to get their modified build
                    # working 'out-of-the-box', without manually updating the
                    # config.
                    plugstates[class_path] = {'enabled': True}
                else:
                    # If we running in normal mode, disable plugin by default
                    # (user can enable it later).
                    plugstates[class_path] = {'enabled': False}
                config_changed = True
                found_new = True

        # Also add a special one for any plugins set to load but *not* found
        # in the scan (this way they will show up in the UI so we can disable
        # them)
        for class_path, plugstate in plugstates.items():
            enabled = plugstate.get('enabled', False)
            assert isinstance(enabled, bool)
            if enabled and class_path not in results.plugins:
                plugs.potential_plugins.append(
                    PotentialPlugin(display_name=Lstr(value=class_path),
                                    class_path=class_path,
                                    available=False))

        plugs.potential_plugins.sort(key=lambda p: p.class_path)

        if found_new:
            _ba.screenmessage(Lstr(resource='pluginsDetectedText'),
                              color=(0, 1, 0))
            _ba.playsound(_ba.getsound('ding'))

        if config_changed:
            _ba.app.config.commit()
Пример #23
0
def no_game_circle_message() -> None:
    from ba._lang import Lstr
    _ba.screenmessage(Lstr(resource='noGameCircleText'), color=(1, 0, 0))
Пример #24
0
def run_gpu_benchmark() -> None:
    """Kick off a benchmark to test gpu speeds."""
    _ba.screenmessage('FIXME: Not wired up yet.', color=(1, 0, 0))
Пример #25
0
def ui_remote_press() -> None:
    """Handle a press by a remote device that is only usable for nav."""
    from ba._lang import Lstr
    _ba.screenmessage(Lstr(resource='internal.controllerForMenusOnlyText'),
                      color=(1, 0, 0))
    _ba.playsound(_ba.getsound('error'))
def send(msg, clientid):
    """Shortcut To Send Private Msg To Client"""

    _ba.chatmessage(str(msg), clients=[clientid])
    _ba.screenmessage(str(msg), transient=True, clients=[clientid])
Пример #27
0
def not_signed_in_screen_message() -> None:
    from ba._lang import Lstr
    _ba.screenmessage(Lstr(resource='notSignedInErrorText'))
Пример #28
0
def purchase_already_in_progress_error() -> None:
    from ba._language import Lstr
    _ba.playsound(_ba.getsound('error'))
    _ba.screenmessage(Lstr(resource='store.purchaseAlreadyInProgressText'),
                      color=(1, 0, 0))
Пример #29
0
    def on_app_launch(self) -> None:
        """Runs after the app finishes bootstrapping.

        (internal)"""
        # pylint: disable=too-many-locals
        # pylint: disable=cyclic-import
        from ba import _apputils
        from ba import _appconfig
        from ba import _achievement
        from ba import _map
        from ba import _campaign
        from bastd import appdelegate
        from bastd import maps as stdmaps
        from bastd.actor import spazappearance
        from ba._generated.enums import TimeType

        cfg = self.config

        self.delegate = appdelegate.AppDelegate()

        self.ui.on_app_launch()

        spazappearance.register_appearances()
        _campaign.init_campaigns()

        # FIXME: This should not be hard-coded.
        for maptype in [
                stdmaps.HockeyStadium, stdmaps.FootballStadium,
                stdmaps.Bridgit, stdmaps.BigG, stdmaps.Roundabout,
                stdmaps.MonkeyFace, stdmaps.ZigZag, stdmaps.ThePad,
                stdmaps.DoomShroom, stdmaps.LakeFrigid, stdmaps.TipTop,
                stdmaps.CragCastle, stdmaps.TowerD, stdmaps.HappyThoughts,
                stdmaps.StepRightUp, stdmaps.Courtyard, stdmaps.Rampage
        ]:
            _map.register_map(maptype)

        # Non-test, non-debug builds should generally be blessed; warn if not.
        # (so I don't accidentally release a build that can't play tourneys)
        if (not self.debug_build and not self.test_build
                and not _ba.is_blessed()):
            _ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0))

        # If there's a leftover log file, attempt to upload it to the
        # master-server and/or get rid of it.
        _apputils.handle_leftover_log_file()

        # Only do this stuff if our config file is healthy so we don't
        # overwrite a broken one or whatnot and wipe out data.
        if not self.config_file_healthy:
            if self.platform in ('mac', 'linux', 'windows'):
                from bastd.ui import configerror
                configerror.ConfigErrorWindow()
                return

            # For now on other systems we just overwrite the bum config.
            # At this point settings are already set; lets just commit them
            # to disk.
            _appconfig.commit_app_config(force=True)

        self.music.on_app_launch()

        launch_count = cfg.get('launchCount', 0)
        launch_count += 1

        # So we know how many times we've run the game at various
        # version milestones.
        for key in ('lc14173', 'lc14292'):
            cfg.setdefault(key, launch_count)

        cfg['launchCount'] = launch_count
        cfg.commit()

        # Run a test in a few seconds to see if we should pop up an existing
        # pending special offer.
        def check_special_offer() -> None:
            from bastd.ui.specialoffer import show_offer
            config = self.config
            if ('pendingSpecialOffer' in config and _ba.get_public_login_id()
                    == config['pendingSpecialOffer']['a']):
                self.special_offer = config['pendingSpecialOffer']['o']
                show_offer()

        if not self.headless_mode:
            _ba.timer(3.0, check_special_offer, timetype=TimeType.REAL)

        self.meta.on_app_launch()
        self.accounts.on_app_launch()
        self.plugins.on_app_launch()

        # See note below in on_app_pause.
        if self.state != self.State.LAUNCHING:
            logging.error('on_app_launch found state %s; expected LAUNCHING.',
                          self.state)

        self._app_launched = True
        self._update_state()

        # from ba._dependency import test_depset
        # test_depset()
        if bool(False):
            self._test_https()