bauiv1lib.coop.tournamentbutton

Defines button for co-op games.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Defines button for co-op games."""
  4
  5from __future__ import annotations
  6
  7from typing import TYPE_CHECKING
  8import copy
  9
 10import bauiv1 as bui
 11
 12if TYPE_CHECKING:
 13    from typing import Any, Callable
 14
 15
 16class TournamentButton:
 17    """Button showing a tournament in coop window."""
 18
 19    def __init__(
 20        self,
 21        parent: bui.Widget,
 22        x: float,
 23        y: float,
 24        select: bool,
 25        on_pressed: Callable[[TournamentButton], None],
 26    ) -> None:
 27        self._r = 'coopSelectWindow'
 28        sclx = 300
 29        scly = 195.0
 30        self.on_pressed = on_pressed
 31        self.lsbt = bui.getmesh('level_select_button_transparent')
 32        self.lsbo = bui.getmesh('level_select_button_opaque')
 33        self.allow_ads = False
 34        self.tournament_id: str | None = None
 35        self.time_remaining: int = 0
 36        self.has_time_remaining: bool = False
 37        self.leader: Any = None
 38        self.required_league: str | None = None
 39        self.button = btn = bui.buttonwidget(
 40            parent=parent,
 41            position=(x + 23, y + 4),
 42            size=(sclx, scly),
 43            label='',
 44            button_type='square',
 45            autoselect=True,
 46            on_activate_call=bui.WeakCall(self._pressed),
 47        )
 48        bui.widget(
 49            edit=btn,
 50            show_buffer_bottom=50,
 51            show_buffer_top=50,
 52            show_buffer_left=400,
 53            show_buffer_right=200,
 54        )
 55        if select:
 56            bui.containerwidget(
 57                edit=parent, selected_child=btn, visible_child=btn
 58            )
 59        image_width = sclx * 0.85 * 0.75
 60
 61        self.image = bui.imagewidget(
 62            parent=parent,
 63            draw_controller=btn,
 64            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150),
 65            size=(image_width, image_width * 0.5),
 66            mesh_transparent=self.lsbt,
 67            mesh_opaque=self.lsbo,
 68            texture=bui.gettexture('black'),
 69            opacity=0.2,
 70            mask_texture=bui.gettexture('mapPreviewMask'),
 71        )
 72
 73        self.lock_image = bui.imagewidget(
 74            parent=parent,
 75            draw_controller=btn,
 76            position=(x + 21 + sclx * 0.5 - image_width * 0.25, y + scly - 150),
 77            size=(image_width * 0.5, image_width * 0.5),
 78            texture=bui.gettexture('lock'),
 79            opacity=0.0,
 80        )
 81
 82        self.button_text = bui.textwidget(
 83            parent=parent,
 84            draw_controller=btn,
 85            position=(x + 20 + sclx * 0.5, y + scly - 35),
 86            size=(0, 0),
 87            h_align='center',
 88            text='-',
 89            v_align='center',
 90            maxwidth=sclx * 0.76,
 91            scale=0.85,
 92            color=(0.8, 1.0, 0.8, 1.0),
 93        )
 94
 95        header_color = (0.43, 0.4, 0.5, 1)
 96        value_color = (0.6, 0.6, 0.6, 1)
 97
 98        x_offs = 0
 99        bui.textwidget(
100            parent=parent,
101            draw_controller=btn,
102            position=(x + 360, y + scly - 20),
103            size=(0, 0),
104            h_align='center',
105            text=bui.Lstr(resource=self._r + '.entryFeeText'),
106            v_align='center',
107            maxwidth=100,
108            scale=0.9,
109            color=header_color,
110            flatness=1.0,
111        )
112
113        self.entry_fee_text_top = bui.textwidget(
114            parent=parent,
115            draw_controller=btn,
116            position=(x + 360, y + scly - 60),
117            size=(0, 0),
118            h_align='center',
119            text='-',
120            v_align='center',
121            maxwidth=60,
122            scale=1.3,
123            color=value_color,
124            flatness=1.0,
125        )
126        self.entry_fee_text_or = bui.textwidget(
127            parent=parent,
128            draw_controller=btn,
129            position=(x + 360, y + scly - 90),
130            size=(0, 0),
131            h_align='center',
132            text='',
133            v_align='center',
134            maxwidth=60,
135            scale=0.5,
136            color=value_color,
137            flatness=1.0,
138        )
139        self.entry_fee_text_remaining = bui.textwidget(
140            parent=parent,
141            draw_controller=btn,
142            position=(x + 360, y + scly - 90),
143            size=(0, 0),
144            h_align='center',
145            text='',
146            v_align='center',
147            maxwidth=60,
148            scale=0.5,
149            color=value_color,
150            flatness=1.0,
151        )
152
153        self.entry_fee_ad_image = bui.imagewidget(
154            parent=parent,
155            size=(40, 40),
156            draw_controller=btn,
157            position=(x + 360 - 20, y + scly - 140),
158            opacity=0.0,
159            texture=bui.gettexture('tv'),
160        )
161
162        x_offs += 50
163
164        bui.textwidget(
165            parent=parent,
166            draw_controller=btn,
167            position=(x + 447 + x_offs, y + scly - 20),
168            size=(0, 0),
169            h_align='center',
170            text=bui.Lstr(resource=self._r + '.prizesText'),
171            v_align='center',
172            maxwidth=130,
173            scale=0.9,
174            color=header_color,
175            flatness=1.0,
176        )
177
178        self.button_x = x
179        self.button_y = y
180        self.button_scale_y = scly
181
182        xo2 = 0
183        prize_value_scale = 1.5
184
185        self.prize_range_1_text = bui.textwidget(
186            parent=parent,
187            draw_controller=btn,
188            position=(x + 355 + xo2 + x_offs, y + scly - 93),
189            size=(0, 0),
190            h_align='right',
191            v_align='center',
192            maxwidth=50,
193            text='-',
194            scale=0.8,
195            color=header_color,
196            flatness=1.0,
197        )
198        self.prize_value_1_text = bui.textwidget(
199            parent=parent,
200            draw_controller=btn,
201            position=(x + 380 + xo2 + x_offs, y + scly - 93),
202            size=(0, 0),
203            h_align='left',
204            text='-',
205            v_align='center',
206            maxwidth=100,
207            scale=prize_value_scale,
208            color=value_color,
209            flatness=1.0,
210        )
211
212        self.prize_range_2_text = bui.textwidget(
213            parent=parent,
214            draw_controller=btn,
215            position=(x + 355 + xo2 + x_offs, y + scly - 93),
216            size=(0, 0),
217            h_align='right',
218            v_align='center',
219            maxwidth=50,
220            scale=0.8,
221            color=header_color,
222            flatness=1.0,
223        )
224        self.prize_value_2_text = bui.textwidget(
225            parent=parent,
226            draw_controller=btn,
227            position=(x + 380 + xo2 + x_offs, y + scly - 93),
228            size=(0, 0),
229            h_align='left',
230            text='',
231            v_align='center',
232            maxwidth=100,
233            scale=prize_value_scale,
234            color=value_color,
235            flatness=1.0,
236        )
237
238        self.prize_range_3_text = bui.textwidget(
239            parent=parent,
240            draw_controller=btn,
241            position=(x + 355 + xo2 + x_offs, y + scly - 93),
242            size=(0, 0),
243            h_align='right',
244            v_align='center',
245            maxwidth=50,
246            scale=0.8,
247            color=header_color,
248            flatness=1.0,
249        )
250        self.prize_value_3_text = bui.textwidget(
251            parent=parent,
252            draw_controller=btn,
253            position=(x + 380 + xo2 + x_offs, y + scly - 93),
254            size=(0, 0),
255            h_align='left',
256            text='',
257            v_align='center',
258            maxwidth=100,
259            scale=prize_value_scale,
260            color=value_color,
261            flatness=1.0,
262        )
263
264        bui.textwidget(
265            parent=parent,
266            draw_controller=btn,
267            position=(x + 620 + x_offs, y + scly - 20),
268            size=(0, 0),
269            h_align='center',
270            text=bui.Lstr(resource=self._r + '.currentBestText'),
271            v_align='center',
272            maxwidth=180,
273            scale=0.9,
274            color=header_color,
275            flatness=1.0,
276        )
277        self.current_leader_name_text = bui.textwidget(
278            parent=parent,
279            draw_controller=btn,
280            position=(
281                x + 620 + x_offs - (170 / 1.4) * 0.5,
282                y + scly - 60 - 40 * 0.5,
283            ),
284            selectable=True,
285            click_activate=True,
286            autoselect=True,
287            on_activate_call=bui.WeakCall(self._show_leader),
288            size=(170 / 1.4, 40),
289            h_align='center',
290            text='-',
291            v_align='center',
292            maxwidth=170,
293            scale=1.4,
294            color=value_color,
295            flatness=1.0,
296        )
297        self.current_leader_score_text = bui.textwidget(
298            parent=parent,
299            draw_controller=btn,
300            position=(x + 620 + x_offs, y + scly - 113 + 10),
301            size=(0, 0),
302            h_align='center',
303            text='-',
304            v_align='center',
305            maxwidth=170,
306            scale=1.8,
307            color=value_color,
308            flatness=1.0,
309        )
310
311        self.more_scores_button = bui.buttonwidget(
312            parent=parent,
313            position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
314            color=(0.5, 0.5, 0.6),
315            textcolor=(0.7, 0.7, 0.8),
316            label='-',
317            size=(120, 40),
318            autoselect=True,
319            up_widget=self.current_leader_name_text,
320            text_scale=0.6,
321            on_activate_call=bui.WeakCall(self._show_scores),
322        )
323        bui.widget(
324            edit=self.current_leader_name_text,
325            down_widget=self.more_scores_button,
326        )
327
328        bui.textwidget(
329            parent=parent,
330            draw_controller=btn,
331            position=(x + 820 + x_offs, y + scly - 20),
332            size=(0, 0),
333            h_align='center',
334            text=bui.Lstr(resource=self._r + '.timeRemainingText'),
335            v_align='center',
336            maxwidth=180,
337            scale=0.9,
338            color=header_color,
339            flatness=1.0,
340        )
341        self.time_remaining_value_text = bui.textwidget(
342            parent=parent,
343            draw_controller=btn,
344            position=(x + 820 + x_offs, y + scly - 68),
345            size=(0, 0),
346            h_align='center',
347            text='-',
348            v_align='center',
349            maxwidth=180,
350            scale=2.0,
351            color=value_color,
352            flatness=1.0,
353        )
354        self.time_remaining_out_of_text = bui.textwidget(
355            parent=parent,
356            draw_controller=btn,
357            position=(x + 820 + x_offs, y + scly - 110),
358            size=(0, 0),
359            h_align='center',
360            text='-',
361            v_align='center',
362            maxwidth=120,
363            scale=0.72,
364            color=(0.4, 0.4, 0.5),
365            flatness=1.0,
366        )
367
368    def _pressed(self) -> None:
369        self.on_pressed(self)
370
371    def _show_leader(self) -> None:
372        # pylint: disable=cyclic-import
373        from bauiv1lib.account.viewer import AccountViewerWindow
374
375        tournament_id = self.tournament_id
376
377        # FIXME: This assumes a single player entry in leader; should expand
378        #  this to work with multiple.
379        if (
380            tournament_id is None
381            or self.leader is None
382            or len(self.leader[2]) != 1
383        ):
384            bui.getsound('error').play()
385            return
386        bui.getsound('swish').play()
387        AccountViewerWindow(
388            account_id=self.leader[2][0].get('a', None),
389            profile_id=self.leader[2][0].get('p', None),
390            position=self.current_leader_name_text.get_screen_space_center(),
391        )
392
393    def _show_scores(self) -> None:
394        # pylint: disable=cyclic-import
395        from bauiv1lib.tournamentscores import TournamentScoresWindow
396
397        tournament_id = self.tournament_id
398        if tournament_id is None:
399            bui.getsound('error').play()
400            return
401
402        TournamentScoresWindow(
403            tournament_id=tournament_id,
404            position=self.more_scores_button.get_screen_space_center(),
405        )
406
407    def update_for_data(self, entry: dict[str, Any]) -> None:
408        """Update for new incoming data."""
409        # pylint: disable=too-many-statements
410        # pylint: disable=too-many-locals
411        # pylint: disable=too-many-branches
412
413        plus = bui.app.plus
414        assert plus is not None
415
416        assert bui.app.classic is not None
417        prize_y_offs = (
418            34
419            if 'prizeRange3' in entry
420            else 20
421            if 'prizeRange2' in entry
422            else 12
423        )
424        x_offs = 90
425
426        # pylint: disable=useless-suppression
427        # pylint: disable=unbalanced-tuple-unpacking
428        (
429            pr1,
430            pv1,
431            pr2,
432            pv2,
433            pr3,
434            pv3,
435        ) = bui.app.classic.get_tournament_prize_strings(entry)
436        # pylint: enable=unbalanced-tuple-unpacking
437        # pylint: enable=useless-suppression
438
439        enabled = 'requiredLeague' not in entry
440        bui.buttonwidget(
441            edit=self.button,
442            color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5),
443        )
444        bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0)
445        bui.textwidget(
446            edit=self.prize_range_1_text,
447            text='-' if pr1 == '' else pr1,
448            position=(
449                self.button_x + 365 + x_offs,
450                self.button_y + self.button_scale_y - 93 + prize_y_offs,
451            ),
452        )
453
454        # We want to draw values containing tickets a bit smaller
455        # (scratch that; we now draw medals a bit bigger).
456        ticket_char = bui.charstr(bui.SpecialChar.TICKET_BACKING)
457        prize_value_scale_large = 1.0
458        prize_value_scale_small = 1.0
459
460        bui.textwidget(
461            edit=self.prize_value_1_text,
462            text='-' if pv1 == '' else pv1,
463            scale=prize_value_scale_large
464            if ticket_char not in pv1
465            else prize_value_scale_small,
466            position=(
467                self.button_x + 380 + x_offs,
468                self.button_y + self.button_scale_y - 93 + prize_y_offs,
469            ),
470        )
471
472        bui.textwidget(
473            edit=self.prize_range_2_text,
474            text=pr2,
475            position=(
476                self.button_x + 365 + x_offs,
477                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
478            ),
479        )
480        bui.textwidget(
481            edit=self.prize_value_2_text,
482            text=pv2,
483            scale=prize_value_scale_large
484            if ticket_char not in pv2
485            else prize_value_scale_small,
486            position=(
487                self.button_x + 380 + x_offs,
488                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
489            ),
490        )
491
492        bui.textwidget(
493            edit=self.prize_range_3_text,
494            text=pr3,
495            position=(
496                self.button_x + 365 + x_offs,
497                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
498            ),
499        )
500        bui.textwidget(
501            edit=self.prize_value_3_text,
502            text=pv3,
503            scale=prize_value_scale_large
504            if ticket_char not in pv3
505            else prize_value_scale_small,
506            position=(
507                self.button_x + 380 + x_offs,
508                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
509            ),
510        )
511
512        leader_name = '-'
513        leader_score: str | bui.Lstr = '-'
514        if entry['scores']:
515            score = self.leader = copy.deepcopy(entry['scores'][0])
516            leader_name = score[1]
517            leader_score = (
518                bui.timestring((score[0] * 10) / 1000.0, centi=True)
519                if entry['scoreType'] == 'time'
520                else str(score[0])
521            )
522        else:
523            self.leader = None
524
525        bui.textwidget(
526            edit=self.current_leader_name_text, text=bui.Lstr(value=leader_name)
527        )
528        bui.textwidget(edit=self.current_leader_score_text, text=leader_score)
529        bui.buttonwidget(
530            edit=self.more_scores_button,
531            label=bui.Lstr(resource=self._r + '.seeMoreText'),
532        )
533        out_of_time_text: str | bui.Lstr = (
534            '-'
535            if 'totalTime' not in entry
536            else bui.Lstr(
537                resource=self._r + '.ofTotalTimeText',
538                subs=[
539                    (
540                        '${TOTAL}',
541                        bui.timestring(entry['totalTime'], centi=False),
542                    )
543                ],
544            )
545        )
546        bui.textwidget(
547            edit=self.time_remaining_out_of_text, text=out_of_time_text
548        )
549
550        self.time_remaining = entry['timeRemaining']
551        self.has_time_remaining = entry is not None
552        self.tournament_id = entry['tournamentID']
553        self.required_league = (
554            None if 'requiredLeague' not in entry else entry['requiredLeague']
555        )
556
557        assert bui.app.classic is not None
558        game = bui.app.classic.accounts.tournament_info[self.tournament_id][
559            'game'
560        ]
561
562        if game is None:
563            bui.textwidget(edit=self.button_text, text='-')
564            bui.imagewidget(
565                edit=self.image, texture=bui.gettexture('black'), opacity=0.2
566            )
567        else:
568            campaignname, levelname = game.split(':')
569            campaign = bui.app.classic.getcampaign(campaignname)
570            max_players = bui.app.classic.accounts.tournament_info[
571                self.tournament_id
572            ]['maxPlayers']
573            txt = bui.Lstr(
574                value='${A} ${B}',
575                subs=[
576                    ('${A}', campaign.getlevel(levelname).displayname),
577                    (
578                        '${B}',
579                        bui.Lstr(
580                            resource='playerCountAbbreviatedText',
581                            subs=[('${COUNT}', str(max_players))],
582                        ),
583                    ),
584                ],
585            )
586            bui.textwidget(edit=self.button_text, text=txt)
587            bui.imagewidget(
588                edit=self.image,
589                texture=bui.gettexture(
590                    campaign.getlevel(levelname).preview_texture_name
591                ),
592                opacity=1.0 if enabled else 0.5,
593            )
594
595        fee = entry['fee']
596
597        if fee is None:
598            fee_var = None
599        elif fee == 4:
600            fee_var = 'price.tournament_entry_4'
601        elif fee == 3:
602            fee_var = 'price.tournament_entry_3'
603        elif fee == 2:
604            fee_var = 'price.tournament_entry_2'
605        elif fee == 1:
606            fee_var = 'price.tournament_entry_1'
607        else:
608            if fee != 0:
609                print('Unknown fee value:', fee)
610            fee_var = 'price.tournament_entry_0'
611
612        self.allow_ads = allow_ads = entry['allowAds']
613
614        final_fee: int | None = (
615            None
616            if fee_var is None
617            else plus.get_v1_account_misc_read_val(fee_var, '?')
618        )
619
620        final_fee_str: str | bui.Lstr
621        if fee_var is None:
622            final_fee_str = ''
623        else:
624            if final_fee == 0:
625                final_fee_str = bui.Lstr(resource='getTicketsWindow.freeText')
626            else:
627                final_fee_str = bui.charstr(
628                    bui.SpecialChar.TICKET_BACKING
629                ) + str(final_fee)
630
631        assert bui.app.classic is not None
632        ad_tries_remaining = bui.app.classic.accounts.tournament_info[
633            self.tournament_id
634        ]['adTriesRemaining']
635        free_tries_remaining = bui.app.classic.accounts.tournament_info[
636            self.tournament_id
637        ]['freeTriesRemaining']
638
639        # Now, if this fee allows ads and we support video ads, show
640        # the 'or ad' version.
641        if allow_ads and bui.has_video_ads():
642            ads_enabled = bui.have_incentivized_ad()
643            bui.imagewidget(
644                edit=self.entry_fee_ad_image,
645                opacity=1.0 if ads_enabled else 0.25,
646            )
647            or_text = (
648                bui.Lstr(resource='orText', subs=[('${A}', ''), ('${B}', '')])
649                .evaluate()
650                .strip()
651            )
652            bui.textwidget(edit=self.entry_fee_text_or, text=or_text)
653            bui.textwidget(
654                edit=self.entry_fee_text_top,
655                position=(
656                    self.button_x + 360,
657                    self.button_y + self.button_scale_y - 60,
658                ),
659                scale=1.3,
660                text=final_fee_str,
661            )
662
663            # Possibly show number of ad-plays remaining.
664            bui.textwidget(
665                edit=self.entry_fee_text_remaining,
666                position=(
667                    self.button_x + 360,
668                    self.button_y + self.button_scale_y - 146,
669                ),
670                text=''
671                if ad_tries_remaining in [None, 0]
672                else ('' + str(ad_tries_remaining)),
673                color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2),
674            )
675        else:
676            bui.imagewidget(edit=self.entry_fee_ad_image, opacity=0.0)
677            bui.textwidget(edit=self.entry_fee_text_or, text='')
678            bui.textwidget(
679                edit=self.entry_fee_text_top,
680                position=(
681                    self.button_x + 360,
682                    self.button_y + self.button_scale_y - 80,
683                ),
684                scale=1.3,
685                text=final_fee_str,
686            )
687
688            # Possibly show number of free-plays remaining.
689            bui.textwidget(
690                edit=self.entry_fee_text_remaining,
691                position=(
692                    self.button_x + 360,
693                    self.button_y + self.button_scale_y - 100,
694                ),
695                text=(
696                    ''
697                    if (free_tries_remaining in [None, 0] or final_fee != 0)
698                    else ('' + str(free_tries_remaining))
699                ),
700                color=(0.6, 0.6, 0.6, 1),
701            )
class TournamentButton:
 17class TournamentButton:
 18    """Button showing a tournament in coop window."""
 19
 20    def __init__(
 21        self,
 22        parent: bui.Widget,
 23        x: float,
 24        y: float,
 25        select: bool,
 26        on_pressed: Callable[[TournamentButton], None],
 27    ) -> None:
 28        self._r = 'coopSelectWindow'
 29        sclx = 300
 30        scly = 195.0
 31        self.on_pressed = on_pressed
 32        self.lsbt = bui.getmesh('level_select_button_transparent')
 33        self.lsbo = bui.getmesh('level_select_button_opaque')
 34        self.allow_ads = False
 35        self.tournament_id: str | None = None
 36        self.time_remaining: int = 0
 37        self.has_time_remaining: bool = False
 38        self.leader: Any = None
 39        self.required_league: str | None = None
 40        self.button = btn = bui.buttonwidget(
 41            parent=parent,
 42            position=(x + 23, y + 4),
 43            size=(sclx, scly),
 44            label='',
 45            button_type='square',
 46            autoselect=True,
 47            on_activate_call=bui.WeakCall(self._pressed),
 48        )
 49        bui.widget(
 50            edit=btn,
 51            show_buffer_bottom=50,
 52            show_buffer_top=50,
 53            show_buffer_left=400,
 54            show_buffer_right=200,
 55        )
 56        if select:
 57            bui.containerwidget(
 58                edit=parent, selected_child=btn, visible_child=btn
 59            )
 60        image_width = sclx * 0.85 * 0.75
 61
 62        self.image = bui.imagewidget(
 63            parent=parent,
 64            draw_controller=btn,
 65            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150),
 66            size=(image_width, image_width * 0.5),
 67            mesh_transparent=self.lsbt,
 68            mesh_opaque=self.lsbo,
 69            texture=bui.gettexture('black'),
 70            opacity=0.2,
 71            mask_texture=bui.gettexture('mapPreviewMask'),
 72        )
 73
 74        self.lock_image = bui.imagewidget(
 75            parent=parent,
 76            draw_controller=btn,
 77            position=(x + 21 + sclx * 0.5 - image_width * 0.25, y + scly - 150),
 78            size=(image_width * 0.5, image_width * 0.5),
 79            texture=bui.gettexture('lock'),
 80            opacity=0.0,
 81        )
 82
 83        self.button_text = bui.textwidget(
 84            parent=parent,
 85            draw_controller=btn,
 86            position=(x + 20 + sclx * 0.5, y + scly - 35),
 87            size=(0, 0),
 88            h_align='center',
 89            text='-',
 90            v_align='center',
 91            maxwidth=sclx * 0.76,
 92            scale=0.85,
 93            color=(0.8, 1.0, 0.8, 1.0),
 94        )
 95
 96        header_color = (0.43, 0.4, 0.5, 1)
 97        value_color = (0.6, 0.6, 0.6, 1)
 98
 99        x_offs = 0
100        bui.textwidget(
101            parent=parent,
102            draw_controller=btn,
103            position=(x + 360, y + scly - 20),
104            size=(0, 0),
105            h_align='center',
106            text=bui.Lstr(resource=self._r + '.entryFeeText'),
107            v_align='center',
108            maxwidth=100,
109            scale=0.9,
110            color=header_color,
111            flatness=1.0,
112        )
113
114        self.entry_fee_text_top = bui.textwidget(
115            parent=parent,
116            draw_controller=btn,
117            position=(x + 360, y + scly - 60),
118            size=(0, 0),
119            h_align='center',
120            text='-',
121            v_align='center',
122            maxwidth=60,
123            scale=1.3,
124            color=value_color,
125            flatness=1.0,
126        )
127        self.entry_fee_text_or = bui.textwidget(
128            parent=parent,
129            draw_controller=btn,
130            position=(x + 360, y + scly - 90),
131            size=(0, 0),
132            h_align='center',
133            text='',
134            v_align='center',
135            maxwidth=60,
136            scale=0.5,
137            color=value_color,
138            flatness=1.0,
139        )
140        self.entry_fee_text_remaining = bui.textwidget(
141            parent=parent,
142            draw_controller=btn,
143            position=(x + 360, y + scly - 90),
144            size=(0, 0),
145            h_align='center',
146            text='',
147            v_align='center',
148            maxwidth=60,
149            scale=0.5,
150            color=value_color,
151            flatness=1.0,
152        )
153
154        self.entry_fee_ad_image = bui.imagewidget(
155            parent=parent,
156            size=(40, 40),
157            draw_controller=btn,
158            position=(x + 360 - 20, y + scly - 140),
159            opacity=0.0,
160            texture=bui.gettexture('tv'),
161        )
162
163        x_offs += 50
164
165        bui.textwidget(
166            parent=parent,
167            draw_controller=btn,
168            position=(x + 447 + x_offs, y + scly - 20),
169            size=(0, 0),
170            h_align='center',
171            text=bui.Lstr(resource=self._r + '.prizesText'),
172            v_align='center',
173            maxwidth=130,
174            scale=0.9,
175            color=header_color,
176            flatness=1.0,
177        )
178
179        self.button_x = x
180        self.button_y = y
181        self.button_scale_y = scly
182
183        xo2 = 0
184        prize_value_scale = 1.5
185
186        self.prize_range_1_text = bui.textwidget(
187            parent=parent,
188            draw_controller=btn,
189            position=(x + 355 + xo2 + x_offs, y + scly - 93),
190            size=(0, 0),
191            h_align='right',
192            v_align='center',
193            maxwidth=50,
194            text='-',
195            scale=0.8,
196            color=header_color,
197            flatness=1.0,
198        )
199        self.prize_value_1_text = bui.textwidget(
200            parent=parent,
201            draw_controller=btn,
202            position=(x + 380 + xo2 + x_offs, y + scly - 93),
203            size=(0, 0),
204            h_align='left',
205            text='-',
206            v_align='center',
207            maxwidth=100,
208            scale=prize_value_scale,
209            color=value_color,
210            flatness=1.0,
211        )
212
213        self.prize_range_2_text = bui.textwidget(
214            parent=parent,
215            draw_controller=btn,
216            position=(x + 355 + xo2 + x_offs, y + scly - 93),
217            size=(0, 0),
218            h_align='right',
219            v_align='center',
220            maxwidth=50,
221            scale=0.8,
222            color=header_color,
223            flatness=1.0,
224        )
225        self.prize_value_2_text = bui.textwidget(
226            parent=parent,
227            draw_controller=btn,
228            position=(x + 380 + xo2 + x_offs, y + scly - 93),
229            size=(0, 0),
230            h_align='left',
231            text='',
232            v_align='center',
233            maxwidth=100,
234            scale=prize_value_scale,
235            color=value_color,
236            flatness=1.0,
237        )
238
239        self.prize_range_3_text = bui.textwidget(
240            parent=parent,
241            draw_controller=btn,
242            position=(x + 355 + xo2 + x_offs, y + scly - 93),
243            size=(0, 0),
244            h_align='right',
245            v_align='center',
246            maxwidth=50,
247            scale=0.8,
248            color=header_color,
249            flatness=1.0,
250        )
251        self.prize_value_3_text = bui.textwidget(
252            parent=parent,
253            draw_controller=btn,
254            position=(x + 380 + xo2 + x_offs, y + scly - 93),
255            size=(0, 0),
256            h_align='left',
257            text='',
258            v_align='center',
259            maxwidth=100,
260            scale=prize_value_scale,
261            color=value_color,
262            flatness=1.0,
263        )
264
265        bui.textwidget(
266            parent=parent,
267            draw_controller=btn,
268            position=(x + 620 + x_offs, y + scly - 20),
269            size=(0, 0),
270            h_align='center',
271            text=bui.Lstr(resource=self._r + '.currentBestText'),
272            v_align='center',
273            maxwidth=180,
274            scale=0.9,
275            color=header_color,
276            flatness=1.0,
277        )
278        self.current_leader_name_text = bui.textwidget(
279            parent=parent,
280            draw_controller=btn,
281            position=(
282                x + 620 + x_offs - (170 / 1.4) * 0.5,
283                y + scly - 60 - 40 * 0.5,
284            ),
285            selectable=True,
286            click_activate=True,
287            autoselect=True,
288            on_activate_call=bui.WeakCall(self._show_leader),
289            size=(170 / 1.4, 40),
290            h_align='center',
291            text='-',
292            v_align='center',
293            maxwidth=170,
294            scale=1.4,
295            color=value_color,
296            flatness=1.0,
297        )
298        self.current_leader_score_text = bui.textwidget(
299            parent=parent,
300            draw_controller=btn,
301            position=(x + 620 + x_offs, y + scly - 113 + 10),
302            size=(0, 0),
303            h_align='center',
304            text='-',
305            v_align='center',
306            maxwidth=170,
307            scale=1.8,
308            color=value_color,
309            flatness=1.0,
310        )
311
312        self.more_scores_button = bui.buttonwidget(
313            parent=parent,
314            position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
315            color=(0.5, 0.5, 0.6),
316            textcolor=(0.7, 0.7, 0.8),
317            label='-',
318            size=(120, 40),
319            autoselect=True,
320            up_widget=self.current_leader_name_text,
321            text_scale=0.6,
322            on_activate_call=bui.WeakCall(self._show_scores),
323        )
324        bui.widget(
325            edit=self.current_leader_name_text,
326            down_widget=self.more_scores_button,
327        )
328
329        bui.textwidget(
330            parent=parent,
331            draw_controller=btn,
332            position=(x + 820 + x_offs, y + scly - 20),
333            size=(0, 0),
334            h_align='center',
335            text=bui.Lstr(resource=self._r + '.timeRemainingText'),
336            v_align='center',
337            maxwidth=180,
338            scale=0.9,
339            color=header_color,
340            flatness=1.0,
341        )
342        self.time_remaining_value_text = bui.textwidget(
343            parent=parent,
344            draw_controller=btn,
345            position=(x + 820 + x_offs, y + scly - 68),
346            size=(0, 0),
347            h_align='center',
348            text='-',
349            v_align='center',
350            maxwidth=180,
351            scale=2.0,
352            color=value_color,
353            flatness=1.0,
354        )
355        self.time_remaining_out_of_text = bui.textwidget(
356            parent=parent,
357            draw_controller=btn,
358            position=(x + 820 + x_offs, y + scly - 110),
359            size=(0, 0),
360            h_align='center',
361            text='-',
362            v_align='center',
363            maxwidth=120,
364            scale=0.72,
365            color=(0.4, 0.4, 0.5),
366            flatness=1.0,
367        )
368
369    def _pressed(self) -> None:
370        self.on_pressed(self)
371
372    def _show_leader(self) -> None:
373        # pylint: disable=cyclic-import
374        from bauiv1lib.account.viewer import AccountViewerWindow
375
376        tournament_id = self.tournament_id
377
378        # FIXME: This assumes a single player entry in leader; should expand
379        #  this to work with multiple.
380        if (
381            tournament_id is None
382            or self.leader is None
383            or len(self.leader[2]) != 1
384        ):
385            bui.getsound('error').play()
386            return
387        bui.getsound('swish').play()
388        AccountViewerWindow(
389            account_id=self.leader[2][0].get('a', None),
390            profile_id=self.leader[2][0].get('p', None),
391            position=self.current_leader_name_text.get_screen_space_center(),
392        )
393
394    def _show_scores(self) -> None:
395        # pylint: disable=cyclic-import
396        from bauiv1lib.tournamentscores import TournamentScoresWindow
397
398        tournament_id = self.tournament_id
399        if tournament_id is None:
400            bui.getsound('error').play()
401            return
402
403        TournamentScoresWindow(
404            tournament_id=tournament_id,
405            position=self.more_scores_button.get_screen_space_center(),
406        )
407
408    def update_for_data(self, entry: dict[str, Any]) -> None:
409        """Update for new incoming data."""
410        # pylint: disable=too-many-statements
411        # pylint: disable=too-many-locals
412        # pylint: disable=too-many-branches
413
414        plus = bui.app.plus
415        assert plus is not None
416
417        assert bui.app.classic is not None
418        prize_y_offs = (
419            34
420            if 'prizeRange3' in entry
421            else 20
422            if 'prizeRange2' in entry
423            else 12
424        )
425        x_offs = 90
426
427        # pylint: disable=useless-suppression
428        # pylint: disable=unbalanced-tuple-unpacking
429        (
430            pr1,
431            pv1,
432            pr2,
433            pv2,
434            pr3,
435            pv3,
436        ) = bui.app.classic.get_tournament_prize_strings(entry)
437        # pylint: enable=unbalanced-tuple-unpacking
438        # pylint: enable=useless-suppression
439
440        enabled = 'requiredLeague' not in entry
441        bui.buttonwidget(
442            edit=self.button,
443            color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5),
444        )
445        bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0)
446        bui.textwidget(
447            edit=self.prize_range_1_text,
448            text='-' if pr1 == '' else pr1,
449            position=(
450                self.button_x + 365 + x_offs,
451                self.button_y + self.button_scale_y - 93 + prize_y_offs,
452            ),
453        )
454
455        # We want to draw values containing tickets a bit smaller
456        # (scratch that; we now draw medals a bit bigger).
457        ticket_char = bui.charstr(bui.SpecialChar.TICKET_BACKING)
458        prize_value_scale_large = 1.0
459        prize_value_scale_small = 1.0
460
461        bui.textwidget(
462            edit=self.prize_value_1_text,
463            text='-' if pv1 == '' else pv1,
464            scale=prize_value_scale_large
465            if ticket_char not in pv1
466            else prize_value_scale_small,
467            position=(
468                self.button_x + 380 + x_offs,
469                self.button_y + self.button_scale_y - 93 + prize_y_offs,
470            ),
471        )
472
473        bui.textwidget(
474            edit=self.prize_range_2_text,
475            text=pr2,
476            position=(
477                self.button_x + 365 + x_offs,
478                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
479            ),
480        )
481        bui.textwidget(
482            edit=self.prize_value_2_text,
483            text=pv2,
484            scale=prize_value_scale_large
485            if ticket_char not in pv2
486            else prize_value_scale_small,
487            position=(
488                self.button_x + 380 + x_offs,
489                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
490            ),
491        )
492
493        bui.textwidget(
494            edit=self.prize_range_3_text,
495            text=pr3,
496            position=(
497                self.button_x + 365 + x_offs,
498                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
499            ),
500        )
501        bui.textwidget(
502            edit=self.prize_value_3_text,
503            text=pv3,
504            scale=prize_value_scale_large
505            if ticket_char not in pv3
506            else prize_value_scale_small,
507            position=(
508                self.button_x + 380 + x_offs,
509                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
510            ),
511        )
512
513        leader_name = '-'
514        leader_score: str | bui.Lstr = '-'
515        if entry['scores']:
516            score = self.leader = copy.deepcopy(entry['scores'][0])
517            leader_name = score[1]
518            leader_score = (
519                bui.timestring((score[0] * 10) / 1000.0, centi=True)
520                if entry['scoreType'] == 'time'
521                else str(score[0])
522            )
523        else:
524            self.leader = None
525
526        bui.textwidget(
527            edit=self.current_leader_name_text, text=bui.Lstr(value=leader_name)
528        )
529        bui.textwidget(edit=self.current_leader_score_text, text=leader_score)
530        bui.buttonwidget(
531            edit=self.more_scores_button,
532            label=bui.Lstr(resource=self._r + '.seeMoreText'),
533        )
534        out_of_time_text: str | bui.Lstr = (
535            '-'
536            if 'totalTime' not in entry
537            else bui.Lstr(
538                resource=self._r + '.ofTotalTimeText',
539                subs=[
540                    (
541                        '${TOTAL}',
542                        bui.timestring(entry['totalTime'], centi=False),
543                    )
544                ],
545            )
546        )
547        bui.textwidget(
548            edit=self.time_remaining_out_of_text, text=out_of_time_text
549        )
550
551        self.time_remaining = entry['timeRemaining']
552        self.has_time_remaining = entry is not None
553        self.tournament_id = entry['tournamentID']
554        self.required_league = (
555            None if 'requiredLeague' not in entry else entry['requiredLeague']
556        )
557
558        assert bui.app.classic is not None
559        game = bui.app.classic.accounts.tournament_info[self.tournament_id][
560            'game'
561        ]
562
563        if game is None:
564            bui.textwidget(edit=self.button_text, text='-')
565            bui.imagewidget(
566                edit=self.image, texture=bui.gettexture('black'), opacity=0.2
567            )
568        else:
569            campaignname, levelname = game.split(':')
570            campaign = bui.app.classic.getcampaign(campaignname)
571            max_players = bui.app.classic.accounts.tournament_info[
572                self.tournament_id
573            ]['maxPlayers']
574            txt = bui.Lstr(
575                value='${A} ${B}',
576                subs=[
577                    ('${A}', campaign.getlevel(levelname).displayname),
578                    (
579                        '${B}',
580                        bui.Lstr(
581                            resource='playerCountAbbreviatedText',
582                            subs=[('${COUNT}', str(max_players))],
583                        ),
584                    ),
585                ],
586            )
587            bui.textwidget(edit=self.button_text, text=txt)
588            bui.imagewidget(
589                edit=self.image,
590                texture=bui.gettexture(
591                    campaign.getlevel(levelname).preview_texture_name
592                ),
593                opacity=1.0 if enabled else 0.5,
594            )
595
596        fee = entry['fee']
597
598        if fee is None:
599            fee_var = None
600        elif fee == 4:
601            fee_var = 'price.tournament_entry_4'
602        elif fee == 3:
603            fee_var = 'price.tournament_entry_3'
604        elif fee == 2:
605            fee_var = 'price.tournament_entry_2'
606        elif fee == 1:
607            fee_var = 'price.tournament_entry_1'
608        else:
609            if fee != 0:
610                print('Unknown fee value:', fee)
611            fee_var = 'price.tournament_entry_0'
612
613        self.allow_ads = allow_ads = entry['allowAds']
614
615        final_fee: int | None = (
616            None
617            if fee_var is None
618            else plus.get_v1_account_misc_read_val(fee_var, '?')
619        )
620
621        final_fee_str: str | bui.Lstr
622        if fee_var is None:
623            final_fee_str = ''
624        else:
625            if final_fee == 0:
626                final_fee_str = bui.Lstr(resource='getTicketsWindow.freeText')
627            else:
628                final_fee_str = bui.charstr(
629                    bui.SpecialChar.TICKET_BACKING
630                ) + str(final_fee)
631
632        assert bui.app.classic is not None
633        ad_tries_remaining = bui.app.classic.accounts.tournament_info[
634            self.tournament_id
635        ]['adTriesRemaining']
636        free_tries_remaining = bui.app.classic.accounts.tournament_info[
637            self.tournament_id
638        ]['freeTriesRemaining']
639
640        # Now, if this fee allows ads and we support video ads, show
641        # the 'or ad' version.
642        if allow_ads and bui.has_video_ads():
643            ads_enabled = bui.have_incentivized_ad()
644            bui.imagewidget(
645                edit=self.entry_fee_ad_image,
646                opacity=1.0 if ads_enabled else 0.25,
647            )
648            or_text = (
649                bui.Lstr(resource='orText', subs=[('${A}', ''), ('${B}', '')])
650                .evaluate()
651                .strip()
652            )
653            bui.textwidget(edit=self.entry_fee_text_or, text=or_text)
654            bui.textwidget(
655                edit=self.entry_fee_text_top,
656                position=(
657                    self.button_x + 360,
658                    self.button_y + self.button_scale_y - 60,
659                ),
660                scale=1.3,
661                text=final_fee_str,
662            )
663
664            # Possibly show number of ad-plays remaining.
665            bui.textwidget(
666                edit=self.entry_fee_text_remaining,
667                position=(
668                    self.button_x + 360,
669                    self.button_y + self.button_scale_y - 146,
670                ),
671                text=''
672                if ad_tries_remaining in [None, 0]
673                else ('' + str(ad_tries_remaining)),
674                color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2),
675            )
676        else:
677            bui.imagewidget(edit=self.entry_fee_ad_image, opacity=0.0)
678            bui.textwidget(edit=self.entry_fee_text_or, text='')
679            bui.textwidget(
680                edit=self.entry_fee_text_top,
681                position=(
682                    self.button_x + 360,
683                    self.button_y + self.button_scale_y - 80,
684                ),
685                scale=1.3,
686                text=final_fee_str,
687            )
688
689            # Possibly show number of free-plays remaining.
690            bui.textwidget(
691                edit=self.entry_fee_text_remaining,
692                position=(
693                    self.button_x + 360,
694                    self.button_y + self.button_scale_y - 100,
695                ),
696                text=(
697                    ''
698                    if (free_tries_remaining in [None, 0] or final_fee != 0)
699                    else ('' + str(free_tries_remaining))
700                ),
701                color=(0.6, 0.6, 0.6, 1),
702            )

Button showing a tournament in coop window.

TournamentButton( parent: _bauiv1.Widget, x: float, y: float, select: bool, on_pressed: Callable[[TournamentButton], NoneType])
 20    def __init__(
 21        self,
 22        parent: bui.Widget,
 23        x: float,
 24        y: float,
 25        select: bool,
 26        on_pressed: Callable[[TournamentButton], None],
 27    ) -> None:
 28        self._r = 'coopSelectWindow'
 29        sclx = 300
 30        scly = 195.0
 31        self.on_pressed = on_pressed
 32        self.lsbt = bui.getmesh('level_select_button_transparent')
 33        self.lsbo = bui.getmesh('level_select_button_opaque')
 34        self.allow_ads = False
 35        self.tournament_id: str | None = None
 36        self.time_remaining: int = 0
 37        self.has_time_remaining: bool = False
 38        self.leader: Any = None
 39        self.required_league: str | None = None
 40        self.button = btn = bui.buttonwidget(
 41            parent=parent,
 42            position=(x + 23, y + 4),
 43            size=(sclx, scly),
 44            label='',
 45            button_type='square',
 46            autoselect=True,
 47            on_activate_call=bui.WeakCall(self._pressed),
 48        )
 49        bui.widget(
 50            edit=btn,
 51            show_buffer_bottom=50,
 52            show_buffer_top=50,
 53            show_buffer_left=400,
 54            show_buffer_right=200,
 55        )
 56        if select:
 57            bui.containerwidget(
 58                edit=parent, selected_child=btn, visible_child=btn
 59            )
 60        image_width = sclx * 0.85 * 0.75
 61
 62        self.image = bui.imagewidget(
 63            parent=parent,
 64            draw_controller=btn,
 65            position=(x + 21 + sclx * 0.5 - image_width * 0.5, y + scly - 150),
 66            size=(image_width, image_width * 0.5),
 67            mesh_transparent=self.lsbt,
 68            mesh_opaque=self.lsbo,
 69            texture=bui.gettexture('black'),
 70            opacity=0.2,
 71            mask_texture=bui.gettexture('mapPreviewMask'),
 72        )
 73
 74        self.lock_image = bui.imagewidget(
 75            parent=parent,
 76            draw_controller=btn,
 77            position=(x + 21 + sclx * 0.5 - image_width * 0.25, y + scly - 150),
 78            size=(image_width * 0.5, image_width * 0.5),
 79            texture=bui.gettexture('lock'),
 80            opacity=0.0,
 81        )
 82
 83        self.button_text = bui.textwidget(
 84            parent=parent,
 85            draw_controller=btn,
 86            position=(x + 20 + sclx * 0.5, y + scly - 35),
 87            size=(0, 0),
 88            h_align='center',
 89            text='-',
 90            v_align='center',
 91            maxwidth=sclx * 0.76,
 92            scale=0.85,
 93            color=(0.8, 1.0, 0.8, 1.0),
 94        )
 95
 96        header_color = (0.43, 0.4, 0.5, 1)
 97        value_color = (0.6, 0.6, 0.6, 1)
 98
 99        x_offs = 0
100        bui.textwidget(
101            parent=parent,
102            draw_controller=btn,
103            position=(x + 360, y + scly - 20),
104            size=(0, 0),
105            h_align='center',
106            text=bui.Lstr(resource=self._r + '.entryFeeText'),
107            v_align='center',
108            maxwidth=100,
109            scale=0.9,
110            color=header_color,
111            flatness=1.0,
112        )
113
114        self.entry_fee_text_top = bui.textwidget(
115            parent=parent,
116            draw_controller=btn,
117            position=(x + 360, y + scly - 60),
118            size=(0, 0),
119            h_align='center',
120            text='-',
121            v_align='center',
122            maxwidth=60,
123            scale=1.3,
124            color=value_color,
125            flatness=1.0,
126        )
127        self.entry_fee_text_or = bui.textwidget(
128            parent=parent,
129            draw_controller=btn,
130            position=(x + 360, y + scly - 90),
131            size=(0, 0),
132            h_align='center',
133            text='',
134            v_align='center',
135            maxwidth=60,
136            scale=0.5,
137            color=value_color,
138            flatness=1.0,
139        )
140        self.entry_fee_text_remaining = bui.textwidget(
141            parent=parent,
142            draw_controller=btn,
143            position=(x + 360, y + scly - 90),
144            size=(0, 0),
145            h_align='center',
146            text='',
147            v_align='center',
148            maxwidth=60,
149            scale=0.5,
150            color=value_color,
151            flatness=1.0,
152        )
153
154        self.entry_fee_ad_image = bui.imagewidget(
155            parent=parent,
156            size=(40, 40),
157            draw_controller=btn,
158            position=(x + 360 - 20, y + scly - 140),
159            opacity=0.0,
160            texture=bui.gettexture('tv'),
161        )
162
163        x_offs += 50
164
165        bui.textwidget(
166            parent=parent,
167            draw_controller=btn,
168            position=(x + 447 + x_offs, y + scly - 20),
169            size=(0, 0),
170            h_align='center',
171            text=bui.Lstr(resource=self._r + '.prizesText'),
172            v_align='center',
173            maxwidth=130,
174            scale=0.9,
175            color=header_color,
176            flatness=1.0,
177        )
178
179        self.button_x = x
180        self.button_y = y
181        self.button_scale_y = scly
182
183        xo2 = 0
184        prize_value_scale = 1.5
185
186        self.prize_range_1_text = bui.textwidget(
187            parent=parent,
188            draw_controller=btn,
189            position=(x + 355 + xo2 + x_offs, y + scly - 93),
190            size=(0, 0),
191            h_align='right',
192            v_align='center',
193            maxwidth=50,
194            text='-',
195            scale=0.8,
196            color=header_color,
197            flatness=1.0,
198        )
199        self.prize_value_1_text = bui.textwidget(
200            parent=parent,
201            draw_controller=btn,
202            position=(x + 380 + xo2 + x_offs, y + scly - 93),
203            size=(0, 0),
204            h_align='left',
205            text='-',
206            v_align='center',
207            maxwidth=100,
208            scale=prize_value_scale,
209            color=value_color,
210            flatness=1.0,
211        )
212
213        self.prize_range_2_text = bui.textwidget(
214            parent=parent,
215            draw_controller=btn,
216            position=(x + 355 + xo2 + x_offs, y + scly - 93),
217            size=(0, 0),
218            h_align='right',
219            v_align='center',
220            maxwidth=50,
221            scale=0.8,
222            color=header_color,
223            flatness=1.0,
224        )
225        self.prize_value_2_text = bui.textwidget(
226            parent=parent,
227            draw_controller=btn,
228            position=(x + 380 + xo2 + x_offs, y + scly - 93),
229            size=(0, 0),
230            h_align='left',
231            text='',
232            v_align='center',
233            maxwidth=100,
234            scale=prize_value_scale,
235            color=value_color,
236            flatness=1.0,
237        )
238
239        self.prize_range_3_text = bui.textwidget(
240            parent=parent,
241            draw_controller=btn,
242            position=(x + 355 + xo2 + x_offs, y + scly - 93),
243            size=(0, 0),
244            h_align='right',
245            v_align='center',
246            maxwidth=50,
247            scale=0.8,
248            color=header_color,
249            flatness=1.0,
250        )
251        self.prize_value_3_text = bui.textwidget(
252            parent=parent,
253            draw_controller=btn,
254            position=(x + 380 + xo2 + x_offs, y + scly - 93),
255            size=(0, 0),
256            h_align='left',
257            text='',
258            v_align='center',
259            maxwidth=100,
260            scale=prize_value_scale,
261            color=value_color,
262            flatness=1.0,
263        )
264
265        bui.textwidget(
266            parent=parent,
267            draw_controller=btn,
268            position=(x + 620 + x_offs, y + scly - 20),
269            size=(0, 0),
270            h_align='center',
271            text=bui.Lstr(resource=self._r + '.currentBestText'),
272            v_align='center',
273            maxwidth=180,
274            scale=0.9,
275            color=header_color,
276            flatness=1.0,
277        )
278        self.current_leader_name_text = bui.textwidget(
279            parent=parent,
280            draw_controller=btn,
281            position=(
282                x + 620 + x_offs - (170 / 1.4) * 0.5,
283                y + scly - 60 - 40 * 0.5,
284            ),
285            selectable=True,
286            click_activate=True,
287            autoselect=True,
288            on_activate_call=bui.WeakCall(self._show_leader),
289            size=(170 / 1.4, 40),
290            h_align='center',
291            text='-',
292            v_align='center',
293            maxwidth=170,
294            scale=1.4,
295            color=value_color,
296            flatness=1.0,
297        )
298        self.current_leader_score_text = bui.textwidget(
299            parent=parent,
300            draw_controller=btn,
301            position=(x + 620 + x_offs, y + scly - 113 + 10),
302            size=(0, 0),
303            h_align='center',
304            text='-',
305            v_align='center',
306            maxwidth=170,
307            scale=1.8,
308            color=value_color,
309            flatness=1.0,
310        )
311
312        self.more_scores_button = bui.buttonwidget(
313            parent=parent,
314            position=(x + 620 + x_offs - 60, y + scly - 50 - 125),
315            color=(0.5, 0.5, 0.6),
316            textcolor=(0.7, 0.7, 0.8),
317            label='-',
318            size=(120, 40),
319            autoselect=True,
320            up_widget=self.current_leader_name_text,
321            text_scale=0.6,
322            on_activate_call=bui.WeakCall(self._show_scores),
323        )
324        bui.widget(
325            edit=self.current_leader_name_text,
326            down_widget=self.more_scores_button,
327        )
328
329        bui.textwidget(
330            parent=parent,
331            draw_controller=btn,
332            position=(x + 820 + x_offs, y + scly - 20),
333            size=(0, 0),
334            h_align='center',
335            text=bui.Lstr(resource=self._r + '.timeRemainingText'),
336            v_align='center',
337            maxwidth=180,
338            scale=0.9,
339            color=header_color,
340            flatness=1.0,
341        )
342        self.time_remaining_value_text = bui.textwidget(
343            parent=parent,
344            draw_controller=btn,
345            position=(x + 820 + x_offs, y + scly - 68),
346            size=(0, 0),
347            h_align='center',
348            text='-',
349            v_align='center',
350            maxwidth=180,
351            scale=2.0,
352            color=value_color,
353            flatness=1.0,
354        )
355        self.time_remaining_out_of_text = bui.textwidget(
356            parent=parent,
357            draw_controller=btn,
358            position=(x + 820 + x_offs, y + scly - 110),
359            size=(0, 0),
360            h_align='center',
361            text='-',
362            v_align='center',
363            maxwidth=120,
364            scale=0.72,
365            color=(0.4, 0.4, 0.5),
366            flatness=1.0,
367        )
on_pressed
lsbt
lsbo
allow_ads
tournament_id: str | None
time_remaining: int
has_time_remaining: bool
leader: Any
required_league: str | None
image
lock_image
button_text
entry_fee_text_top
entry_fee_text_or
entry_fee_text_remaining
entry_fee_ad_image
button_x
button_y
button_scale_y
prize_range_1_text
prize_value_1_text
prize_range_2_text
prize_value_2_text
prize_range_3_text
prize_value_3_text
current_leader_name_text
current_leader_score_text
more_scores_button
time_remaining_value_text
time_remaining_out_of_text
def update_for_data(self, entry: dict[str, typing.Any]) -> None:
408    def update_for_data(self, entry: dict[str, Any]) -> None:
409        """Update for new incoming data."""
410        # pylint: disable=too-many-statements
411        # pylint: disable=too-many-locals
412        # pylint: disable=too-many-branches
413
414        plus = bui.app.plus
415        assert plus is not None
416
417        assert bui.app.classic is not None
418        prize_y_offs = (
419            34
420            if 'prizeRange3' in entry
421            else 20
422            if 'prizeRange2' in entry
423            else 12
424        )
425        x_offs = 90
426
427        # pylint: disable=useless-suppression
428        # pylint: disable=unbalanced-tuple-unpacking
429        (
430            pr1,
431            pv1,
432            pr2,
433            pv2,
434            pr3,
435            pv3,
436        ) = bui.app.classic.get_tournament_prize_strings(entry)
437        # pylint: enable=unbalanced-tuple-unpacking
438        # pylint: enable=useless-suppression
439
440        enabled = 'requiredLeague' not in entry
441        bui.buttonwidget(
442            edit=self.button,
443            color=(0.5, 0.7, 0.2) if enabled else (0.5, 0.5, 0.5),
444        )
445        bui.imagewidget(edit=self.lock_image, opacity=0.0 if enabled else 1.0)
446        bui.textwidget(
447            edit=self.prize_range_1_text,
448            text='-' if pr1 == '' else pr1,
449            position=(
450                self.button_x + 365 + x_offs,
451                self.button_y + self.button_scale_y - 93 + prize_y_offs,
452            ),
453        )
454
455        # We want to draw values containing tickets a bit smaller
456        # (scratch that; we now draw medals a bit bigger).
457        ticket_char = bui.charstr(bui.SpecialChar.TICKET_BACKING)
458        prize_value_scale_large = 1.0
459        prize_value_scale_small = 1.0
460
461        bui.textwidget(
462            edit=self.prize_value_1_text,
463            text='-' if pv1 == '' else pv1,
464            scale=prize_value_scale_large
465            if ticket_char not in pv1
466            else prize_value_scale_small,
467            position=(
468                self.button_x + 380 + x_offs,
469                self.button_y + self.button_scale_y - 93 + prize_y_offs,
470            ),
471        )
472
473        bui.textwidget(
474            edit=self.prize_range_2_text,
475            text=pr2,
476            position=(
477                self.button_x + 365 + x_offs,
478                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
479            ),
480        )
481        bui.textwidget(
482            edit=self.prize_value_2_text,
483            text=pv2,
484            scale=prize_value_scale_large
485            if ticket_char not in pv2
486            else prize_value_scale_small,
487            position=(
488                self.button_x + 380 + x_offs,
489                self.button_y + self.button_scale_y - 93 - 45 + prize_y_offs,
490            ),
491        )
492
493        bui.textwidget(
494            edit=self.prize_range_3_text,
495            text=pr3,
496            position=(
497                self.button_x + 365 + x_offs,
498                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
499            ),
500        )
501        bui.textwidget(
502            edit=self.prize_value_3_text,
503            text=pv3,
504            scale=prize_value_scale_large
505            if ticket_char not in pv3
506            else prize_value_scale_small,
507            position=(
508                self.button_x + 380 + x_offs,
509                self.button_y + self.button_scale_y - 93 - 90 + prize_y_offs,
510            ),
511        )
512
513        leader_name = '-'
514        leader_score: str | bui.Lstr = '-'
515        if entry['scores']:
516            score = self.leader = copy.deepcopy(entry['scores'][0])
517            leader_name = score[1]
518            leader_score = (
519                bui.timestring((score[0] * 10) / 1000.0, centi=True)
520                if entry['scoreType'] == 'time'
521                else str(score[0])
522            )
523        else:
524            self.leader = None
525
526        bui.textwidget(
527            edit=self.current_leader_name_text, text=bui.Lstr(value=leader_name)
528        )
529        bui.textwidget(edit=self.current_leader_score_text, text=leader_score)
530        bui.buttonwidget(
531            edit=self.more_scores_button,
532            label=bui.Lstr(resource=self._r + '.seeMoreText'),
533        )
534        out_of_time_text: str | bui.Lstr = (
535            '-'
536            if 'totalTime' not in entry
537            else bui.Lstr(
538                resource=self._r + '.ofTotalTimeText',
539                subs=[
540                    (
541                        '${TOTAL}',
542                        bui.timestring(entry['totalTime'], centi=False),
543                    )
544                ],
545            )
546        )
547        bui.textwidget(
548            edit=self.time_remaining_out_of_text, text=out_of_time_text
549        )
550
551        self.time_remaining = entry['timeRemaining']
552        self.has_time_remaining = entry is not None
553        self.tournament_id = entry['tournamentID']
554        self.required_league = (
555            None if 'requiredLeague' not in entry else entry['requiredLeague']
556        )
557
558        assert bui.app.classic is not None
559        game = bui.app.classic.accounts.tournament_info[self.tournament_id][
560            'game'
561        ]
562
563        if game is None:
564            bui.textwidget(edit=self.button_text, text='-')
565            bui.imagewidget(
566                edit=self.image, texture=bui.gettexture('black'), opacity=0.2
567            )
568        else:
569            campaignname, levelname = game.split(':')
570            campaign = bui.app.classic.getcampaign(campaignname)
571            max_players = bui.app.classic.accounts.tournament_info[
572                self.tournament_id
573            ]['maxPlayers']
574            txt = bui.Lstr(
575                value='${A} ${B}',
576                subs=[
577                    ('${A}', campaign.getlevel(levelname).displayname),
578                    (
579                        '${B}',
580                        bui.Lstr(
581                            resource='playerCountAbbreviatedText',
582                            subs=[('${COUNT}', str(max_players))],
583                        ),
584                    ),
585                ],
586            )
587            bui.textwidget(edit=self.button_text, text=txt)
588            bui.imagewidget(
589                edit=self.image,
590                texture=bui.gettexture(
591                    campaign.getlevel(levelname).preview_texture_name
592                ),
593                opacity=1.0 if enabled else 0.5,
594            )
595
596        fee = entry['fee']
597
598        if fee is None:
599            fee_var = None
600        elif fee == 4:
601            fee_var = 'price.tournament_entry_4'
602        elif fee == 3:
603            fee_var = 'price.tournament_entry_3'
604        elif fee == 2:
605            fee_var = 'price.tournament_entry_2'
606        elif fee == 1:
607            fee_var = 'price.tournament_entry_1'
608        else:
609            if fee != 0:
610                print('Unknown fee value:', fee)
611            fee_var = 'price.tournament_entry_0'
612
613        self.allow_ads = allow_ads = entry['allowAds']
614
615        final_fee: int | None = (
616            None
617            if fee_var is None
618            else plus.get_v1_account_misc_read_val(fee_var, '?')
619        )
620
621        final_fee_str: str | bui.Lstr
622        if fee_var is None:
623            final_fee_str = ''
624        else:
625            if final_fee == 0:
626                final_fee_str = bui.Lstr(resource='getTicketsWindow.freeText')
627            else:
628                final_fee_str = bui.charstr(
629                    bui.SpecialChar.TICKET_BACKING
630                ) + str(final_fee)
631
632        assert bui.app.classic is not None
633        ad_tries_remaining = bui.app.classic.accounts.tournament_info[
634            self.tournament_id
635        ]['adTriesRemaining']
636        free_tries_remaining = bui.app.classic.accounts.tournament_info[
637            self.tournament_id
638        ]['freeTriesRemaining']
639
640        # Now, if this fee allows ads and we support video ads, show
641        # the 'or ad' version.
642        if allow_ads and bui.has_video_ads():
643            ads_enabled = bui.have_incentivized_ad()
644            bui.imagewidget(
645                edit=self.entry_fee_ad_image,
646                opacity=1.0 if ads_enabled else 0.25,
647            )
648            or_text = (
649                bui.Lstr(resource='orText', subs=[('${A}', ''), ('${B}', '')])
650                .evaluate()
651                .strip()
652            )
653            bui.textwidget(edit=self.entry_fee_text_or, text=or_text)
654            bui.textwidget(
655                edit=self.entry_fee_text_top,
656                position=(
657                    self.button_x + 360,
658                    self.button_y + self.button_scale_y - 60,
659                ),
660                scale=1.3,
661                text=final_fee_str,
662            )
663
664            # Possibly show number of ad-plays remaining.
665            bui.textwidget(
666                edit=self.entry_fee_text_remaining,
667                position=(
668                    self.button_x + 360,
669                    self.button_y + self.button_scale_y - 146,
670                ),
671                text=''
672                if ad_tries_remaining in [None, 0]
673                else ('' + str(ad_tries_remaining)),
674                color=(0.6, 0.6, 0.6, 1 if ads_enabled else 0.2),
675            )
676        else:
677            bui.imagewidget(edit=self.entry_fee_ad_image, opacity=0.0)
678            bui.textwidget(edit=self.entry_fee_text_or, text='')
679            bui.textwidget(
680                edit=self.entry_fee_text_top,
681                position=(
682                    self.button_x + 360,
683                    self.button_y + self.button_scale_y - 80,
684                ),
685                scale=1.3,
686                text=final_fee_str,
687            )
688
689            # Possibly show number of free-plays remaining.
690            bui.textwidget(
691                edit=self.entry_fee_text_remaining,
692                position=(
693                    self.button_x + 360,
694                    self.button_y + self.button_scale_y - 100,
695                ),
696                text=(
697                    ''
698                    if (free_tries_remaining in [None, 0] or final_fee != 0)
699                    else ('' + str(free_tries_remaining))
700                ),
701                color=(0.6, 0.6, 0.6, 1),
702            )

Update for new incoming data.