bastd.ui.play

Provides the top level play window.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides the top level play window."""
  4
  5from __future__ import annotations
  6
  7from typing import TYPE_CHECKING
  8
  9import ba
 10import ba.internal
 11
 12if TYPE_CHECKING:
 13    pass
 14
 15
 16class PlayWindow(ba.Window):
 17    """Window for selecting overall play type."""
 18
 19    def __init__(
 20        self,
 21        transition: str = 'in_right',
 22        origin_widget: ba.Widget | None = None,
 23    ):
 24        # pylint: disable=too-many-statements
 25        # pylint: disable=too-many-locals
 26        import threading
 27
 28        # Preload some modules we use in a background thread so we won't
 29        # have a visual hitch when the user taps them.
 30        threading.Thread(target=self._preload_modules).start()
 31
 32        # We can currently be used either for main menu duty or for selecting
 33        # playlists (should make this more elegant/general).
 34        self._is_main_menu = not ba.app.ui.selecting_private_party_playlist
 35
 36        uiscale = ba.app.ui.uiscale
 37        width = 1000 if uiscale is ba.UIScale.SMALL else 800
 38        x_offs = 100 if uiscale is ba.UIScale.SMALL else 0
 39        height = 550
 40        button_width = 400
 41
 42        scale_origin: tuple[float, float] | None
 43        if origin_widget is not None:
 44            self._transition_out = 'out_scale'
 45            scale_origin = origin_widget.get_screen_space_center()
 46            transition = 'in_scale'
 47        else:
 48            self._transition_out = 'out_right'
 49            scale_origin = None
 50
 51        self._r = 'playWindow'
 52
 53        super().__init__(
 54            root_widget=ba.containerwidget(
 55                size=(width, height),
 56                transition=transition,
 57                toolbar_visibility='menu_full',
 58                scale_origin_stack_offset=scale_origin,
 59                scale=(
 60                    1.6
 61                    if uiscale is ba.UIScale.SMALL
 62                    else 0.9
 63                    if uiscale is ba.UIScale.MEDIUM
 64                    else 0.8
 65                ),
 66                stack_offset=(0, 0) if uiscale is ba.UIScale.SMALL else (0, 0),
 67            )
 68        )
 69        self._back_button = back_button = btn = ba.buttonwidget(
 70            parent=self._root_widget,
 71            position=(55 + x_offs, height - 132),
 72            size=(120, 60),
 73            scale=1.1,
 74            text_res_scale=1.5,
 75            text_scale=1.2,
 76            autoselect=True,
 77            label=ba.Lstr(resource='backText'),
 78            button_type='back',
 79        )
 80
 81        txt = ba.textwidget(
 82            parent=self._root_widget,
 83            position=(width * 0.5, height - 101),
 84            # position=(width * 0.5, height -
 85            #           (101 if main_menu else 61)),
 86            size=(0, 0),
 87            text=ba.Lstr(
 88                resource=(self._r + '.titleText')
 89                if self._is_main_menu
 90                else 'playlistsText'
 91            ),
 92            scale=1.7,
 93            res_scale=2.0,
 94            maxwidth=400,
 95            color=ba.app.ui.heading_color,
 96            h_align='center',
 97            v_align='center',
 98        )
 99
100        ba.buttonwidget(
101            edit=btn,
102            button_type='backSmall',
103            size=(60, 60),
104            label=ba.charstr(ba.SpecialChar.BACK),
105        )
106        if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
107            ba.textwidget(edit=txt, text='')
108
109        v = height - (110 if self._is_main_menu else 90)
110        v -= 100
111        clr = (0.6, 0.7, 0.6, 1.0)
112        v -= 280 if self._is_main_menu else 180
113        v += 30 if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL else 0
114        hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
115        scl = 1.13 if self._is_main_menu else 0.68
116
117        self._lineup_tex = ba.gettexture('playerLineup')
118        angry_computer_transparent_model = ba.getmodel(
119            'angryComputerTransparent'
120        )
121        self._lineup_1_transparent_model = ba.getmodel(
122            'playerLineup1Transparent'
123        )
124        self._lineup_2_transparent_model = ba.getmodel(
125            'playerLineup2Transparent'
126        )
127        self._lineup_3_transparent_model = ba.getmodel(
128            'playerLineup3Transparent'
129        )
130        self._lineup_4_transparent_model = ba.getmodel(
131            'playerLineup4Transparent'
132        )
133        self._eyes_model = ba.getmodel('plasticEyesTransparent')
134
135        self._coop_button: ba.Widget | None = None
136
137        # Only show coop button in main-menu variant.
138        if self._is_main_menu:
139            self._coop_button = btn = ba.buttonwidget(
140                parent=self._root_widget,
141                position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
142                size=(
143                    scl * button_width,
144                    scl * (300 if self._is_main_menu else 360),
145                ),
146                extra_touch_border_scale=0.1,
147                autoselect=True,
148                label='',
149                button_type='square',
150                text_scale=1.13,
151                on_activate_call=self._coop,
152            )
153
154            if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
155                ba.widget(
156                    edit=btn,
157                    left_widget=ba.internal.get_special_widget('back_button'),
158                )
159                ba.widget(
160                    edit=btn,
161                    up_widget=ba.internal.get_special_widget('account_button'),
162                )
163                ba.widget(
164                    edit=btn,
165                    down_widget=ba.internal.get_special_widget(
166                        'settings_button'
167                    ),
168                )
169
170            self._draw_dude(
171                0,
172                btn,
173                hoffs,
174                v,
175                scl,
176                position=(140, 30),
177                color=(0.72, 0.4, 1.0),
178            )
179            self._draw_dude(
180                1,
181                btn,
182                hoffs,
183                v,
184                scl,
185                position=(185, 53),
186                color=(0.71, 0.5, 1.0),
187            )
188            self._draw_dude(
189                2,
190                btn,
191                hoffs,
192                v,
193                scl,
194                position=(220, 27),
195                color=(0.67, 0.44, 1.0),
196            )
197            self._draw_dude(
198                3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)
199            )
200            ba.imagewidget(
201                parent=self._root_widget,
202                draw_controller=btn,
203                position=(hoffs + scl * 230, v + scl * 153),
204                size=(scl * 115, scl * 115),
205                texture=self._lineup_tex,
206                model_transparent=angry_computer_transparent_model,
207            )
208
209            ba.textwidget(
210                parent=self._root_widget,
211                draw_controller=btn,
212                position=(hoffs + scl * (-10), v + scl * 95),
213                size=(scl * button_width, scl * 50),
214                text=ba.Lstr(
215                    resource='playModes.singlePlayerCoopText',
216                    fallback_resource='playModes.coopText',
217                ),
218                maxwidth=scl * button_width * 0.7,
219                res_scale=1.5,
220                h_align='center',
221                v_align='center',
222                color=(0.7, 0.9, 0.7, 1.0),
223                scale=scl * 2.3,
224            )
225
226            ba.textwidget(
227                parent=self._root_widget,
228                draw_controller=btn,
229                position=(hoffs + scl * (-10), v + (scl * 54)),
230                size=(scl * button_width, scl * 30),
231                text=ba.Lstr(resource=self._r + '.oneToFourPlayersText'),
232                h_align='center',
233                v_align='center',
234                scale=0.83 * scl,
235                flatness=1.0,
236                maxwidth=scl * button_width * 0.7,
237                color=clr,
238            )
239
240        scl = 0.5 if self._is_main_menu else 0.68
241        hoffs += 440 if self._is_main_menu else 216
242        v += 180 if self._is_main_menu else -68
243
244        self._teams_button = btn = ba.buttonwidget(
245            parent=self._root_widget,
246            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
247            size=(
248                scl * button_width,
249                scl * (300 if self._is_main_menu else 360),
250            ),
251            extra_touch_border_scale=0.1,
252            autoselect=True,
253            label='',
254            button_type='square',
255            text_scale=1.13,
256            on_activate_call=self._team_tourney,
257        )
258
259        if ba.app.ui.use_toolbars:
260            ba.widget(
261                edit=btn,
262                up_widget=ba.internal.get_special_widget('tickets_plus_button'),
263                right_widget=ba.internal.get_special_widget('party_button'),
264            )
265
266        xxx = -14
267        self._draw_dude(
268            2,
269            btn,
270            hoffs,
271            v,
272            scl,
273            position=(xxx + 148, 30),
274            color=(0.2, 0.4, 1.0),
275        )
276        self._draw_dude(
277            3,
278            btn,
279            hoffs,
280            v,
281            scl,
282            position=(xxx + 181, 53),
283            color=(0.3, 0.4, 1.0),
284        )
285        self._draw_dude(
286            1,
287            btn,
288            hoffs,
289            v,
290            scl,
291            position=(xxx + 216, 33),
292            color=(0.3, 0.5, 1.0),
293        )
294        self._draw_dude(
295            0,
296            btn,
297            hoffs,
298            v,
299            scl,
300            position=(xxx + 245, 57),
301            color=(0.3, 0.5, 1.0),
302        )
303
304        xxx = 155
305        self._draw_dude(
306            0,
307            btn,
308            hoffs,
309            v,
310            scl,
311            position=(xxx + 151, 30),
312            color=(1.0, 0.5, 0.4),
313        )
314        self._draw_dude(
315            1,
316            btn,
317            hoffs,
318            v,
319            scl,
320            position=(xxx + 189, 53),
321            color=(1.0, 0.58, 0.58),
322        )
323        self._draw_dude(
324            3,
325            btn,
326            hoffs,
327            v,
328            scl,
329            position=(xxx + 223, 27),
330            color=(1.0, 0.5, 0.5),
331        )
332        self._draw_dude(
333            2,
334            btn,
335            hoffs,
336            v,
337            scl,
338            position=(xxx + 257, 57),
339            color=(1.0, 0.5, 0.5),
340        )
341
342        ba.textwidget(
343            parent=self._root_widget,
344            draw_controller=btn,
345            position=(hoffs + scl * (-10), v + scl * 95),
346            size=(scl * button_width, scl * 50),
347            text=ba.Lstr(
348                resource='playModes.teamsText', fallback_resource='teamsText'
349            ),
350            res_scale=1.5,
351            maxwidth=scl * button_width * 0.7,
352            h_align='center',
353            v_align='center',
354            color=(0.7, 0.9, 0.7, 1.0),
355            scale=scl * 2.3,
356        )
357        ba.textwidget(
358            parent=self._root_widget,
359            draw_controller=btn,
360            position=(hoffs + scl * (-10), v + (scl * 54)),
361            size=(scl * button_width, scl * 30),
362            text=ba.Lstr(resource=self._r + '.twoToEightPlayersText'),
363            h_align='center',
364            v_align='center',
365            res_scale=1.5,
366            scale=0.9 * scl,
367            flatness=1.0,
368            maxwidth=scl * button_width * 0.7,
369            color=clr,
370        )
371
372        hoffs += 0 if self._is_main_menu else 300
373        v -= 155 if self._is_main_menu else 0
374        self._free_for_all_button = btn = ba.buttonwidget(
375            parent=self._root_widget,
376            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
377            size=(
378                scl * button_width,
379                scl * (300 if self._is_main_menu else 360),
380            ),
381            extra_touch_border_scale=0.1,
382            autoselect=True,
383            label='',
384            button_type='square',
385            text_scale=1.13,
386            on_activate_call=self._free_for_all,
387        )
388
389        xxx = -5
390        self._draw_dude(
391            0,
392            btn,
393            hoffs,
394            v,
395            scl,
396            position=(xxx + 140, 30),
397            color=(0.4, 1.0, 0.4),
398        )
399        self._draw_dude(
400            3,
401            btn,
402            hoffs,
403            v,
404            scl,
405            position=(xxx + 185, 53),
406            color=(1.0, 0.4, 0.5),
407        )
408        self._draw_dude(
409            1,
410            btn,
411            hoffs,
412            v,
413            scl,
414            position=(xxx + 220, 27),
415            color=(0.4, 0.5, 1.0),
416        )
417        self._draw_dude(
418            2,
419            btn,
420            hoffs,
421            v,
422            scl,
423            position=(xxx + 255, 57),
424            color=(0.5, 1.0, 0.4),
425        )
426        xxx = 140
427        self._draw_dude(
428            2,
429            btn,
430            hoffs,
431            v,
432            scl,
433            position=(xxx + 148, 30),
434            color=(1.0, 0.9, 0.4),
435        )
436        self._draw_dude(
437            0,
438            btn,
439            hoffs,
440            v,
441            scl,
442            position=(xxx + 182, 53),
443            color=(0.7, 1.0, 0.5),
444        )
445        self._draw_dude(
446            3,
447            btn,
448            hoffs,
449            v,
450            scl,
451            position=(xxx + 233, 27),
452            color=(0.7, 0.5, 0.9),
453        )
454        self._draw_dude(
455            1,
456            btn,
457            hoffs,
458            v,
459            scl,
460            position=(xxx + 266, 53),
461            color=(0.4, 0.5, 0.8),
462        )
463        ba.textwidget(
464            parent=self._root_widget,
465            draw_controller=btn,
466            position=(hoffs + scl * (-10), v + scl * 95),
467            size=(scl * button_width, scl * 50),
468            text=ba.Lstr(
469                resource='playModes.freeForAllText',
470                fallback_resource='freeForAllText',
471            ),
472            maxwidth=scl * button_width * 0.7,
473            h_align='center',
474            v_align='center',
475            color=(0.7, 0.9, 0.7, 1.0),
476            scale=scl * 1.9,
477        )
478        ba.textwidget(
479            parent=self._root_widget,
480            draw_controller=btn,
481            position=(hoffs + scl * (-10), v + (scl * 54)),
482            size=(scl * button_width, scl * 30),
483            text=ba.Lstr(resource=self._r + '.twoToEightPlayersText'),
484            h_align='center',
485            v_align='center',
486            scale=0.9 * scl,
487            flatness=1.0,
488            maxwidth=scl * button_width * 0.7,
489            color=clr,
490        )
491
492        if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
493            back_button.delete()
494            ba.containerwidget(
495                edit=self._root_widget,
496                on_cancel_call=self._back,
497                selected_child=self._coop_button
498                if self._is_main_menu
499                else self._teams_button,
500            )
501        else:
502            ba.buttonwidget(edit=back_button, on_activate_call=self._back)
503            ba.containerwidget(
504                edit=self._root_widget,
505                cancel_button=back_button,
506                selected_child=self._coop_button
507                if self._is_main_menu
508                else self._teams_button,
509            )
510
511        self._restore_state()
512
513    # noinspection PyUnresolvedReferences
514    @staticmethod
515    def _preload_modules() -> None:
516        """Preload modules we use (called in bg thread)."""
517        import bastd.ui.mainmenu as _unused1
518        import bastd.ui.account as _unused2
519        import bastd.ui.coop.browser as _unused3
520        import bastd.ui.playlist.browser as _unused4
521
522    def _back(self) -> None:
523        # pylint: disable=cyclic-import
524        if self._is_main_menu:
525            from bastd.ui.mainmenu import MainMenuWindow
526
527            self._save_state()
528            ba.app.ui.set_main_menu_window(
529                MainMenuWindow(transition='in_left').get_root_widget()
530            )
531            ba.containerwidget(
532                edit=self._root_widget, transition=self._transition_out
533            )
534        else:
535            from bastd.ui.gather import GatherWindow
536
537            self._save_state()
538            ba.app.ui.set_main_menu_window(
539                GatherWindow(transition='in_left').get_root_widget()
540            )
541            ba.containerwidget(
542                edit=self._root_widget, transition=self._transition_out
543            )
544
545    def _coop(self) -> None:
546        # pylint: disable=cyclic-import
547        from bastd.ui.account import show_sign_in_prompt
548        from bastd.ui.coop.browser import CoopBrowserWindow
549
550        if ba.internal.get_v1_account_state() != 'signed_in':
551            show_sign_in_prompt()
552            return
553        self._save_state()
554        ba.containerwidget(edit=self._root_widget, transition='out_left')
555        ba.app.ui.set_main_menu_window(
556            CoopBrowserWindow(origin_widget=self._coop_button).get_root_widget()
557        )
558
559    def _team_tourney(self) -> None:
560        # pylint: disable=cyclic-import
561        from bastd.ui.playlist.browser import PlaylistBrowserWindow
562
563        self._save_state()
564        ba.containerwidget(edit=self._root_widget, transition='out_left')
565        ba.app.ui.set_main_menu_window(
566            PlaylistBrowserWindow(
567                origin_widget=self._teams_button, sessiontype=ba.DualTeamSession
568            ).get_root_widget()
569        )
570
571    def _free_for_all(self) -> None:
572        # pylint: disable=cyclic-import
573        from bastd.ui.playlist.browser import PlaylistBrowserWindow
574
575        self._save_state()
576        ba.containerwidget(edit=self._root_widget, transition='out_left')
577        ba.app.ui.set_main_menu_window(
578            PlaylistBrowserWindow(
579                origin_widget=self._free_for_all_button,
580                sessiontype=ba.FreeForAllSession,
581            ).get_root_widget()
582        )
583
584    def _draw_dude(
585        self,
586        i: int,
587        btn: ba.Widget,
588        hoffs: float,
589        v: float,
590        scl: float,
591        position: tuple[float, float],
592        color: tuple[float, float, float],
593    ) -> None:
594        h_extra = -100
595        v_extra = 130
596        eye_color = (
597            0.7 * 1.0 + 0.3 * color[0],
598            0.7 * 1.0 + 0.3 * color[1],
599            0.7 * 1.0 + 0.3 * color[2],
600        )
601        if i == 0:
602            ba.imagewidget(
603                parent=self._root_widget,
604                draw_controller=btn,
605                position=(
606                    hoffs + scl * (h_extra + position[0]),
607                    v + scl * (v_extra + position[1]),
608                ),
609                size=(scl * 60, scl * 80),
610                color=color,
611                texture=self._lineup_tex,
612                model_transparent=self._lineup_1_transparent_model,
613            )
614            ba.imagewidget(
615                parent=self._root_widget,
616                draw_controller=btn,
617                position=(
618                    hoffs + scl * (h_extra + position[0] + 12),
619                    v + scl * (v_extra + position[1] + 53),
620                ),
621                size=(scl * 36, scl * 18),
622                texture=self._lineup_tex,
623                color=eye_color,
624                model_transparent=self._eyes_model,
625            )
626        elif i == 1:
627            ba.imagewidget(
628                parent=self._root_widget,
629                draw_controller=btn,
630                position=(
631                    hoffs + scl * (h_extra + position[0]),
632                    v + scl * (v_extra + position[1]),
633                ),
634                size=(scl * 45, scl * 90),
635                color=color,
636                texture=self._lineup_tex,
637                model_transparent=self._lineup_2_transparent_model,
638            )
639            ba.imagewidget(
640                parent=self._root_widget,
641                draw_controller=btn,
642                position=(
643                    hoffs + scl * (h_extra + position[0] + 5),
644                    v + scl * (v_extra + position[1] + 67),
645                ),
646                size=(scl * 32, scl * 16),
647                texture=self._lineup_tex,
648                color=eye_color,
649                model_transparent=self._eyes_model,
650            )
651        elif i == 2:
652            ba.imagewidget(
653                parent=self._root_widget,
654                draw_controller=btn,
655                position=(
656                    hoffs + scl * (h_extra + position[0]),
657                    v + scl * (v_extra + position[1]),
658                ),
659                size=(scl * 45, scl * 90),
660                color=color,
661                texture=self._lineup_tex,
662                model_transparent=self._lineup_3_transparent_model,
663            )
664            ba.imagewidget(
665                parent=self._root_widget,
666                draw_controller=btn,
667                position=(
668                    hoffs + scl * (h_extra + position[0] + 5),
669                    v + scl * (v_extra + position[1] + 59),
670                ),
671                size=(scl * 34, scl * 17),
672                texture=self._lineup_tex,
673                color=eye_color,
674                model_transparent=self._eyes_model,
675            )
676        elif i == 3:
677            ba.imagewidget(
678                parent=self._root_widget,
679                draw_controller=btn,
680                position=(
681                    hoffs + scl * (h_extra + position[0]),
682                    v + scl * (v_extra + position[1]),
683                ),
684                size=(scl * 48, scl * 96),
685                color=color,
686                texture=self._lineup_tex,
687                model_transparent=self._lineup_4_transparent_model,
688            )
689            ba.imagewidget(
690                parent=self._root_widget,
691                draw_controller=btn,
692                position=(
693                    hoffs + scl * (h_extra + position[0] + 2),
694                    v + scl * (v_extra + position[1] + 62),
695                ),
696                size=(scl * 38, scl * 19),
697                texture=self._lineup_tex,
698                color=eye_color,
699                model_transparent=self._eyes_model,
700            )
701
702    def _save_state(self) -> None:
703        try:
704            sel = self._root_widget.get_selected_child()
705            if sel == self._teams_button:
706                sel_name = 'Team Games'
707            elif self._coop_button is not None and sel == self._coop_button:
708                sel_name = 'Co-op Games'
709            elif sel == self._free_for_all_button:
710                sel_name = 'Free-for-All Games'
711            elif sel == self._back_button:
712                sel_name = 'Back'
713            else:
714                raise ValueError(f'unrecognized selection {sel}')
715            ba.app.ui.window_states[type(self)] = sel_name
716        except Exception:
717            ba.print_exception(f'Error saving state for {self}.')
718
719    def _restore_state(self) -> None:
720        try:
721            sel_name = ba.app.ui.window_states.get(type(self))
722            if sel_name == 'Team Games':
723                sel = self._teams_button
724            elif sel_name == 'Co-op Games' and self._coop_button is not None:
725                sel = self._coop_button
726            elif sel_name == 'Free-for-All Games':
727                sel = self._free_for_all_button
728            elif sel_name == 'Back':
729                sel = self._back_button
730            else:
731                sel = (
732                    self._coop_button
733                    if self._coop_button is not None
734                    else self._teams_button
735                )
736            ba.containerwidget(edit=self._root_widget, selected_child=sel)
737        except Exception:
738            ba.print_exception(f'Error restoring state for {self}.')
class PlayWindow(ba.ui.Window):
 17class PlayWindow(ba.Window):
 18    """Window for selecting overall play type."""
 19
 20    def __init__(
 21        self,
 22        transition: str = 'in_right',
 23        origin_widget: ba.Widget | None = None,
 24    ):
 25        # pylint: disable=too-many-statements
 26        # pylint: disable=too-many-locals
 27        import threading
 28
 29        # Preload some modules we use in a background thread so we won't
 30        # have a visual hitch when the user taps them.
 31        threading.Thread(target=self._preload_modules).start()
 32
 33        # We can currently be used either for main menu duty or for selecting
 34        # playlists (should make this more elegant/general).
 35        self._is_main_menu = not ba.app.ui.selecting_private_party_playlist
 36
 37        uiscale = ba.app.ui.uiscale
 38        width = 1000 if uiscale is ba.UIScale.SMALL else 800
 39        x_offs = 100 if uiscale is ba.UIScale.SMALL else 0
 40        height = 550
 41        button_width = 400
 42
 43        scale_origin: tuple[float, float] | None
 44        if origin_widget is not None:
 45            self._transition_out = 'out_scale'
 46            scale_origin = origin_widget.get_screen_space_center()
 47            transition = 'in_scale'
 48        else:
 49            self._transition_out = 'out_right'
 50            scale_origin = None
 51
 52        self._r = 'playWindow'
 53
 54        super().__init__(
 55            root_widget=ba.containerwidget(
 56                size=(width, height),
 57                transition=transition,
 58                toolbar_visibility='menu_full',
 59                scale_origin_stack_offset=scale_origin,
 60                scale=(
 61                    1.6
 62                    if uiscale is ba.UIScale.SMALL
 63                    else 0.9
 64                    if uiscale is ba.UIScale.MEDIUM
 65                    else 0.8
 66                ),
 67                stack_offset=(0, 0) if uiscale is ba.UIScale.SMALL else (0, 0),
 68            )
 69        )
 70        self._back_button = back_button = btn = ba.buttonwidget(
 71            parent=self._root_widget,
 72            position=(55 + x_offs, height - 132),
 73            size=(120, 60),
 74            scale=1.1,
 75            text_res_scale=1.5,
 76            text_scale=1.2,
 77            autoselect=True,
 78            label=ba.Lstr(resource='backText'),
 79            button_type='back',
 80        )
 81
 82        txt = ba.textwidget(
 83            parent=self._root_widget,
 84            position=(width * 0.5, height - 101),
 85            # position=(width * 0.5, height -
 86            #           (101 if main_menu else 61)),
 87            size=(0, 0),
 88            text=ba.Lstr(
 89                resource=(self._r + '.titleText')
 90                if self._is_main_menu
 91                else 'playlistsText'
 92            ),
 93            scale=1.7,
 94            res_scale=2.0,
 95            maxwidth=400,
 96            color=ba.app.ui.heading_color,
 97            h_align='center',
 98            v_align='center',
 99        )
100
101        ba.buttonwidget(
102            edit=btn,
103            button_type='backSmall',
104            size=(60, 60),
105            label=ba.charstr(ba.SpecialChar.BACK),
106        )
107        if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
108            ba.textwidget(edit=txt, text='')
109
110        v = height - (110 if self._is_main_menu else 90)
111        v -= 100
112        clr = (0.6, 0.7, 0.6, 1.0)
113        v -= 280 if self._is_main_menu else 180
114        v += 30 if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL else 0
115        hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
116        scl = 1.13 if self._is_main_menu else 0.68
117
118        self._lineup_tex = ba.gettexture('playerLineup')
119        angry_computer_transparent_model = ba.getmodel(
120            'angryComputerTransparent'
121        )
122        self._lineup_1_transparent_model = ba.getmodel(
123            'playerLineup1Transparent'
124        )
125        self._lineup_2_transparent_model = ba.getmodel(
126            'playerLineup2Transparent'
127        )
128        self._lineup_3_transparent_model = ba.getmodel(
129            'playerLineup3Transparent'
130        )
131        self._lineup_4_transparent_model = ba.getmodel(
132            'playerLineup4Transparent'
133        )
134        self._eyes_model = ba.getmodel('plasticEyesTransparent')
135
136        self._coop_button: ba.Widget | None = None
137
138        # Only show coop button in main-menu variant.
139        if self._is_main_menu:
140            self._coop_button = btn = ba.buttonwidget(
141                parent=self._root_widget,
142                position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
143                size=(
144                    scl * button_width,
145                    scl * (300 if self._is_main_menu else 360),
146                ),
147                extra_touch_border_scale=0.1,
148                autoselect=True,
149                label='',
150                button_type='square',
151                text_scale=1.13,
152                on_activate_call=self._coop,
153            )
154
155            if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
156                ba.widget(
157                    edit=btn,
158                    left_widget=ba.internal.get_special_widget('back_button'),
159                )
160                ba.widget(
161                    edit=btn,
162                    up_widget=ba.internal.get_special_widget('account_button'),
163                )
164                ba.widget(
165                    edit=btn,
166                    down_widget=ba.internal.get_special_widget(
167                        'settings_button'
168                    ),
169                )
170
171            self._draw_dude(
172                0,
173                btn,
174                hoffs,
175                v,
176                scl,
177                position=(140, 30),
178                color=(0.72, 0.4, 1.0),
179            )
180            self._draw_dude(
181                1,
182                btn,
183                hoffs,
184                v,
185                scl,
186                position=(185, 53),
187                color=(0.71, 0.5, 1.0),
188            )
189            self._draw_dude(
190                2,
191                btn,
192                hoffs,
193                v,
194                scl,
195                position=(220, 27),
196                color=(0.67, 0.44, 1.0),
197            )
198            self._draw_dude(
199                3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)
200            )
201            ba.imagewidget(
202                parent=self._root_widget,
203                draw_controller=btn,
204                position=(hoffs + scl * 230, v + scl * 153),
205                size=(scl * 115, scl * 115),
206                texture=self._lineup_tex,
207                model_transparent=angry_computer_transparent_model,
208            )
209
210            ba.textwidget(
211                parent=self._root_widget,
212                draw_controller=btn,
213                position=(hoffs + scl * (-10), v + scl * 95),
214                size=(scl * button_width, scl * 50),
215                text=ba.Lstr(
216                    resource='playModes.singlePlayerCoopText',
217                    fallback_resource='playModes.coopText',
218                ),
219                maxwidth=scl * button_width * 0.7,
220                res_scale=1.5,
221                h_align='center',
222                v_align='center',
223                color=(0.7, 0.9, 0.7, 1.0),
224                scale=scl * 2.3,
225            )
226
227            ba.textwidget(
228                parent=self._root_widget,
229                draw_controller=btn,
230                position=(hoffs + scl * (-10), v + (scl * 54)),
231                size=(scl * button_width, scl * 30),
232                text=ba.Lstr(resource=self._r + '.oneToFourPlayersText'),
233                h_align='center',
234                v_align='center',
235                scale=0.83 * scl,
236                flatness=1.0,
237                maxwidth=scl * button_width * 0.7,
238                color=clr,
239            )
240
241        scl = 0.5 if self._is_main_menu else 0.68
242        hoffs += 440 if self._is_main_menu else 216
243        v += 180 if self._is_main_menu else -68
244
245        self._teams_button = btn = ba.buttonwidget(
246            parent=self._root_widget,
247            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
248            size=(
249                scl * button_width,
250                scl * (300 if self._is_main_menu else 360),
251            ),
252            extra_touch_border_scale=0.1,
253            autoselect=True,
254            label='',
255            button_type='square',
256            text_scale=1.13,
257            on_activate_call=self._team_tourney,
258        )
259
260        if ba.app.ui.use_toolbars:
261            ba.widget(
262                edit=btn,
263                up_widget=ba.internal.get_special_widget('tickets_plus_button'),
264                right_widget=ba.internal.get_special_widget('party_button'),
265            )
266
267        xxx = -14
268        self._draw_dude(
269            2,
270            btn,
271            hoffs,
272            v,
273            scl,
274            position=(xxx + 148, 30),
275            color=(0.2, 0.4, 1.0),
276        )
277        self._draw_dude(
278            3,
279            btn,
280            hoffs,
281            v,
282            scl,
283            position=(xxx + 181, 53),
284            color=(0.3, 0.4, 1.0),
285        )
286        self._draw_dude(
287            1,
288            btn,
289            hoffs,
290            v,
291            scl,
292            position=(xxx + 216, 33),
293            color=(0.3, 0.5, 1.0),
294        )
295        self._draw_dude(
296            0,
297            btn,
298            hoffs,
299            v,
300            scl,
301            position=(xxx + 245, 57),
302            color=(0.3, 0.5, 1.0),
303        )
304
305        xxx = 155
306        self._draw_dude(
307            0,
308            btn,
309            hoffs,
310            v,
311            scl,
312            position=(xxx + 151, 30),
313            color=(1.0, 0.5, 0.4),
314        )
315        self._draw_dude(
316            1,
317            btn,
318            hoffs,
319            v,
320            scl,
321            position=(xxx + 189, 53),
322            color=(1.0, 0.58, 0.58),
323        )
324        self._draw_dude(
325            3,
326            btn,
327            hoffs,
328            v,
329            scl,
330            position=(xxx + 223, 27),
331            color=(1.0, 0.5, 0.5),
332        )
333        self._draw_dude(
334            2,
335            btn,
336            hoffs,
337            v,
338            scl,
339            position=(xxx + 257, 57),
340            color=(1.0, 0.5, 0.5),
341        )
342
343        ba.textwidget(
344            parent=self._root_widget,
345            draw_controller=btn,
346            position=(hoffs + scl * (-10), v + scl * 95),
347            size=(scl * button_width, scl * 50),
348            text=ba.Lstr(
349                resource='playModes.teamsText', fallback_resource='teamsText'
350            ),
351            res_scale=1.5,
352            maxwidth=scl * button_width * 0.7,
353            h_align='center',
354            v_align='center',
355            color=(0.7, 0.9, 0.7, 1.0),
356            scale=scl * 2.3,
357        )
358        ba.textwidget(
359            parent=self._root_widget,
360            draw_controller=btn,
361            position=(hoffs + scl * (-10), v + (scl * 54)),
362            size=(scl * button_width, scl * 30),
363            text=ba.Lstr(resource=self._r + '.twoToEightPlayersText'),
364            h_align='center',
365            v_align='center',
366            res_scale=1.5,
367            scale=0.9 * scl,
368            flatness=1.0,
369            maxwidth=scl * button_width * 0.7,
370            color=clr,
371        )
372
373        hoffs += 0 if self._is_main_menu else 300
374        v -= 155 if self._is_main_menu else 0
375        self._free_for_all_button = btn = ba.buttonwidget(
376            parent=self._root_widget,
377            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
378            size=(
379                scl * button_width,
380                scl * (300 if self._is_main_menu else 360),
381            ),
382            extra_touch_border_scale=0.1,
383            autoselect=True,
384            label='',
385            button_type='square',
386            text_scale=1.13,
387            on_activate_call=self._free_for_all,
388        )
389
390        xxx = -5
391        self._draw_dude(
392            0,
393            btn,
394            hoffs,
395            v,
396            scl,
397            position=(xxx + 140, 30),
398            color=(0.4, 1.0, 0.4),
399        )
400        self._draw_dude(
401            3,
402            btn,
403            hoffs,
404            v,
405            scl,
406            position=(xxx + 185, 53),
407            color=(1.0, 0.4, 0.5),
408        )
409        self._draw_dude(
410            1,
411            btn,
412            hoffs,
413            v,
414            scl,
415            position=(xxx + 220, 27),
416            color=(0.4, 0.5, 1.0),
417        )
418        self._draw_dude(
419            2,
420            btn,
421            hoffs,
422            v,
423            scl,
424            position=(xxx + 255, 57),
425            color=(0.5, 1.0, 0.4),
426        )
427        xxx = 140
428        self._draw_dude(
429            2,
430            btn,
431            hoffs,
432            v,
433            scl,
434            position=(xxx + 148, 30),
435            color=(1.0, 0.9, 0.4),
436        )
437        self._draw_dude(
438            0,
439            btn,
440            hoffs,
441            v,
442            scl,
443            position=(xxx + 182, 53),
444            color=(0.7, 1.0, 0.5),
445        )
446        self._draw_dude(
447            3,
448            btn,
449            hoffs,
450            v,
451            scl,
452            position=(xxx + 233, 27),
453            color=(0.7, 0.5, 0.9),
454        )
455        self._draw_dude(
456            1,
457            btn,
458            hoffs,
459            v,
460            scl,
461            position=(xxx + 266, 53),
462            color=(0.4, 0.5, 0.8),
463        )
464        ba.textwidget(
465            parent=self._root_widget,
466            draw_controller=btn,
467            position=(hoffs + scl * (-10), v + scl * 95),
468            size=(scl * button_width, scl * 50),
469            text=ba.Lstr(
470                resource='playModes.freeForAllText',
471                fallback_resource='freeForAllText',
472            ),
473            maxwidth=scl * button_width * 0.7,
474            h_align='center',
475            v_align='center',
476            color=(0.7, 0.9, 0.7, 1.0),
477            scale=scl * 1.9,
478        )
479        ba.textwidget(
480            parent=self._root_widget,
481            draw_controller=btn,
482            position=(hoffs + scl * (-10), v + (scl * 54)),
483            size=(scl * button_width, scl * 30),
484            text=ba.Lstr(resource=self._r + '.twoToEightPlayersText'),
485            h_align='center',
486            v_align='center',
487            scale=0.9 * scl,
488            flatness=1.0,
489            maxwidth=scl * button_width * 0.7,
490            color=clr,
491        )
492
493        if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
494            back_button.delete()
495            ba.containerwidget(
496                edit=self._root_widget,
497                on_cancel_call=self._back,
498                selected_child=self._coop_button
499                if self._is_main_menu
500                else self._teams_button,
501            )
502        else:
503            ba.buttonwidget(edit=back_button, on_activate_call=self._back)
504            ba.containerwidget(
505                edit=self._root_widget,
506                cancel_button=back_button,
507                selected_child=self._coop_button
508                if self._is_main_menu
509                else self._teams_button,
510            )
511
512        self._restore_state()
513
514    # noinspection PyUnresolvedReferences
515    @staticmethod
516    def _preload_modules() -> None:
517        """Preload modules we use (called in bg thread)."""
518        import bastd.ui.mainmenu as _unused1
519        import bastd.ui.account as _unused2
520        import bastd.ui.coop.browser as _unused3
521        import bastd.ui.playlist.browser as _unused4
522
523    def _back(self) -> None:
524        # pylint: disable=cyclic-import
525        if self._is_main_menu:
526            from bastd.ui.mainmenu import MainMenuWindow
527
528            self._save_state()
529            ba.app.ui.set_main_menu_window(
530                MainMenuWindow(transition='in_left').get_root_widget()
531            )
532            ba.containerwidget(
533                edit=self._root_widget, transition=self._transition_out
534            )
535        else:
536            from bastd.ui.gather import GatherWindow
537
538            self._save_state()
539            ba.app.ui.set_main_menu_window(
540                GatherWindow(transition='in_left').get_root_widget()
541            )
542            ba.containerwidget(
543                edit=self._root_widget, transition=self._transition_out
544            )
545
546    def _coop(self) -> None:
547        # pylint: disable=cyclic-import
548        from bastd.ui.account import show_sign_in_prompt
549        from bastd.ui.coop.browser import CoopBrowserWindow
550
551        if ba.internal.get_v1_account_state() != 'signed_in':
552            show_sign_in_prompt()
553            return
554        self._save_state()
555        ba.containerwidget(edit=self._root_widget, transition='out_left')
556        ba.app.ui.set_main_menu_window(
557            CoopBrowserWindow(origin_widget=self._coop_button).get_root_widget()
558        )
559
560    def _team_tourney(self) -> None:
561        # pylint: disable=cyclic-import
562        from bastd.ui.playlist.browser import PlaylistBrowserWindow
563
564        self._save_state()
565        ba.containerwidget(edit=self._root_widget, transition='out_left')
566        ba.app.ui.set_main_menu_window(
567            PlaylistBrowserWindow(
568                origin_widget=self._teams_button, sessiontype=ba.DualTeamSession
569            ).get_root_widget()
570        )
571
572    def _free_for_all(self) -> None:
573        # pylint: disable=cyclic-import
574        from bastd.ui.playlist.browser import PlaylistBrowserWindow
575
576        self._save_state()
577        ba.containerwidget(edit=self._root_widget, transition='out_left')
578        ba.app.ui.set_main_menu_window(
579            PlaylistBrowserWindow(
580                origin_widget=self._free_for_all_button,
581                sessiontype=ba.FreeForAllSession,
582            ).get_root_widget()
583        )
584
585    def _draw_dude(
586        self,
587        i: int,
588        btn: ba.Widget,
589        hoffs: float,
590        v: float,
591        scl: float,
592        position: tuple[float, float],
593        color: tuple[float, float, float],
594    ) -> None:
595        h_extra = -100
596        v_extra = 130
597        eye_color = (
598            0.7 * 1.0 + 0.3 * color[0],
599            0.7 * 1.0 + 0.3 * color[1],
600            0.7 * 1.0 + 0.3 * color[2],
601        )
602        if i == 0:
603            ba.imagewidget(
604                parent=self._root_widget,
605                draw_controller=btn,
606                position=(
607                    hoffs + scl * (h_extra + position[0]),
608                    v + scl * (v_extra + position[1]),
609                ),
610                size=(scl * 60, scl * 80),
611                color=color,
612                texture=self._lineup_tex,
613                model_transparent=self._lineup_1_transparent_model,
614            )
615            ba.imagewidget(
616                parent=self._root_widget,
617                draw_controller=btn,
618                position=(
619                    hoffs + scl * (h_extra + position[0] + 12),
620                    v + scl * (v_extra + position[1] + 53),
621                ),
622                size=(scl * 36, scl * 18),
623                texture=self._lineup_tex,
624                color=eye_color,
625                model_transparent=self._eyes_model,
626            )
627        elif i == 1:
628            ba.imagewidget(
629                parent=self._root_widget,
630                draw_controller=btn,
631                position=(
632                    hoffs + scl * (h_extra + position[0]),
633                    v + scl * (v_extra + position[1]),
634                ),
635                size=(scl * 45, scl * 90),
636                color=color,
637                texture=self._lineup_tex,
638                model_transparent=self._lineup_2_transparent_model,
639            )
640            ba.imagewidget(
641                parent=self._root_widget,
642                draw_controller=btn,
643                position=(
644                    hoffs + scl * (h_extra + position[0] + 5),
645                    v + scl * (v_extra + position[1] + 67),
646                ),
647                size=(scl * 32, scl * 16),
648                texture=self._lineup_tex,
649                color=eye_color,
650                model_transparent=self._eyes_model,
651            )
652        elif i == 2:
653            ba.imagewidget(
654                parent=self._root_widget,
655                draw_controller=btn,
656                position=(
657                    hoffs + scl * (h_extra + position[0]),
658                    v + scl * (v_extra + position[1]),
659                ),
660                size=(scl * 45, scl * 90),
661                color=color,
662                texture=self._lineup_tex,
663                model_transparent=self._lineup_3_transparent_model,
664            )
665            ba.imagewidget(
666                parent=self._root_widget,
667                draw_controller=btn,
668                position=(
669                    hoffs + scl * (h_extra + position[0] + 5),
670                    v + scl * (v_extra + position[1] + 59),
671                ),
672                size=(scl * 34, scl * 17),
673                texture=self._lineup_tex,
674                color=eye_color,
675                model_transparent=self._eyes_model,
676            )
677        elif i == 3:
678            ba.imagewidget(
679                parent=self._root_widget,
680                draw_controller=btn,
681                position=(
682                    hoffs + scl * (h_extra + position[0]),
683                    v + scl * (v_extra + position[1]),
684                ),
685                size=(scl * 48, scl * 96),
686                color=color,
687                texture=self._lineup_tex,
688                model_transparent=self._lineup_4_transparent_model,
689            )
690            ba.imagewidget(
691                parent=self._root_widget,
692                draw_controller=btn,
693                position=(
694                    hoffs + scl * (h_extra + position[0] + 2),
695                    v + scl * (v_extra + position[1] + 62),
696                ),
697                size=(scl * 38, scl * 19),
698                texture=self._lineup_tex,
699                color=eye_color,
700                model_transparent=self._eyes_model,
701            )
702
703    def _save_state(self) -> None:
704        try:
705            sel = self._root_widget.get_selected_child()
706            if sel == self._teams_button:
707                sel_name = 'Team Games'
708            elif self._coop_button is not None and sel == self._coop_button:
709                sel_name = 'Co-op Games'
710            elif sel == self._free_for_all_button:
711                sel_name = 'Free-for-All Games'
712            elif sel == self._back_button:
713                sel_name = 'Back'
714            else:
715                raise ValueError(f'unrecognized selection {sel}')
716            ba.app.ui.window_states[type(self)] = sel_name
717        except Exception:
718            ba.print_exception(f'Error saving state for {self}.')
719
720    def _restore_state(self) -> None:
721        try:
722            sel_name = ba.app.ui.window_states.get(type(self))
723            if sel_name == 'Team Games':
724                sel = self._teams_button
725            elif sel_name == 'Co-op Games' and self._coop_button is not None:
726                sel = self._coop_button
727            elif sel_name == 'Free-for-All Games':
728                sel = self._free_for_all_button
729            elif sel_name == 'Back':
730                sel = self._back_button
731            else:
732                sel = (
733                    self._coop_button
734                    if self._coop_button is not None
735                    else self._teams_button
736                )
737            ba.containerwidget(edit=self._root_widget, selected_child=sel)
738        except Exception:
739            ba.print_exception(f'Error restoring state for {self}.')

Window for selecting overall play type.

PlayWindow( transition: str = 'in_right', origin_widget: _ba.Widget | None = None)
 20    def __init__(
 21        self,
 22        transition: str = 'in_right',
 23        origin_widget: ba.Widget | None = None,
 24    ):
 25        # pylint: disable=too-many-statements
 26        # pylint: disable=too-many-locals
 27        import threading
 28
 29        # Preload some modules we use in a background thread so we won't
 30        # have a visual hitch when the user taps them.
 31        threading.Thread(target=self._preload_modules).start()
 32
 33        # We can currently be used either for main menu duty or for selecting
 34        # playlists (should make this more elegant/general).
 35        self._is_main_menu = not ba.app.ui.selecting_private_party_playlist
 36
 37        uiscale = ba.app.ui.uiscale
 38        width = 1000 if uiscale is ba.UIScale.SMALL else 800
 39        x_offs = 100 if uiscale is ba.UIScale.SMALL else 0
 40        height = 550
 41        button_width = 400
 42
 43        scale_origin: tuple[float, float] | None
 44        if origin_widget is not None:
 45            self._transition_out = 'out_scale'
 46            scale_origin = origin_widget.get_screen_space_center()
 47            transition = 'in_scale'
 48        else:
 49            self._transition_out = 'out_right'
 50            scale_origin = None
 51
 52        self._r = 'playWindow'
 53
 54        super().__init__(
 55            root_widget=ba.containerwidget(
 56                size=(width, height),
 57                transition=transition,
 58                toolbar_visibility='menu_full',
 59                scale_origin_stack_offset=scale_origin,
 60                scale=(
 61                    1.6
 62                    if uiscale is ba.UIScale.SMALL
 63                    else 0.9
 64                    if uiscale is ba.UIScale.MEDIUM
 65                    else 0.8
 66                ),
 67                stack_offset=(0, 0) if uiscale is ba.UIScale.SMALL else (0, 0),
 68            )
 69        )
 70        self._back_button = back_button = btn = ba.buttonwidget(
 71            parent=self._root_widget,
 72            position=(55 + x_offs, height - 132),
 73            size=(120, 60),
 74            scale=1.1,
 75            text_res_scale=1.5,
 76            text_scale=1.2,
 77            autoselect=True,
 78            label=ba.Lstr(resource='backText'),
 79            button_type='back',
 80        )
 81
 82        txt = ba.textwidget(
 83            parent=self._root_widget,
 84            position=(width * 0.5, height - 101),
 85            # position=(width * 0.5, height -
 86            #           (101 if main_menu else 61)),
 87            size=(0, 0),
 88            text=ba.Lstr(
 89                resource=(self._r + '.titleText')
 90                if self._is_main_menu
 91                else 'playlistsText'
 92            ),
 93            scale=1.7,
 94            res_scale=2.0,
 95            maxwidth=400,
 96            color=ba.app.ui.heading_color,
 97            h_align='center',
 98            v_align='center',
 99        )
100
101        ba.buttonwidget(
102            edit=btn,
103            button_type='backSmall',
104            size=(60, 60),
105            label=ba.charstr(ba.SpecialChar.BACK),
106        )
107        if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
108            ba.textwidget(edit=txt, text='')
109
110        v = height - (110 if self._is_main_menu else 90)
111        v -= 100
112        clr = (0.6, 0.7, 0.6, 1.0)
113        v -= 280 if self._is_main_menu else 180
114        v += 30 if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL else 0
115        hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
116        scl = 1.13 if self._is_main_menu else 0.68
117
118        self._lineup_tex = ba.gettexture('playerLineup')
119        angry_computer_transparent_model = ba.getmodel(
120            'angryComputerTransparent'
121        )
122        self._lineup_1_transparent_model = ba.getmodel(
123            'playerLineup1Transparent'
124        )
125        self._lineup_2_transparent_model = ba.getmodel(
126            'playerLineup2Transparent'
127        )
128        self._lineup_3_transparent_model = ba.getmodel(
129            'playerLineup3Transparent'
130        )
131        self._lineup_4_transparent_model = ba.getmodel(
132            'playerLineup4Transparent'
133        )
134        self._eyes_model = ba.getmodel('plasticEyesTransparent')
135
136        self._coop_button: ba.Widget | None = None
137
138        # Only show coop button in main-menu variant.
139        if self._is_main_menu:
140            self._coop_button = btn = ba.buttonwidget(
141                parent=self._root_widget,
142                position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
143                size=(
144                    scl * button_width,
145                    scl * (300 if self._is_main_menu else 360),
146                ),
147                extra_touch_border_scale=0.1,
148                autoselect=True,
149                label='',
150                button_type='square',
151                text_scale=1.13,
152                on_activate_call=self._coop,
153            )
154
155            if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
156                ba.widget(
157                    edit=btn,
158                    left_widget=ba.internal.get_special_widget('back_button'),
159                )
160                ba.widget(
161                    edit=btn,
162                    up_widget=ba.internal.get_special_widget('account_button'),
163                )
164                ba.widget(
165                    edit=btn,
166                    down_widget=ba.internal.get_special_widget(
167                        'settings_button'
168                    ),
169                )
170
171            self._draw_dude(
172                0,
173                btn,
174                hoffs,
175                v,
176                scl,
177                position=(140, 30),
178                color=(0.72, 0.4, 1.0),
179            )
180            self._draw_dude(
181                1,
182                btn,
183                hoffs,
184                v,
185                scl,
186                position=(185, 53),
187                color=(0.71, 0.5, 1.0),
188            )
189            self._draw_dude(
190                2,
191                btn,
192                hoffs,
193                v,
194                scl,
195                position=(220, 27),
196                color=(0.67, 0.44, 1.0),
197            )
198            self._draw_dude(
199                3, btn, hoffs, v, scl, position=(255, 57), color=(0.7, 0.3, 1.0)
200            )
201            ba.imagewidget(
202                parent=self._root_widget,
203                draw_controller=btn,
204                position=(hoffs + scl * 230, v + scl * 153),
205                size=(scl * 115, scl * 115),
206                texture=self._lineup_tex,
207                model_transparent=angry_computer_transparent_model,
208            )
209
210            ba.textwidget(
211                parent=self._root_widget,
212                draw_controller=btn,
213                position=(hoffs + scl * (-10), v + scl * 95),
214                size=(scl * button_width, scl * 50),
215                text=ba.Lstr(
216                    resource='playModes.singlePlayerCoopText',
217                    fallback_resource='playModes.coopText',
218                ),
219                maxwidth=scl * button_width * 0.7,
220                res_scale=1.5,
221                h_align='center',
222                v_align='center',
223                color=(0.7, 0.9, 0.7, 1.0),
224                scale=scl * 2.3,
225            )
226
227            ba.textwidget(
228                parent=self._root_widget,
229                draw_controller=btn,
230                position=(hoffs + scl * (-10), v + (scl * 54)),
231                size=(scl * button_width, scl * 30),
232                text=ba.Lstr(resource=self._r + '.oneToFourPlayersText'),
233                h_align='center',
234                v_align='center',
235                scale=0.83 * scl,
236                flatness=1.0,
237                maxwidth=scl * button_width * 0.7,
238                color=clr,
239            )
240
241        scl = 0.5 if self._is_main_menu else 0.68
242        hoffs += 440 if self._is_main_menu else 216
243        v += 180 if self._is_main_menu else -68
244
245        self._teams_button = btn = ba.buttonwidget(
246            parent=self._root_widget,
247            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
248            size=(
249                scl * button_width,
250                scl * (300 if self._is_main_menu else 360),
251            ),
252            extra_touch_border_scale=0.1,
253            autoselect=True,
254            label='',
255            button_type='square',
256            text_scale=1.13,
257            on_activate_call=self._team_tourney,
258        )
259
260        if ba.app.ui.use_toolbars:
261            ba.widget(
262                edit=btn,
263                up_widget=ba.internal.get_special_widget('tickets_plus_button'),
264                right_widget=ba.internal.get_special_widget('party_button'),
265            )
266
267        xxx = -14
268        self._draw_dude(
269            2,
270            btn,
271            hoffs,
272            v,
273            scl,
274            position=(xxx + 148, 30),
275            color=(0.2, 0.4, 1.0),
276        )
277        self._draw_dude(
278            3,
279            btn,
280            hoffs,
281            v,
282            scl,
283            position=(xxx + 181, 53),
284            color=(0.3, 0.4, 1.0),
285        )
286        self._draw_dude(
287            1,
288            btn,
289            hoffs,
290            v,
291            scl,
292            position=(xxx + 216, 33),
293            color=(0.3, 0.5, 1.0),
294        )
295        self._draw_dude(
296            0,
297            btn,
298            hoffs,
299            v,
300            scl,
301            position=(xxx + 245, 57),
302            color=(0.3, 0.5, 1.0),
303        )
304
305        xxx = 155
306        self._draw_dude(
307            0,
308            btn,
309            hoffs,
310            v,
311            scl,
312            position=(xxx + 151, 30),
313            color=(1.0, 0.5, 0.4),
314        )
315        self._draw_dude(
316            1,
317            btn,
318            hoffs,
319            v,
320            scl,
321            position=(xxx + 189, 53),
322            color=(1.0, 0.58, 0.58),
323        )
324        self._draw_dude(
325            3,
326            btn,
327            hoffs,
328            v,
329            scl,
330            position=(xxx + 223, 27),
331            color=(1.0, 0.5, 0.5),
332        )
333        self._draw_dude(
334            2,
335            btn,
336            hoffs,
337            v,
338            scl,
339            position=(xxx + 257, 57),
340            color=(1.0, 0.5, 0.5),
341        )
342
343        ba.textwidget(
344            parent=self._root_widget,
345            draw_controller=btn,
346            position=(hoffs + scl * (-10), v + scl * 95),
347            size=(scl * button_width, scl * 50),
348            text=ba.Lstr(
349                resource='playModes.teamsText', fallback_resource='teamsText'
350            ),
351            res_scale=1.5,
352            maxwidth=scl * button_width * 0.7,
353            h_align='center',
354            v_align='center',
355            color=(0.7, 0.9, 0.7, 1.0),
356            scale=scl * 2.3,
357        )
358        ba.textwidget(
359            parent=self._root_widget,
360            draw_controller=btn,
361            position=(hoffs + scl * (-10), v + (scl * 54)),
362            size=(scl * button_width, scl * 30),
363            text=ba.Lstr(resource=self._r + '.twoToEightPlayersText'),
364            h_align='center',
365            v_align='center',
366            res_scale=1.5,
367            scale=0.9 * scl,
368            flatness=1.0,
369            maxwidth=scl * button_width * 0.7,
370            color=clr,
371        )
372
373        hoffs += 0 if self._is_main_menu else 300
374        v -= 155 if self._is_main_menu else 0
375        self._free_for_all_button = btn = ba.buttonwidget(
376            parent=self._root_widget,
377            position=(hoffs, v + (scl * 15 if self._is_main_menu else 0)),
378            size=(
379                scl * button_width,
380                scl * (300 if self._is_main_menu else 360),
381            ),
382            extra_touch_border_scale=0.1,
383            autoselect=True,
384            label='',
385            button_type='square',
386            text_scale=1.13,
387            on_activate_call=self._free_for_all,
388        )
389
390        xxx = -5
391        self._draw_dude(
392            0,
393            btn,
394            hoffs,
395            v,
396            scl,
397            position=(xxx + 140, 30),
398            color=(0.4, 1.0, 0.4),
399        )
400        self._draw_dude(
401            3,
402            btn,
403            hoffs,
404            v,
405            scl,
406            position=(xxx + 185, 53),
407            color=(1.0, 0.4, 0.5),
408        )
409        self._draw_dude(
410            1,
411            btn,
412            hoffs,
413            v,
414            scl,
415            position=(xxx + 220, 27),
416            color=(0.4, 0.5, 1.0),
417        )
418        self._draw_dude(
419            2,
420            btn,
421            hoffs,
422            v,
423            scl,
424            position=(xxx + 255, 57),
425            color=(0.5, 1.0, 0.4),
426        )
427        xxx = 140
428        self._draw_dude(
429            2,
430            btn,
431            hoffs,
432            v,
433            scl,
434            position=(xxx + 148, 30),
435            color=(1.0, 0.9, 0.4),
436        )
437        self._draw_dude(
438            0,
439            btn,
440            hoffs,
441            v,
442            scl,
443            position=(xxx + 182, 53),
444            color=(0.7, 1.0, 0.5),
445        )
446        self._draw_dude(
447            3,
448            btn,
449            hoffs,
450            v,
451            scl,
452            position=(xxx + 233, 27),
453            color=(0.7, 0.5, 0.9),
454        )
455        self._draw_dude(
456            1,
457            btn,
458            hoffs,
459            v,
460            scl,
461            position=(xxx + 266, 53),
462            color=(0.4, 0.5, 0.8),
463        )
464        ba.textwidget(
465            parent=self._root_widget,
466            draw_controller=btn,
467            position=(hoffs + scl * (-10), v + scl * 95),
468            size=(scl * button_width, scl * 50),
469            text=ba.Lstr(
470                resource='playModes.freeForAllText',
471                fallback_resource='freeForAllText',
472            ),
473            maxwidth=scl * button_width * 0.7,
474            h_align='center',
475            v_align='center',
476            color=(0.7, 0.9, 0.7, 1.0),
477            scale=scl * 1.9,
478        )
479        ba.textwidget(
480            parent=self._root_widget,
481            draw_controller=btn,
482            position=(hoffs + scl * (-10), v + (scl * 54)),
483            size=(scl * button_width, scl * 30),
484            text=ba.Lstr(resource=self._r + '.twoToEightPlayersText'),
485            h_align='center',
486            v_align='center',
487            scale=0.9 * scl,
488            flatness=1.0,
489            maxwidth=scl * button_width * 0.7,
490            color=clr,
491        )
492
493        if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
494            back_button.delete()
495            ba.containerwidget(
496                edit=self._root_widget,
497                on_cancel_call=self._back,
498                selected_child=self._coop_button
499                if self._is_main_menu
500                else self._teams_button,
501            )
502        else:
503            ba.buttonwidget(edit=back_button, on_activate_call=self._back)
504            ba.containerwidget(
505                edit=self._root_widget,
506                cancel_button=back_button,
507                selected_child=self._coop_button
508                if self._is_main_menu
509                else self._teams_button,
510            )
511
512        self._restore_state()
Inherited Members
ba.ui.Window
get_root_widget