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