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