bastd.ui.store.item
UI functionality related to UI items.
1# Released under the MIT License. See LICENSE for details. 2# 3"""UI functionality related to UI items.""" 4from __future__ import annotations 5 6from typing import TYPE_CHECKING 7 8import ba 9 10if TYPE_CHECKING: 11 from typing import Any 12 13 14def instantiate_store_item_display( 15 item_name: str, 16 item: dict[str, Any], 17 parent_widget: ba.Widget, 18 b_pos: tuple[float, float], 19 b_width: float, 20 b_height: float, 21 boffs_h: float = 0.0, 22 boffs_h2: float = 0.0, 23 boffs_v2: float = 0, 24 delay: float = 0.0, 25 button: bool = True, 26) -> None: 27 """(internal)""" 28 # pylint: disable=too-many-statements 29 # pylint: disable=too-many-branches 30 # pylint: disable=too-many-locals 31 from ba.internal import ( 32 get_store_item, 33 get_store_item_name_translated, 34 get_clean_price, 35 ) 36 37 del boffs_h # unused arg 38 del boffs_h2 # unused arg 39 del boffs_v2 # unused arg 40 item_info = get_store_item(item_name) 41 title_v = 0.24 42 price_v = 0.145 43 base_text_scale = 1.0 44 45 item['name'] = title = get_store_item_name_translated(item_name) 46 47 btn: ba.Widget | None 48 49 # Hack; showbuffer stuff isn't working well when we're showing merch. 50 showbuffer = 10 if item_name in {'merch', 'pro', 'pro_sale'} else 76.0 51 52 if button: 53 item['button'] = btn = ba.buttonwidget( 54 parent=parent_widget, 55 position=b_pos, 56 transition_delay=delay, 57 show_buffer_top=showbuffer, 58 enable_sound=False, 59 button_type='square', 60 size=(b_width, b_height), 61 autoselect=True, 62 label='', 63 ) 64 ba.widget(edit=btn, show_buffer_bottom=showbuffer) 65 else: 66 btn = None 67 68 b_offs_x = -0.015 * b_width 69 check_pos = 0.76 70 71 icon_tex = None 72 tint_tex = None 73 tint_color = None 74 tint2_color = None 75 tex_name: str | None = None 76 desc: str | None = None 77 modes: ba.Lstr | None = None 78 79 if item_name.startswith('characters.'): 80 character = ba.app.spaz_appearances[item_info['character']] 81 tint_color = ( 82 item_info['color'] 83 if 'color' in item_info 84 else character.default_color 85 if character.default_color is not None 86 else (1, 1, 1) 87 ) 88 tint2_color = ( 89 item_info['highlight'] 90 if 'highlight' in item_info 91 else character.default_highlight 92 if character.default_highlight is not None 93 else (1, 1, 1) 94 ) 95 icon_tex = character.icon_texture 96 tint_tex = character.icon_mask_texture 97 title_v = 0.255 98 price_v = 0.145 99 elif item_name == 'merch': 100 base_text_scale = 0.6 101 title_v = 0.85 102 price_v = 0.15 103 elif item_name in ['upgrades.pro', 'pro']: 104 base_text_scale = 0.6 105 title_v = 0.85 106 price_v = 0.15 107 elif item_name.startswith('maps.'): 108 map_type = item_info['map_type'] 109 tex_name = map_type.get_preview_texture_name() 110 title_v = 0.312 111 price_v = 0.17 112 113 elif item_name.startswith('games.'): 114 gametype = item_info['gametype'] 115 modes_l = [] 116 if gametype.supports_session_type(ba.CoopSession): 117 modes_l.append(ba.Lstr(resource='playModes.coopText')) 118 if gametype.supports_session_type(ba.DualTeamSession): 119 modes_l.append(ba.Lstr(resource='playModes.teamsText')) 120 if gametype.supports_session_type(ba.FreeForAllSession): 121 modes_l.append(ba.Lstr(resource='playModes.freeForAllText')) 122 123 if len(modes_l) == 3: 124 modes = ba.Lstr( 125 value='${A}, ${B}, ${C}', 126 subs=[ 127 ('${A}', modes_l[0]), 128 ('${B}', modes_l[1]), 129 ('${C}', modes_l[2]), 130 ], 131 ) 132 elif len(modes_l) == 2: 133 modes = ba.Lstr( 134 value='${A}, ${B}', 135 subs=[('${A}', modes_l[0]), ('${B}', modes_l[1])], 136 ) 137 elif len(modes_l) == 1: 138 modes = modes_l[0] 139 else: 140 raise Exception() 141 desc = gametype.get_description_display_string(ba.CoopSession) 142 tex_name = item_info['previewTex'] 143 base_text_scale = 0.8 144 title_v = 0.48 145 price_v = 0.17 146 147 elif item_name.startswith('icons.'): 148 base_text_scale = 1.5 149 price_v = 0.2 150 check_pos = 0.6 151 152 if item_name.startswith('characters.'): 153 frame_size = b_width * 0.7 154 im_dim = frame_size * (100.0 / 113.0) 155 im_pos = ( 156 b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x, 157 b_pos[1] + b_height * 0.57 - im_dim * 0.5, 158 ) 159 mask_texture = ba.gettexture('characterIconMask') 160 assert icon_tex is not None 161 assert tint_tex is not None 162 ba.imagewidget( 163 parent=parent_widget, 164 position=im_pos, 165 size=(im_dim, im_dim), 166 color=(1, 1, 1), 167 transition_delay=delay, 168 mask_texture=mask_texture, 169 draw_controller=btn, 170 texture=ba.gettexture(icon_tex), 171 tint_texture=ba.gettexture(tint_tex), 172 tint_color=tint_color, 173 tint2_color=tint2_color, 174 ) 175 176 if item_name == 'merch': 177 frame_size = b_width * 0.65 178 im_dim = frame_size * (100.0 / 113.0) 179 im_pos = ( 180 b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x, 181 b_pos[1] + b_height * 0.47 - im_dim * 0.5, 182 ) 183 ba.imagewidget( 184 parent=parent_widget, 185 position=im_pos, 186 size=(im_dim, im_dim), 187 transition_delay=delay, 188 draw_controller=btn, 189 opacity=1.0, 190 texture=ba.gettexture('merch'), 191 ) 192 193 if item_name in ['pro', 'upgrades.pro']: 194 frame_size = b_width * 0.5 195 im_dim = frame_size * (100.0 / 113.0) 196 im_pos = ( 197 b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x, 198 b_pos[1] + b_height * 0.5 - im_dim * 0.5, 199 ) 200 ba.imagewidget( 201 parent=parent_widget, 202 position=im_pos, 203 size=(im_dim, im_dim), 204 transition_delay=delay, 205 draw_controller=btn, 206 color=(0.3, 0.0, 0.3), 207 opacity=0.3, 208 texture=ba.gettexture('logo'), 209 ) 210 txt = ba.Lstr(resource='store.bombSquadProNewDescriptionText') 211 212 item['descriptionText'] = ba.textwidget( 213 parent=parent_widget, 214 text=txt, 215 position=(b_pos[0] + b_width * 0.5, b_pos[1] + b_height * 0.69), 216 transition_delay=delay, 217 scale=b_width * (1.0 / 230.0) * base_text_scale * 0.75, 218 maxwidth=b_width * 0.75, 219 max_height=b_height * 0.2, 220 size=(0, 0), 221 h_align='center', 222 v_align='center', 223 draw_controller=btn, 224 color=(0.3, 1, 0.3), 225 ) 226 227 extra_backings = item['extra_backings'] = [] 228 extra_images = item['extra_images'] = [] 229 extra_texts = item['extra_texts'] = [] 230 extra_texts_2 = item['extra_texts_2'] = [] 231 232 backing_color = (0.5, 0.8, 0.3) if button else (0.6, 0.5, 0.65) 233 b_square_texture = ba.gettexture('buttonSquare') 234 char_mask_texture = ba.gettexture('characterIconMask') 235 236 pos = (0.17, 0.43) 237 tile_size = (b_width * 0.16 * 1.2, b_width * 0.2 * 1.2) 238 tile_pos = (b_pos[0] + b_width * pos[0], b_pos[1] + b_height * pos[1]) 239 extra_backings.append( 240 ba.imagewidget( 241 parent=parent_widget, 242 position=( 243 tile_pos[0] - tile_size[0] * 0.5, 244 tile_pos[1] - tile_size[1] * 0.5, 245 ), 246 size=tile_size, 247 transition_delay=delay, 248 draw_controller=btn, 249 color=backing_color, 250 texture=b_square_texture, 251 ) 252 ) 253 im_size = tile_size[0] * 0.8 254 extra_images.append( 255 ba.imagewidget( 256 parent=parent_widget, 257 position=( 258 tile_pos[0] - im_size * 0.5, 259 tile_pos[1] - im_size * 0.4, 260 ), 261 size=(im_size, im_size), 262 transition_delay=delay, 263 draw_controller=btn, 264 color=(1, 1, 1), 265 texture=ba.gettexture('ticketsMore'), 266 ) 267 ) 268 bonus_tickets = str( 269 ba.internal.get_v1_account_misc_read_val('proBonusTickets', 100) 270 ) 271 extra_texts.append( 272 ba.textwidget( 273 parent=parent_widget, 274 draw_controller=btn, 275 position=( 276 tile_pos[0] - tile_size[0] * 0.03, 277 tile_pos[1] - tile_size[1] * 0.25, 278 ), 279 size=(0, 0), 280 color=(0.6, 1, 0.6), 281 transition_delay=delay, 282 h_align='center', 283 v_align='center', 284 maxwidth=tile_size[0] * 0.7, 285 scale=0.55, 286 text=ba.Lstr( 287 resource='getTicketsWindow.ticketsText', 288 subs=[('${COUNT}', bonus_tickets)], 289 ), 290 flatness=1.0, 291 shadow=0.0, 292 ) 293 ) 294 295 for charname, pos in [ 296 ('Kronk', (0.32, 0.45)), 297 ('Zoe', (0.425, 0.4)), 298 ('Jack Morgan', (0.555, 0.45)), 299 ('Mel', (0.645, 0.4)), 300 ]: 301 tile_size = (b_width * 0.16 * 0.9, b_width * 0.2 * 0.9) 302 tile_pos = ( 303 b_pos[0] + b_width * pos[0], 304 b_pos[1] + b_height * pos[1], 305 ) 306 character = ba.app.spaz_appearances[charname] 307 extra_backings.append( 308 ba.imagewidget( 309 parent=parent_widget, 310 position=( 311 tile_pos[0] - tile_size[0] * 0.5, 312 tile_pos[1] - tile_size[1] * 0.5, 313 ), 314 size=tile_size, 315 transition_delay=delay, 316 draw_controller=btn, 317 color=backing_color, 318 texture=b_square_texture, 319 ) 320 ) 321 im_size = tile_size[0] * 0.7 322 extra_images.append( 323 ba.imagewidget( 324 parent=parent_widget, 325 position=( 326 tile_pos[0] - im_size * 0.53, 327 tile_pos[1] - im_size * 0.35, 328 ), 329 size=(im_size, im_size), 330 transition_delay=delay, 331 draw_controller=btn, 332 color=(1, 1, 1), 333 texture=ba.gettexture(character.icon_texture), 334 tint_texture=ba.gettexture(character.icon_mask_texture), 335 tint_color=character.default_color, 336 tint2_color=character.default_highlight, 337 mask_texture=char_mask_texture, 338 ) 339 ) 340 extra_texts.append( 341 ba.textwidget( 342 parent=parent_widget, 343 draw_controller=btn, 344 position=( 345 tile_pos[0] - im_size * 0.03, 346 tile_pos[1] - im_size * 0.51, 347 ), 348 size=(0, 0), 349 color=(0.6, 1, 0.6), 350 transition_delay=delay, 351 h_align='center', 352 v_align='center', 353 maxwidth=tile_size[0] * 0.7, 354 scale=0.55, 355 text=ba.Lstr(translate=('characterNames', charname)), 356 flatness=1.0, 357 shadow=0.0, 358 ) 359 ) 360 361 # If we have a 'total-worth' item-id for this id, show that price so 362 # the user knows how much this is worth. 363 total_worth_item = ba.internal.get_v1_account_misc_read_val( 364 'twrths', {} 365 ).get(item_name) 366 total_worth_price: str | None 367 if total_worth_item is not None: 368 price = ba.internal.get_price(total_worth_item) 369 total_worth_price = ( 370 get_clean_price(price) if price is not None else '??' 371 ) 372 else: 373 total_worth_price = None 374 375 if total_worth_price is not None: 376 total_worth_text = ba.Lstr( 377 resource='store.totalWorthText', 378 subs=[('${TOTAL_WORTH}', total_worth_price)], 379 ) 380 extra_texts_2.append( 381 ba.textwidget( 382 parent=parent_widget, 383 text=total_worth_text, 384 position=( 385 b_pos[0] + b_width * 0.5 + b_offs_x, 386 b_pos[1] + b_height * 0.25, 387 ), 388 transition_delay=delay, 389 scale=b_width * (1.0 / 230.0) * base_text_scale * 0.45, 390 maxwidth=b_width * 0.5, 391 size=(0, 0), 392 h_align='center', 393 v_align='center', 394 shadow=1.0, 395 flatness=1.0, 396 draw_controller=btn, 397 color=(0.3, 1, 1), 398 ) 399 ) 400 401 model_opaque = ba.getmodel('level_select_button_opaque') 402 model_transparent = ba.getmodel('level_select_button_transparent') 403 mask_tex = ba.gettexture('mapPreviewMask') 404 for levelname, preview_tex_name, pos in [ 405 ('Infinite Onslaught', 'doomShroomPreview', (0.80, 0.48)), 406 ('Infinite Runaround', 'towerDPreview', (0.80, 0.32)), 407 ]: 408 tile_size = (b_width * 0.2, b_width * 0.13) 409 tile_pos = ( 410 b_pos[0] + b_width * pos[0], 411 b_pos[1] + b_height * pos[1], 412 ) 413 im_size = tile_size[0] * 0.8 414 extra_backings.append( 415 ba.imagewidget( 416 parent=parent_widget, 417 position=( 418 tile_pos[0] - tile_size[0] * 0.5, 419 tile_pos[1] - tile_size[1] * 0.5, 420 ), 421 size=tile_size, 422 transition_delay=delay, 423 draw_controller=btn, 424 color=backing_color, 425 texture=b_square_texture, 426 ) 427 ) 428 429 # Hack - gotta draw two transparent versions to avoid z issues. 430 for mod in model_opaque, model_transparent: 431 extra_images.append( 432 ba.imagewidget( 433 parent=parent_widget, 434 position=( 435 tile_pos[0] - im_size * 0.52, 436 tile_pos[1] - im_size * 0.2, 437 ), 438 size=(im_size, im_size * 0.5), 439 transition_delay=delay, 440 model_transparent=mod, 441 mask_texture=mask_tex, 442 draw_controller=btn, 443 texture=ba.gettexture(preview_tex_name), 444 ) 445 ) 446 447 extra_texts.append( 448 ba.textwidget( 449 parent=parent_widget, 450 draw_controller=btn, 451 position=( 452 tile_pos[0] - im_size * 0.03, 453 tile_pos[1] - im_size * 0.2, 454 ), 455 size=(0, 0), 456 color=(0.6, 1, 0.6), 457 transition_delay=delay, 458 h_align='center', 459 v_align='center', 460 maxwidth=tile_size[0] * 0.7, 461 scale=0.55, 462 text=ba.Lstr(translate=('coopLevelNames', levelname)), 463 flatness=1.0, 464 shadow=0.0, 465 ) 466 ) 467 468 if item_name.startswith('icons.'): 469 item['icon_text'] = ba.textwidget( 470 parent=parent_widget, 471 text=item_info['icon'], 472 position=(b_pos[0] + b_width * 0.5, b_pos[1] + b_height * 0.5), 473 transition_delay=delay, 474 scale=b_width * (1.0 / 230.0) * base_text_scale * 2.0, 475 maxwidth=b_width * 0.9, 476 max_height=b_height * 0.9, 477 size=(0, 0), 478 h_align='center', 479 v_align='center', 480 draw_controller=btn, 481 ) 482 483 if item_name.startswith('maps.'): 484 frame_size = b_width * 0.9 485 im_dim = frame_size * (100.0 / 113.0) 486 im_pos = ( 487 b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x, 488 b_pos[1] + b_height * 0.62 - im_dim * 0.25, 489 ) 490 model_opaque = ba.getmodel('level_select_button_opaque') 491 model_transparent = ba.getmodel('level_select_button_transparent') 492 mask_tex = ba.gettexture('mapPreviewMask') 493 assert tex_name is not None 494 ba.imagewidget( 495 parent=parent_widget, 496 position=im_pos, 497 size=(im_dim, im_dim * 0.5), 498 transition_delay=delay, 499 model_opaque=model_opaque, 500 model_transparent=model_transparent, 501 mask_texture=mask_tex, 502 draw_controller=btn, 503 texture=ba.gettexture(tex_name), 504 ) 505 506 if item_name.startswith('games.'): 507 frame_size = b_width * 0.8 508 im_dim = frame_size * (100.0 / 113.0) 509 im_pos = ( 510 b_pos[0] + b_width * 0.5 - im_dim * 0.5 + b_offs_x, 511 b_pos[1] + b_height * 0.72 - im_dim * 0.25, 512 ) 513 model_opaque = ba.getmodel('level_select_button_opaque') 514 model_transparent = ba.getmodel('level_select_button_transparent') 515 mask_tex = ba.gettexture('mapPreviewMask') 516 assert tex_name is not None 517 ba.imagewidget( 518 parent=parent_widget, 519 position=im_pos, 520 size=(im_dim, im_dim * 0.5), 521 transition_delay=delay, 522 model_opaque=model_opaque, 523 model_transparent=model_transparent, 524 mask_texture=mask_tex, 525 draw_controller=btn, 526 texture=ba.gettexture(tex_name), 527 ) 528 item['descriptionText'] = ba.textwidget( 529 parent=parent_widget, 530 text=desc, 531 position=(b_pos[0] + b_width * 0.5, b_pos[1] + b_height * 0.36), 532 transition_delay=delay, 533 scale=b_width * (1.0 / 230.0) * base_text_scale * 0.78, 534 maxwidth=b_width * 0.8, 535 max_height=b_height * 0.14, 536 size=(0, 0), 537 h_align='center', 538 v_align='center', 539 draw_controller=btn, 540 flatness=1.0, 541 shadow=0.0, 542 color=(0.6, 1, 0.6), 543 ) 544 item['gameModesText'] = ba.textwidget( 545 parent=parent_widget, 546 text=modes, 547 position=(b_pos[0] + b_width * 0.5, b_pos[1] + b_height * 0.26), 548 transition_delay=delay, 549 scale=b_width * (1.0 / 230.0) * base_text_scale * 0.65, 550 maxwidth=b_width * 0.8, 551 size=(0, 0), 552 h_align='center', 553 v_align='center', 554 draw_controller=btn, 555 shadow=0, 556 flatness=1.0, 557 color=(0.6, 0.8, 0.6), 558 ) 559 560 if not item_name.startswith('icons.'): 561 item['title_text'] = ba.textwidget( 562 parent=parent_widget, 563 text=title, 564 position=( 565 b_pos[0] + b_width * 0.5 + b_offs_x, 566 b_pos[1] + b_height * title_v, 567 ), 568 transition_delay=delay, 569 scale=b_width * (1.0 / 230.0) * base_text_scale, 570 maxwidth=b_width * 0.8, 571 size=(0, 0), 572 h_align='center', 573 v_align='center', 574 draw_controller=btn, 575 color=(0.7, 0.9, 0.7, 1.0), 576 ) 577 578 item['purchase_check'] = ba.imagewidget( 579 parent=parent_widget, 580 position=(b_pos[0] + b_width * check_pos, b_pos[1] + b_height * 0.05), 581 transition_delay=delay, 582 model_transparent=ba.getmodel('checkTransparent'), 583 opacity=0.0, 584 size=(60, 60), 585 color=(0.6, 0.5, 0.8), 586 draw_controller=btn, 587 texture=ba.gettexture('uiAtlas'), 588 ) 589 item['price_widget'] = ba.textwidget( 590 parent=parent_widget, 591 text='', 592 position=( 593 b_pos[0] + b_width * 0.5 + b_offs_x, 594 b_pos[1] + b_height * price_v, 595 ), 596 transition_delay=delay, 597 scale=b_width * (1.0 / 300.0) * base_text_scale, 598 maxwidth=b_width * 0.9, 599 size=(0, 0), 600 h_align='center', 601 v_align='center', 602 draw_controller=btn, 603 color=(0.2, 1, 0.2, 1.0), 604 ) 605 item['price_widget_left'] = ba.textwidget( 606 parent=parent_widget, 607 text='', 608 position=( 609 b_pos[0] + b_width * 0.33 + b_offs_x, 610 b_pos[1] + b_height * price_v, 611 ), 612 transition_delay=delay, 613 scale=b_width * (1.0 / 300.0) * base_text_scale, 614 maxwidth=b_width * 0.3, 615 size=(0, 0), 616 h_align='center', 617 v_align='center', 618 draw_controller=btn, 619 color=(0.2, 1, 0.2, 0.5), 620 ) 621 item['price_widget_right'] = ba.textwidget( 622 parent=parent_widget, 623 text='', 624 position=( 625 b_pos[0] + b_width * 0.66 + b_offs_x, 626 b_pos[1] + b_height * price_v, 627 ), 628 transition_delay=delay, 629 scale=1.1 * b_width * (1.0 / 300.0) * base_text_scale, 630 maxwidth=b_width * 0.3, 631 size=(0, 0), 632 h_align='center', 633 v_align='center', 634 draw_controller=btn, 635 color=(0.2, 1, 0.2, 1.0), 636 ) 637 item['price_slash_widget'] = ba.imagewidget( 638 parent=parent_widget, 639 position=( 640 b_pos[0] + b_width * 0.33 + b_offs_x - 36, 641 b_pos[1] + b_height * price_v - 35, 642 ), 643 transition_delay=delay, 644 texture=ba.gettexture('slash'), 645 opacity=0.0, 646 size=(70, 70), 647 draw_controller=btn, 648 color=(1, 0, 0), 649 ) 650 badge_rad = 44 651 badge_center = ( 652 b_pos[0] + b_width * 0.1 + b_offs_x, 653 b_pos[1] + b_height * 0.87, 654 ) 655 item['sale_bg_widget'] = ba.imagewidget( 656 parent=parent_widget, 657 position=(badge_center[0] - badge_rad, badge_center[1] - badge_rad), 658 opacity=0.0, 659 transition_delay=delay, 660 texture=ba.gettexture('circleZigZag'), 661 draw_controller=btn, 662 size=(badge_rad * 2, badge_rad * 2), 663 color=(0.5, 0, 1), 664 ) 665 item['sale_title_widget'] = ba.textwidget( 666 parent=parent_widget, 667 position=(badge_center[0], badge_center[1] + 12), 668 transition_delay=delay, 669 scale=1.0, 670 maxwidth=badge_rad * 1.6, 671 size=(0, 0), 672 h_align='center', 673 v_align='center', 674 draw_controller=btn, 675 shadow=0.0, 676 flatness=1.0, 677 color=(0, 1, 0), 678 ) 679 item['sale_time_widget'] = ba.textwidget( 680 parent=parent_widget, 681 position=(badge_center[0], badge_center[1] - 12), 682 transition_delay=delay, 683 scale=0.7, 684 maxwidth=badge_rad * 1.6, 685 size=(0, 0), 686 h_align='center', 687 v_align='center', 688 draw_controller=btn, 689 shadow=0.0, 690 flatness=1.0, 691 color=(0.0, 1, 0.0, 1), 692 )