Source code for bauiv1lib.coop.tournamentbutton

# Released under the MIT License. See LICENSE for details.
#
"""Defines button for co-op games."""

from __future__ import annotations

from typing import TYPE_CHECKING
import copy

import bauiv1 as bui

if TYPE_CHECKING:
    from typing import Any, Callable

# As of 1.7.37, no longer charging entry fees for tourneys (tourneys now
# reward chests and the game now makes its money from tokens/ads used to
# speed up chest openings).
USE_ENTRY_FEES = False


[docs] class TournamentButton: """Button showing a tournament in coop window.""" def __init__( self, parent: bui.Widget, x: float, y: float, select: bool, on_pressed: Callable[[TournamentButton], None], ) -> None: # pylint: disable=too-many-positional-arguments # pylint: disable=too-many-statements self._r = 'coopSelectWindow' sclx = 300 scly = 195.0 self.on_pressed = on_pressed self.lsbt = bui.getmesh('level_select_button_transparent') self.lsbo = bui.getmesh('level_select_button_opaque') self.allow_ads = False self.tournament_id: str | None = None self.game: str | None = None self.time_remaining: int = 0 self.has_time_remaining: bool = False self.leader: Any = None self.required_league: str | None = None self._base_x_offs = 0 if USE_ENTRY_FEES else -45.0 self.button = btn = bui.buttonwidget( parent=parent, position=(x + 23, y + 4), size=(sclx, scly), label='', button_type='square', autoselect=True, on_activate_call=bui.WeakCall(self._pressed), ) bui.widget( edit=btn, show_buffer_bottom=50, show_buffer_top=50, show_buffer_left=400, show_buffer_right=200, ) if select: bui.containerwidget( edit=parent, selected_child=btn, visible_child=btn ) image_width = sclx * 0.85 * 0.75 self.image = bui.imagewidget( parent=parent, draw_controller=btn, position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150), size=(image_width, image_width * 0.5), mesh_transparent=self.lsbt, mesh_opaque=self.lsbo, texture=bui.gettexture('black'), opacity=0.2, mask_texture=bui.gettexture('mapPreviewMask'), ) self.lock_image = bui.imagewidget( parent=parent, draw_controller=btn, position=(x + 21 + sclx * 0.5 - image_width * 0.15, y + scly - 130), size=(image_width * 0.3, image_width * 0.3), texture=bui.gettexture('lock'), opacity=0.0, ) self.button_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 20 + sclx * 0.5, y + scly - 35), size=(0, 0), h_align='center', text='-', v_align='center', maxwidth=sclx * 0.76, scale=0.85, color=(0.8, 1.0, 0.8, 1.0), ) header_color = (0.43, 0.4, 0.5, 1) value_color = (0.6, 0.6, 0.6, 1) x_offs = self._base_x_offs # No longer using entry fees. if USE_ENTRY_FEES: bui.textwidget( parent=parent, draw_controller=btn, position=(x + 360, y + scly - 20), size=(0, 0), h_align='center', text=bui.Lstr(resource=f'{self._r}.entryFeeText'), v_align='center', maxwidth=100, scale=0.9, color=header_color, flatness=1.0, ) self.entry_fee_text_top = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 360, y + scly - 60), size=(0, 0), h_align='center', text='-', v_align='center', maxwidth=60, scale=1.3, color=value_color, flatness=1.0, ) self.entry_fee_text_or = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 360, y + scly - 90), size=(0, 0), h_align='center', text='', v_align='center', maxwidth=60, scale=0.5, color=value_color, flatness=1.0, ) self.entry_fee_text_remaining = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 360, y + scly - 90), size=(0, 0), h_align='center', text='', v_align='center', maxwidth=60, scale=0.5, color=value_color, flatness=1.0, ) self.entry_fee_ad_image = bui.imagewidget( parent=parent, size=(40, 40), draw_controller=btn, position=(x + 360 - 20, y + scly - 140), opacity=0.0, texture=bui.gettexture('tv'), ) x_offs += 50 bui.textwidget( parent=parent, draw_controller=btn, position=(x + 447 + x_offs, y + scly - 20), size=(0, 0), h_align='center', text=bui.Lstr(resource=f'{self._r}.prizesText'), v_align='center', maxwidth=130, scale=0.9, color=header_color, flatness=1.0, ) self.button_x = x self.button_y = y self.button_scale_y = scly # Offset for prize range/values. xo2 = 0.0 self.prize_range_1_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 355 + xo2 + x_offs, y + scly - 93), size=(0, 0), h_align='right', v_align='center', maxwidth=50, text='', scale=0.8, color=header_color, flatness=1.0, ) self.prize_value_1_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 380 + xo2 + x_offs, y + scly - 93), size=(0, 0), h_align='left', text='', v_align='center', maxwidth=100, color=value_color, flatness=1.0, ) self._chestsz = 50 self.prize_chest_1_image = bui.imagewidget( parent=parent, draw_controller=btn, texture=bui.gettexture('white'), position=(x + 380 + xo2 + x_offs, y + scly - 93), size=(self._chestsz, self._chestsz), opacity=0.0, ) self.prize_range_2_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 355 + xo2 + x_offs, y + scly - 93), size=(0, 0), h_align='right', text='', v_align='center', maxwidth=50, scale=0.8, color=header_color, flatness=1.0, ) self.prize_value_2_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 380 + xo2 + x_offs, y + scly - 93), size=(0, 0), h_align='left', text='', v_align='center', maxwidth=100, color=value_color, flatness=1.0, ) self.prize_chest_2_image = bui.imagewidget( parent=parent, draw_controller=btn, texture=bui.gettexture('white'), position=(x + 380 + xo2 + x_offs, y + scly - 93), size=(self._chestsz, self._chestsz), opacity=0.0, ) self.prize_range_3_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 355 + xo2 + x_offs, y + scly - 93), size=(0, 0), h_align='right', text='', v_align='center', maxwidth=50, scale=0.8, color=header_color, flatness=1.0, ) self.prize_value_3_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 380 + xo2 + x_offs, y + scly - 93), size=(0, 0), h_align='left', text='', v_align='center', maxwidth=100, color=value_color, flatness=1.0, ) self.prize_chest_3_image = bui.imagewidget( parent=parent, draw_controller=btn, texture=bui.gettexture('white'), position=(x + 380 + xo2 + x_offs, y + scly - 93), size=(self._chestsz, self._chestsz), opacity=0.0, ) bui.textwidget( parent=parent, draw_controller=btn, position=(x + 625 + x_offs, y + scly - 20), size=(0, 0), h_align='center', text=bui.Lstr(resource=f'{self._r}.currentBestText'), v_align='center', maxwidth=180, scale=0.9, color=header_color, flatness=1.0, ) self.current_leader_name_text = bui.textwidget( parent=parent, draw_controller=btn, position=( x + 625 + x_offs - (170 / 1.4) * 0.5, y + scly - 60 - 40 * 0.5, ), selectable=True, click_activate=True, autoselect=True, on_activate_call=bui.WeakCall(self._show_leader), size=(170 / 1.4, 40), h_align='center', text='-', v_align='center', maxwidth=170, glow_type='uniform', scale=1.4, color=value_color, flatness=1.0, ) self.current_leader_score_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 625 + x_offs, y + scly - 113 + 10), size=(0, 0), h_align='center', text='-', v_align='center', maxwidth=170, scale=1.8, color=value_color, flatness=1.0, ) self.more_scores_button = bui.buttonwidget( parent=parent, position=(x + 625 + x_offs - 60, y + scly - 50 - 125), color=(0.5, 0.5, 0.6), textcolor=(0.7, 0.7, 0.8), label='-', size=(120, 40), autoselect=True, up_widget=self.current_leader_name_text, text_scale=0.6, on_activate_call=bui.WeakCall(self._show_scores), ) bui.widget( edit=self.current_leader_name_text, down_widget=self.more_scores_button, ) bui.textwidget( parent=parent, draw_controller=btn, position=(x + 840 + x_offs, y + scly - 20), size=(0, 0), h_align='center', text=bui.Lstr(resource=f'{self._r}.timeRemainingText'), v_align='center', maxwidth=180, scale=0.9, color=header_color, flatness=1.0, ) self.time_remaining_value_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 840 + x_offs, y + scly - 68), size=(0, 0), h_align='center', text='-', v_align='center', maxwidth=180, scale=2.0, color=value_color, flatness=1.0, ) self.time_remaining_out_of_text = bui.textwidget( parent=parent, draw_controller=btn, position=(x + 840 + x_offs, y + scly - 110), size=(0, 0), h_align='center', text='-', v_align='center', maxwidth=120, scale=0.72, color=(0.4, 0.4, 0.5), flatness=1.0, ) self._lock_update_timer = bui.AppTimer( 1.03, bui.WeakCall(self._update_lock_state), repeat=True ) def _pressed(self) -> None: self.on_pressed(self) def _show_leader(self) -> None: # pylint: disable=cyclic-import from bauiv1lib.account.viewer import AccountViewerWindow tournament_id = self.tournament_id # FIXME: This assumes a single player entry in leader; should expand # this to work with multiple. if ( tournament_id is None or self.leader is None or len(self.leader[2]) != 1 ): bui.getsound('error').play() return bui.getsound('swish').play() AccountViewerWindow( account_id=self.leader[2][0].get('a', None), profile_id=self.leader[2][0].get('p', None), position=self.current_leader_name_text.get_screen_space_center(), ) def _show_scores(self) -> None: # pylint: disable=cyclic-import from bauiv1lib.tournamentscores import TournamentScoresWindow tournament_id = self.tournament_id if tournament_id is None: bui.getsound('error').play() return TournamentScoresWindow( tournament_id=tournament_id, position=self.more_scores_button.get_screen_space_center(), ) def _update_lock_state(self) -> None: if self.game is None: return assert bui.app.classic is not None campaignname, levelname = self.game.split(':') campaign = bui.app.classic.getcampaign(campaignname) enabled = ( self.required_league is None and bui.app.classic.is_game_unlocked(self.game) ) bui.buttonwidget( edit=self.button, color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5), ) bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0) bui.imagewidget( edit=self.image, texture=bui.gettexture( campaign.getlevel(levelname).preview_texture_name ), opacity=1.0 if enabled else 0.5, )
[docs] def update_for_data(self, entry: dict[str, Any]) -> None: """Update for new incoming data.""" # pylint: disable=too-many-statements # pylint: disable=too-many-locals # pylint: disable=too-many-branches plus = bui.app.plus assert plus is not None classic = bui.app.classic assert classic is not None prize_y_offs = ( 34 if 'prizeRange3' in entry else 20 if 'prizeRange2' in entry else 12 ) x_offs = self._base_x_offs + 90 # Special offset for prize ranges/vals. x_offs2 = x_offs - 20.0 # Special offset for prize chests. x_offs2c = x_offs2 + 50 # Fetch prize range and trophy strings. (pr1, pv1, pr2, pv2, pr3, pv3) = classic.get_tournament_prize_strings( entry, include_tickets=False ) self.time_remaining = entry['timeRemaining'] self.has_time_remaining = entry is not None self.tournament_id = entry['tournamentID'] self.required_league = entry.get('requiredLeague') assert bui.app.classic is not None self.game = bui.app.classic.accounts.tournament_info[ self.tournament_id ]['game'] assert isinstance(self.game, str) campaignname, levelname = self.game.split(':') campaign = bui.app.classic.getcampaign(campaignname) self._update_lock_state() bui.textwidget( edit=self.prize_range_1_text, text='-' if pr1 == '' else pr1, position=( self.button_x + 365 + x_offs2, self.button_y + self.button_scale_y - 93 + prize_y_offs, ), ) bui.textwidget( edit=self.prize_value_1_text, text='-' if pv1 == '' else pv1, position=( self.button_x + 380 + x_offs2, self.button_y + self.button_scale_y - 93 + prize_y_offs, ), ) bui.imagewidget( edit=self.prize_chest_1_image, position=( self.button_x + 380 + x_offs2c, self.button_y + self.button_scale_y - 93 + prize_y_offs - 0.5 * self._chestsz, ), ) classic.set_tournament_prize_image(entry, 0, self.prize_chest_1_image) bui.textwidget( edit=self.prize_range_2_text, text=pr2, position=( self.button_x + 365 + x_offs2, self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs, ), ) bui.textwidget( edit=self.prize_value_2_text, text=pv2, position=( self.button_x + 380 + x_offs2, self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs, ), ) bui.imagewidget( edit=self.prize_chest_2_image, position=( self.button_x + 380 + x_offs2c, self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs - 0.5 * self._chestsz, ), ) classic.set_tournament_prize_image(entry, 1, self.prize_chest_2_image) bui.textwidget( edit=self.prize_range_3_text, text=pr3, position=( self.button_x + 365 + x_offs2, self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs, ), ) bui.textwidget( edit=self.prize_value_3_text, text=pv3, position=( self.button_x + 380 + x_offs2, self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs, ), ) bui.imagewidget( edit=self.prize_chest_3_image, position=( self.button_x + 380 + x_offs2c, self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs - 0.5 * self._chestsz, ), ) classic.set_tournament_prize_image(entry, 2, self.prize_chest_3_image) leader_name = '-' leader_score: str | bui.Lstr = '-' if entry['scores']: score = self.leader = copy.deepcopy(entry['scores'][0]) leader_name = score[1] leader_score = ( bui.timestring((score[0] * 10) / 1000.0, centi=True) if entry['scoreType'] == 'time' else str(score[0]) ) else: self.leader = None bui.textwidget( edit=self.current_leader_name_text, text=bui.Lstr(value=leader_name) ) bui.textwidget(edit=self.current_leader_score_text, text=leader_score) bui.buttonwidget( edit=self.more_scores_button, label=bui.Lstr(resource=f'{self._r}.seeMoreText'), ) out_of_time_text: str | bui.Lstr = ( '-' if 'totalTime' not in entry else bui.Lstr( resource=f'{self._r}.ofTotalTimeText', subs=[ ( '${TOTAL}', bui.timestring(entry['totalTime'], centi=False), ) ], ) ) bui.textwidget( edit=self.time_remaining_out_of_text, text=out_of_time_text ) # if self.game is None: # bui.textwidget(edit=self.button_text, text='-') # bui.imagewidget( # edit=self.image, texture=bui.gettexture('black'), opacity=0.2 # ) # else: max_players = bui.app.classic.accounts.tournament_info[ self.tournament_id ]['maxPlayers'] txt = bui.Lstr( value='${A} ${B}', subs=[ ('${A}', campaign.getlevel(levelname).displayname), ( '${B}', bui.Lstr( resource='playerCountAbbreviatedText', subs=[('${COUNT}', str(max_players))], ), ), ], ) bui.textwidget(edit=self.button_text, text=txt) fee = entry['fee'] assert isinstance(fee, int | None) if fee is None: fee_var = None elif fee == 4: fee_var = 'price.tournament_entry_4' elif fee == 3: fee_var = 'price.tournament_entry_3' elif fee == 2: fee_var = 'price.tournament_entry_2' elif fee == 1: fee_var = 'price.tournament_entry_1' elif fee == -1: fee_var = None else: if fee != 0: print('Unknown fee value:', fee) fee_var = 'price.tournament_entry_0' self.allow_ads = allow_ads = ( entry['allowAds'] if USE_ENTRY_FEES else False ) final_fee = ( None if fee_var is None else plus.get_v1_account_misc_read_val(fee_var, '?') ) assert isinstance(final_fee, int | None) final_fee_str: str | bui.Lstr if fee_var is None: final_fee_str = '' else: if final_fee == 0: final_fee_str = bui.Lstr(resource='getTicketsWindow.freeText') else: final_fee_str = bui.charstr( bui.SpecialChar.TICKET_BACKING ) + str(final_fee) assert bui.app.classic is not None ad_tries_remaining = bui.app.classic.accounts.tournament_info[ self.tournament_id ]['adTriesRemaining'] assert isinstance(ad_tries_remaining, int | None) free_tries_remaining = bui.app.classic.accounts.tournament_info[ self.tournament_id ]['freeTriesRemaining'] assert isinstance(free_tries_remaining, int | None) # Now, if this fee allows ads and we support video ads, show the # 'or ad' version. if USE_ENTRY_FEES: if allow_ads and plus.has_video_ads(): ads_enabled = plus.have_incentivized_ad() bui.imagewidget( edit=self.entry_fee_ad_image, opacity=1.0 if ads_enabled else 0.25, ) or_text = ( bui.Lstr( resource='orText', subs=[('${A}', ''), ('${B}', '')] ) .evaluate() .strip() ) bui.textwidget(edit=self.entry_fee_text_or, text=or_text) bui.textwidget( edit=self.entry_fee_text_top, position=( self.button_x + 360, self.button_y + self.button_scale_y - 60, ), scale=1.3, text=final_fee_str, ) # Possibly show number of ad-plays remaining. bui.textwidget( edit=self.entry_fee_text_remaining, position=( self.button_x + 360, self.button_y + self.button_scale_y - 146, ), text=( '' if ad_tries_remaining in [None, 0] else ('' + str(ad_tries_remaining)) ), color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2), ) else: bui.imagewidget(edit=self.entry_fee_ad_image, opacity=0.0) bui.textwidget(edit=self.entry_fee_text_or, text='') bui.textwidget( edit=self.entry_fee_text_top, position=( self.button_x + 360, self.button_y + self.button_scale_y - 80, ), scale=1.3, text=final_fee_str, ) # Possibly show number of free-plays remaining. bui.textwidget( edit=self.entry_fee_text_remaining, position=( self.button_x + 360, self.button_y + self.button_scale_y - 100, ), text=( '' if (free_tries_remaining in [None, 0] or final_fee != 0) else ('' + str(free_tries_remaining)) ), color=(0.6, 0.6, 0.6, 1), )