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