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