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