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