diff --git a/src/assets/ba_data/python/bascenev1/_coopsession.py b/src/assets/ba_data/python/bascenev1/_coopsession.py index f1d59ae4..a68a72c4 100644 --- a/src/assets/ba_data/python/bascenev1/_coopsession.py +++ b/src/assets/ba_data/python/bascenev1/_coopsession.py @@ -61,6 +61,10 @@ class CoopSession(Session): max_players = classic.coop_session_args['max_players'] else: max_players = app.config.get('Coop Game Max Players', 4) + if 'submit_score' in classic.coop_session_args: + submit_score = classic.coop_session_args['submit_score'] + else: + submit_score = True # print('FIXME: COOP SESSION WOULD CALC DEPS.') depsets: Sequence[bascenev1.DependencySet] = [] @@ -71,6 +75,7 @@ class CoopSession(Session): team_colors=TEAM_COLORS, min_players=min_players, max_players=max_players, + submit_score=submit_score, ) # Tournament-ID if we correspond to a co-op tournament (otherwise None) @@ -346,7 +351,10 @@ class CoopSession(Session): self.setactivity(next_game) if not (env.demo or env.arcade): - if self.tournament_id is not None: + if ( + self.tournament_id is not None + and classic.coop_session_args['submit_score'] + ): self._custom_menu_ui = [ { 'label': babase.Lstr(resource='restartText'), diff --git a/src/assets/ba_data/python/bascenev1/_session.py b/src/assets/ba_data/python/bascenev1/_session.py index 9acad485..dd757346 100644 --- a/src/assets/ba_data/python/bascenev1/_session.py +++ b/src/assets/ba_data/python/bascenev1/_session.py @@ -100,6 +100,7 @@ class Session: team_colors: Sequence[Sequence[float]] | None = None, min_players: int = 1, max_players: int = 8, + submit_score: bool = True, ): """Instantiate a session. @@ -175,6 +176,7 @@ class Session: if _max_players_override is None else _max_players_override ) + self.submit_score = submit_score self.customdata = {} self._in_set_activity = False diff --git a/src/assets/ba_data/python/bascenev1lib/activity/coopscore.py b/src/assets/ba_data/python/bascenev1lib/activity/coopscore.py index 12ffc3ad..86cabfc6 100644 --- a/src/assets/ba_data/python/bascenev1lib/activity/coopscore.py +++ b/src/assets/ba_data/python/bascenev1lib/activity/coopscore.py @@ -125,6 +125,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]): self._tournament_time_remaining: float | None = None self._tournament_time_remaining_text: Text | None = None self._tournament_time_remaining_text_timer: bs.BaseTimer | None = None + self._submit_score = self.session.submit_score # Stuff for activity skip by pressing button self._birth_time = bs.time() @@ -789,7 +790,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]): transition_delay=2.0, ) - if self._score is not None: + if self._score is not None and self._submit_score: bs.timer(0.4, bs.WeakCall(self._play_drumroll)) # Add us to high scores, filter, and store. @@ -1396,7 +1397,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]): assert self._show_info is not None available = self._show_info['results'] is not None - if available: + if available and self._submit_score: error = ( self._show_info['results']['error'] if 'error' in self._show_info['results'] @@ -1529,7 +1530,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]): maxwidth=400, transition_delay=1.0, ).autoretain() - else: + elif self._submit_score: ZoomText( ( ('#' + str(player_rank)) @@ -1752,9 +1753,10 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]): transition_delay=0, ).autoretain() - bs.timer(0.35, self._score_display_sound.play) - if not error: - bs.timer(0.35, self.cymbal_sound.play) + if self._submit_score: + bs.timer(0.35, self._score_display_sound.play) + if not error: + bs.timer(0.35, self.cymbal_sound.play) def _show_fail(self) -> None: ZoomText( diff --git a/src/assets/ba_data/python/bauiv1lib/tournamententry.py b/src/assets/ba_data/python/bauiv1lib/tournamententry.py index 34c863c5..7c7a1206 100644 --- a/src/assets/ba_data/python/bauiv1lib/tournamententry.py +++ b/src/assets/ba_data/python/bauiv1lib/tournamententry.py @@ -14,7 +14,6 @@ import bauiv1 as bui if TYPE_CHECKING: from typing import Any, Callable - import bascenev1 as bs @@ -32,6 +31,7 @@ class TournamentEntryWindow(PopupWindow): on_close_call: Callable[[], Any] | None = None, ): # Needs some tidying. + # pylint: disable=too-many-locals # pylint: disable=too-many-branches # pylint: disable=too-many-statements @@ -80,11 +80,21 @@ class TournamentEntryWindow(PopupWindow): self._tournament_activity = tournament_activity - self._width = 340 - self._height = 225 + self._width: float = 340.0 + self._height: float = 225.0 bg_color = (0.5, 0.4, 0.6) + # Show the practice button as long as we're not + # restarting while on a paid tournament run. + self._do_practice = ( + self._tournament_activity is None and + bui.app.config.get('tournament_practice_enabled', False) + ) + + off_p = 0 if not self._do_practice else 48 + self._height += off_p * 0.933 + # Creates our root_widget. super().__init__( position=position, @@ -107,7 +117,7 @@ class TournamentEntryWindow(PopupWindow): self._cancel_button = bui.buttonwidget( parent=self.root_widget, - position=(20, self._height - 34), + position=(40, self._height - 34), size=(60, 60), scale=0.5, label='', @@ -132,15 +142,15 @@ class TournamentEntryWindow(PopupWindow): btn = self._pay_with_tickets_button = bui.buttonwidget( parent=self.root_widget, - position=(30 + x_offs, 60), + position=(30 + x_offs, 60 + off_p), autoselect=True, button_type='square', size=(120, 120), label='', on_activate_call=self._on_pay_with_tickets_press, ) - self._ticket_img_pos = (50 + x_offs, 94) - self._ticket_img_pos_free = (50 + x_offs, 80) + self._ticket_img_pos = (50 + x_offs, 94 + off_p) + self._ticket_img_pos_free = (50 + x_offs, 80 + off_p) self._ticket_img = bui.imagewidget( parent=self.root_widget, draw_controller=btn, @@ -148,8 +158,8 @@ class TournamentEntryWindow(PopupWindow): position=self._ticket_img_pos, texture=bui.gettexture('tickets'), ) - self._ticket_cost_text_position = (87 + x_offs, 88) - self._ticket_cost_text_position_free = (87 + x_offs, 120) + self._ticket_cost_text_position = (87 + x_offs, 88 + off_p) + self._ticket_cost_text_position_free = (87 + x_offs, 120 + off_p) self._ticket_cost_text = bui.textwidget( parent=self.root_widget, draw_controller=btn, @@ -165,7 +175,7 @@ class TournamentEntryWindow(PopupWindow): self._free_plays_remaining_text = bui.textwidget( parent=self.root_widget, draw_controller=btn, - position=(87 + x_offs, 78), + position=(87 + x_offs, 78 + off_p), size=(0, 0), h_align='center', v_align='center', @@ -178,7 +188,7 @@ class TournamentEntryWindow(PopupWindow): if self._do_ad_btn: btn = self._pay_with_ad_btn = bui.buttonwidget( parent=self.root_widget, - position=(190, 60), + position=(190, 60 + off_p), autoselect=True, button_type='square', size=(120, 120), @@ -189,12 +199,12 @@ class TournamentEntryWindow(PopupWindow): parent=self.root_widget, draw_controller=btn, size=(80, 80), - position=(210, 94), + position=(210, 94 + off_p), texture=bui.gettexture('tv'), ) - self._ad_text_position = (251, 88) - self._ad_text_position_remaining = (251, 92) + self._ad_text_position = (251, 88 + off_p) + self._ad_text_position_remaining = (251, 92 + off_p) have_ad_tries_remaining = ( self._tournament_info['adTriesRemaining'] is not None ) @@ -224,7 +234,7 @@ class TournamentEntryWindow(PopupWindow): self._ad_plays_remaining_text = bui.textwidget( parent=self.root_widget, draw_controller=btn, - position=(251, 78), + position=(251, 78 + off_p), size=(0, 0), h_align='center', v_align='center', @@ -236,7 +246,7 @@ class TournamentEntryWindow(PopupWindow): bui.textwidget( parent=self.root_widget, - position=(self._width * 0.5, 120), + position=(self._width * 0.5, 120 + off_p), size=(0, 0), h_align='center', v_align='center', @@ -250,13 +260,26 @@ class TournamentEntryWindow(PopupWindow): else: self._pay_with_ad_btn = None + btn_size = (150, 45) + btn_pos = (self._width / 2 - btn_size[0] / 2, self._width / 2 - 110) + self._practice_button = None + if self._do_practice: + self._practice_button = bui.buttonwidget( + parent=self.root_widget, + position=btn_pos, + autoselect=True, + size=btn_size, + label=bui.Lstr(resource='practiceText'), + on_activate_call=self._on_practice_press, + ) + self._get_tickets_button: bui.Widget | None = None self._ticket_count_text: bui.Widget | None = None if not bui.app.ui_v1.use_toolbars: if bui.app.classic.allow_ticket_purchases: self._get_tickets_button = bui.buttonwidget( parent=self.root_widget, - position=(self._width - 190 + 125, self._height - 34), + position=(self._width - 190 + 105, self._height - 34), autoselect=True, scale=0.5, size=(120, 60), @@ -372,6 +395,8 @@ class TournamentEntryWindow(PopupWindow): sel = self.root_widget.get_selected_child() if sel == self._pay_with_ad_btn: sel_name = 'Ad' + elif sel == self._practice_button: + sel_name = 'Practice' else: sel_name = 'Tickets' cfg = bui.app.config @@ -382,6 +407,8 @@ class TournamentEntryWindow(PopupWindow): sel_name = bui.app.config.get('Tournament Pay Selection', 'Tickets') if sel_name == 'Ad' and self._pay_with_ad_btn is not None: sel = self._pay_with_ad_btn + elif sel_name == 'Practice' and self._practice_button is not None: + sel = self._practice_button else: sel = self._pay_with_tickets_button bui.containerwidget(edit=self.root_widget, selected_child=sel) @@ -537,29 +564,37 @@ class TournamentEntryWindow(PopupWindow): text=bui.charstr(bui.SpecialChar.TICKET) + t_str, ) - def _launch(self) -> None: + def _launch(self, practice: bool = False) -> None: assert bui.app.classic is not 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: + # If they gave us an existing, non-consistent + # practice activity, just restart it. + if ( + self._tournament_activity is not None + and not practice == self._tournament_activity.session.submit_score + ): try: - bui.apptimer(0.1, bui.getsound('cashRegister').play) + if not practice: + bui.apptimer(0.1, bui.getsound('cashRegister').play) + bui.screenmessage( + bui.Lstr( + translate=( + 'serverResponses', + 'Entering tournament...', + ) + ), + color=(0, 1, 0), + ) + bui.apptimer(0 if practice else 0.3, self._transition_out) + launched = True with self._tournament_activity.context: self._tournament_activity.end( {'outcome': 'restart'}, force=True ) - bui.apptimer(0.3, self._transition_out) - launched = True - bui.screenmessage( - bui.Lstr( - translate=('serverResponses', 'Entering tournament...') - ), - color=(0, 1, 0), - ) # We can hit exceptions here if _tournament_activity ends before # our restart attempt happens. @@ -572,29 +607,28 @@ class TournamentEntryWindow(PopupWindow): # If we had no existing activity (or were unable to restart it) # launch a new session. if not launched: - bui.apptimer(0.1, bui.getsound('cashRegister').play) + if not practice: + bui.apptimer(0.1, bui.getsound('cashRegister').play) + bui.screenmessage( + bui.Lstr( + translate=('serverResponses', 'Entering tournament...') + ), + color=(0, 1, 0), + ) bui.apptimer( - 1.0, - lambda: ( - bui.app.classic.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, - }, - ) - if bui.app.classic is not None - else None - ), - ) - bui.apptimer(0.7, self._transition_out) - bui.screenmessage( - bui.Lstr( - translate=('serverResponses', 'Entering tournament...') - ), - color=(0, 1, 0), + 0 if practice else 1.0, + lambda: bui.app.classic.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, + 'submit_score': not practice, + }, + ) if bui.app.classic is not None + else None ) + bui.apptimer(0 if practice else 1.25, self._transition_out) def _on_pay_with_tickets_press(self) -> None: from bauiv1lib import getcurrency @@ -691,6 +725,25 @@ class TournamentEntryWindow(PopupWindow): on_completion_call=bui.WeakCall(self._on_ad_complete), ) + def _on_practice_press(self) -> None: + plus = bui.app.plus + assert plus is not None + + # If we're already entering, ignore. + if self._entering: + return + + # Deny if it looks like the tourney has ended. + if self._seconds_remaining == 0: + bui.screenmessage( + bui.Lstr(resource='tournamentEndedText'), color=(1, 0, 0) + ) + bui.getsound('error').play() + return + + self._entering = True + self._launch(practice=True) + def _on_ad_complete(self, actually_showed: bool) -> None: plus = bui.app.plus assert plus is not None