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
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
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
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))
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))
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
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))
def connection_failed_message() -> None: from ba._lang import Lstr _ba.screenmessage(Lstr(resource='internal.connectionFailedText'), color=(1, 0.5, 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])
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'])
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
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")
def connecting_to_party_message() -> None: from ba._lang import Lstr _ba.screenmessage(Lstr(resource='internal.connectingToPartyText'), color=(1, 1, 1))
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))
def rejecting_invite_already_in_party_message() -> None: from ba._lang import Lstr _ba.screenmessage( Lstr(resource='internal.rejectingInviteAlreadyInPartyText'), color=(1, 0.5, 0))
def orientation_reset_message() -> None: from ba._lang import Lstr _ba.screenmessage(Lstr(resource='internal.vrOrientationResetText'), color=(0, 1, 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))
def purchases_restored_message() -> None: from ba._lang import Lstr _ba.screenmessage(Lstr(resource='getTicketsWindow.purchasesRestoredText'), color=(0, 1, 0))
def error_message() -> None: from ba._lang import Lstr _ba.playsound(_ba.getsound('error')) _ba.screenmessage(Lstr(resource='errorText'), color=(1, 0, 0))
def unavailable_message() -> None: from ba._lang import Lstr _ba.screenmessage(Lstr(resource='getTicketsWindow.unavailableText'), color=(1, 0, 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()
def no_game_circle_message() -> None: from ba._lang import Lstr _ba.screenmessage(Lstr(resource='noGameCircleText'), color=(1, 0, 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))
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])
def not_signed_in_screen_message() -> None: from ba._lang import Lstr _ba.screenmessage(Lstr(resource='notSignedInErrorText'))
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))
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()