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