bastd.ui.kiosk

UI functionality for running the game in kiosk mode.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""UI functionality for running the game in kiosk mode."""
  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 KioskWindow(ba.Window):
 17    """Kiosk mode window."""
 18
 19    def __init__(self, transition: str = 'in_right'):
 20        # pylint: disable=too-many-locals, too-many-statements
 21        from bastd.ui.confirm import QuitWindow
 22
 23        self._width = 720.0
 24        self._height = 340.0
 25
 26        def _do_cancel() -> None:
 27            QuitWindow(swish=True, back=True)
 28
 29        super().__init__(
 30            root_widget=ba.containerwidget(
 31                size=(self._width, self._height),
 32                transition=transition,
 33                on_cancel_call=_do_cancel,
 34                background=False,
 35                stack_offset=(0, -130),
 36            )
 37        )
 38
 39        self._r = 'kioskWindow'
 40
 41        self._show_multiplayer = False
 42
 43        # Let's reset all random player names every time we hit the main menu.
 44        ba.internal.reset_random_player_names()
 45
 46        # Reset achievements too (at least locally).
 47        ba.app.config['Achievements'] = {}
 48
 49        t_delay_base = 0.0
 50        t_delay_scale = 0.0
 51        if not ba.app.did_menu_intro:
 52            t_delay_base = 1.0
 53            t_delay_scale = 1.0
 54
 55        model_opaque = ba.getmodel('level_select_button_opaque')
 56        model_transparent = ba.getmodel('level_select_button_transparent')
 57        mask_tex = ba.gettexture('mapPreviewMask')
 58
 59        y_extra = 130.0 + (0.0 if self._show_multiplayer else -130.0)
 60        b_width = 250.0
 61        b_height = 200.0
 62        b_space = 280.0
 63        b_v = 80.0 + y_extra
 64        label_height = 130.0 + y_extra
 65        img_width = 180.0
 66        img_v = 158.0 + y_extra
 67
 68        if self._show_multiplayer:
 69            tdelay = t_delay_base + t_delay_scale * 1.3
 70            ba.textwidget(
 71                parent=self._root_widget,
 72                size=(0, 0),
 73                position=(self._width * 0.5, self._height + y_extra - 44),
 74                transition_delay=tdelay,
 75                text=ba.Lstr(resource=self._r + '.singlePlayerExamplesText'),
 76                flatness=1.0,
 77                scale=1.2,
 78                h_align='center',
 79                v_align='center',
 80                shadow=1.0,
 81            )
 82        else:
 83            tdelay = t_delay_base + t_delay_scale * 0.7
 84            ba.textwidget(
 85                parent=self._root_widget,
 86                size=(0, 0),
 87                position=(self._width * 0.5, self._height + y_extra - 34),
 88                transition_delay=tdelay,
 89                text=(
 90                    ba.Lstr(
 91                        resource='demoText',
 92                        fallback_resource='mainMenu.demoMenuText',
 93                    )
 94                    if ba.app.demo_mode
 95                    else 'ARCADE'
 96                ),
 97                flatness=1.0,
 98                scale=1.2,
 99                h_align='center',
100                v_align='center',
101                shadow=1.0,
102            )
103        h = self._width * 0.5 - b_space
104        tdelay = t_delay_base + t_delay_scale * 0.7
105        self._b1 = btn = ba.buttonwidget(
106            parent=self._root_widget,
107            autoselect=True,
108            size=(b_width, b_height),
109            on_activate_call=ba.Call(self._do_game, 'easy'),
110            transition_delay=tdelay,
111            position=(h - b_width * 0.5, b_v),
112            label='',
113            button_type='square',
114        )
115        ba.textwidget(
116            parent=self._root_widget,
117            draw_controller=btn,
118            transition_delay=tdelay,
119            size=(0, 0),
120            position=(h, label_height),
121            maxwidth=b_width * 0.7,
122            text=ba.Lstr(resource=self._r + '.easyText'),
123            scale=1.3,
124            h_align='center',
125            v_align='center',
126        )
127        ba.imagewidget(
128            parent=self._root_widget,
129            draw_controller=btn,
130            size=(img_width, 0.5 * img_width),
131            transition_delay=tdelay,
132            position=(h - img_width * 0.5, img_v),
133            texture=ba.gettexture('doomShroomPreview'),
134            model_opaque=model_opaque,
135            model_transparent=model_transparent,
136            mask_texture=mask_tex,
137        )
138        h = self._width * 0.5
139        tdelay = t_delay_base + t_delay_scale * 0.65
140        self._b2 = btn = ba.buttonwidget(
141            parent=self._root_widget,
142            autoselect=True,
143            size=(b_width, b_height),
144            on_activate_call=ba.Call(self._do_game, 'medium'),
145            position=(h - b_width * 0.5, b_v),
146            label='',
147            button_type='square',
148            transition_delay=tdelay,
149        )
150        ba.textwidget(
151            parent=self._root_widget,
152            draw_controller=btn,
153            transition_delay=tdelay,
154            size=(0, 0),
155            position=(h, label_height),
156            maxwidth=b_width * 0.7,
157            text=ba.Lstr(resource=self._r + '.mediumText'),
158            scale=1.3,
159            h_align='center',
160            v_align='center',
161        )
162        ba.imagewidget(
163            parent=self._root_widget,
164            draw_controller=btn,
165            size=(img_width, 0.5 * img_width),
166            transition_delay=tdelay,
167            position=(h - img_width * 0.5, img_v),
168            texture=ba.gettexture('footballStadiumPreview'),
169            model_opaque=model_opaque,
170            model_transparent=model_transparent,
171            mask_texture=mask_tex,
172        )
173        h = self._width * 0.5 + b_space
174        tdelay = t_delay_base + t_delay_scale * 0.6
175        self._b3 = btn = ba.buttonwidget(
176            parent=self._root_widget,
177            autoselect=True,
178            size=(b_width, b_height),
179            on_activate_call=ba.Call(self._do_game, 'hard'),
180            transition_delay=tdelay,
181            position=(h - b_width * 0.5, b_v),
182            label='',
183            button_type='square',
184        )
185        ba.textwidget(
186            parent=self._root_widget,
187            draw_controller=btn,
188            transition_delay=tdelay,
189            size=(0, 0),
190            position=(h, label_height),
191            maxwidth=b_width * 0.7,
192            text='Hard',
193            scale=1.3,
194            h_align='center',
195            v_align='center',
196        )
197        ba.imagewidget(
198            parent=self._root_widget,
199            draw_controller=btn,
200            transition_delay=tdelay,
201            size=(img_width, 0.5 * img_width),
202            position=(h - img_width * 0.5, img_v),
203            texture=ba.gettexture('courtyardPreview'),
204            model_opaque=model_opaque,
205            model_transparent=model_transparent,
206            mask_texture=mask_tex,
207        )
208        if not ba.app.did_menu_intro:
209            ba.app.did_menu_intro = True
210
211        self._b4: ba.Widget | None
212        self._b5: ba.Widget | None
213        self._b6: ba.Widget | None
214
215        if bool(False):
216            ba.textwidget(
217                parent=self._root_widget,
218                size=(0, 0),
219                position=(self._width * 0.5, self._height + y_extra - 44),
220                transition_delay=tdelay,
221                text=ba.Lstr(resource=self._r + '.versusExamplesText'),
222                flatness=1.0,
223                scale=1.2,
224                h_align='center',
225                v_align='center',
226                shadow=1.0,
227            )
228            h = self._width * 0.5 - b_space
229            tdelay = t_delay_base + t_delay_scale * 0.7
230            self._b4 = btn = ba.buttonwidget(
231                parent=self._root_widget,
232                autoselect=True,
233                size=(b_width, b_height),
234                on_activate_call=ba.Call(self._do_game, 'ctf'),
235                transition_delay=tdelay,
236                position=(h - b_width * 0.5, b_v),
237                label='',
238                button_type='square',
239            )
240            ba.textwidget(
241                parent=self._root_widget,
242                draw_controller=btn,
243                transition_delay=tdelay,
244                size=(0, 0),
245                position=(h, label_height),
246                maxwidth=b_width * 0.7,
247                text=ba.Lstr(translate=('gameNames', 'Capture the Flag')),
248                scale=1.3,
249                h_align='center',
250                v_align='center',
251            )
252            ba.imagewidget(
253                parent=self._root_widget,
254                draw_controller=btn,
255                size=(img_width, 0.5 * img_width),
256                transition_delay=tdelay,
257                position=(h - img_width * 0.5, img_v),
258                texture=ba.gettexture('bridgitPreview'),
259                model_opaque=model_opaque,
260                model_transparent=model_transparent,
261                mask_texture=mask_tex,
262            )
263
264            h = self._width * 0.5
265            tdelay = t_delay_base + t_delay_scale * 0.65
266            self._b5 = btn = ba.buttonwidget(
267                parent=self._root_widget,
268                autoselect=True,
269                size=(b_width, b_height),
270                on_activate_call=ba.Call(self._do_game, 'hockey'),
271                position=(h - b_width * 0.5, b_v),
272                label='',
273                button_type='square',
274                transition_delay=tdelay,
275            )
276            ba.textwidget(
277                parent=self._root_widget,
278                draw_controller=btn,
279                transition_delay=tdelay,
280                size=(0, 0),
281                position=(h, label_height),
282                maxwidth=b_width * 0.7,
283                text=ba.Lstr(translate=('gameNames', 'Hockey')),
284                scale=1.3,
285                h_align='center',
286                v_align='center',
287            )
288            ba.imagewidget(
289                parent=self._root_widget,
290                draw_controller=btn,
291                size=(img_width, 0.5 * img_width),
292                transition_delay=tdelay,
293                position=(h - img_width * 0.5, img_v),
294                texture=ba.gettexture('hockeyStadiumPreview'),
295                model_opaque=model_opaque,
296                model_transparent=model_transparent,
297                mask_texture=mask_tex,
298            )
299            h = self._width * 0.5 + b_space
300            tdelay = t_delay_base + t_delay_scale * 0.6
301            self._b6 = btn = ba.buttonwidget(
302                parent=self._root_widget,
303                autoselect=True,
304                size=(b_width, b_height),
305                on_activate_call=ba.Call(self._do_game, 'epic'),
306                transition_delay=tdelay,
307                position=(h - b_width * 0.5, b_v),
308                label='',
309                button_type='square',
310            )
311            ba.textwidget(
312                parent=self._root_widget,
313                draw_controller=btn,
314                transition_delay=tdelay,
315                size=(0, 0),
316                position=(h, label_height),
317                maxwidth=b_width * 0.7,
318                text=ba.Lstr(resource=self._r + '.epicModeText'),
319                scale=1.3,
320                h_align='center',
321                v_align='center',
322            )
323            ba.imagewidget(
324                parent=self._root_widget,
325                draw_controller=btn,
326                transition_delay=tdelay,
327                size=(img_width, 0.5 * img_width),
328                position=(h - img_width * 0.5, img_v),
329                texture=ba.gettexture('tipTopPreview'),
330                model_opaque=model_opaque,
331                model_transparent=model_transparent,
332                mask_texture=mask_tex,
333            )
334        else:
335            self._b4 = self._b5 = self._b6 = None
336
337        self._b7: ba.Widget | None
338        if ba.app.arcade_mode:
339            self._b7 = ba.buttonwidget(
340                parent=self._root_widget,
341                autoselect=True,
342                size=(b_width, 50),
343                color=(0.45, 0.55, 0.45),
344                textcolor=(0.7, 0.8, 0.7),
345                scale=0.5,
346                position=(self._width * 0.5 - 60.0, b_v - 70.0),
347                transition_delay=tdelay,
348                label=ba.Lstr(resource=self._r + '.fullMenuText'),
349                on_activate_call=self._do_full_menu,
350            )
351        else:
352            self._b7 = None
353        self._restore_state()
354        self._update()
355        self._update_timer = ba.Timer(
356            1.0,
357            ba.WeakCall(self._update),
358            timetype=ba.TimeType.REAL,
359            repeat=True,
360        )
361
362    def _restore_state(self) -> None:
363        sel_name = ba.app.ui.window_states.get(type(self))
364        sel: ba.Widget | None
365        if sel_name == 'b1':
366            sel = self._b1
367        elif sel_name == 'b2':
368            sel = self._b2
369        elif sel_name == 'b3':
370            sel = self._b3
371        elif sel_name == 'b4':
372            sel = self._b4
373        elif sel_name == 'b5':
374            sel = self._b5
375        elif sel_name == 'b6':
376            sel = self._b6
377        elif sel_name == 'b7':
378            sel = self._b7
379        else:
380            sel = self._b1
381        if sel:
382            ba.containerwidget(edit=self._root_widget, selected_child=sel)
383
384    def _save_state(self) -> None:
385        sel = self._root_widget.get_selected_child()
386        if sel == self._b1:
387            sel_name = 'b1'
388        elif sel == self._b2:
389            sel_name = 'b2'
390        elif sel == self._b3:
391            sel_name = 'b3'
392        elif sel == self._b4:
393            sel_name = 'b4'
394        elif sel == self._b5:
395            sel_name = 'b5'
396        elif sel == self._b6:
397            sel_name = 'b6'
398        elif sel == self._b7:
399            sel_name = 'b7'
400        else:
401            sel_name = 'b1'
402        ba.app.ui.window_states[type(self)] = sel_name
403
404    def _update(self) -> None:
405        # Kiosk-mode is designed to be used signed-out... try for force
406        # the issue.
407        if ba.internal.get_v1_account_state() == 'signed_in':
408            # _bs.sign_out()
409            # FIXME: Try to delete player profiles here too.
410            pass
411        else:
412            # Also make sure there's no player profiles.
413            appconfig = ba.app.config
414            appconfig['Player Profiles'] = {}
415
416    def _do_game(self, mode: str) -> None:
417        self._save_state()
418        if mode in ['epic', 'ctf', 'hockey']:
419            appconfig = ba.app.config
420            if 'Team Tournament Playlists' not in appconfig:
421                appconfig['Team Tournament Playlists'] = {}
422            if 'Free-for-All Playlists' not in appconfig:
423                appconfig['Free-for-All Playlists'] = {}
424            appconfig['Show Tutorial'] = False
425            if mode == 'epic':
426                appconfig['Free-for-All Playlists']['Just Epic Elim'] = [
427                    {
428                        'settings': {
429                            'Epic Mode': 1,
430                            'Lives Per Player': 1,
431                            'Respawn Times': 1.0,
432                            'Time Limit': 0,
433                            'map': 'Tip Top',
434                        },
435                        'type': 'bs_elimination.EliminationGame',
436                    }
437                ]
438                appconfig['Free-for-All Playlist Selection'] = 'Just Epic Elim'
439                ba.internal.fade_screen(
440                    False,
441                    endcall=ba.Call(
442                        ba.pushcall,
443                        ba.Call(
444                            ba.internal.new_host_session, ba.FreeForAllSession
445                        ),
446                    ),
447                )
448            else:
449                if mode == 'ctf':
450                    appconfig['Team Tournament Playlists']['Just CTF'] = [
451                        {
452                            'settings': {
453                                'Epic Mode': False,
454                                'Flag Idle Return Time': 30,
455                                'Flag Touch Return Time': 0,
456                                'Respawn Times': 1.0,
457                                'Score to Win': 3,
458                                'Time Limit': 0,
459                                'map': 'Bridgit',
460                            },
461                            'type': 'bs_capture_the_flag.CTFGame',
462                        }
463                    ]
464                    appconfig['Team Tournament Playlist Selection'] = 'Just CTF'
465                else:
466                    appconfig['Team Tournament Playlists']['Just Hockey'] = [
467                        {
468                            'settings': {
469                                'Respawn Times': 1.0,
470                                'Score to Win': 1,
471                                'Time Limit': 0,
472                                'map': 'Hockey Stadium',
473                            },
474                            'type': 'bs_hockey.HockeyGame',
475                        }
476                    ]
477                    appconfig[
478                        'Team Tournament Playlist Selection'
479                    ] = 'Just Hockey'
480                ba.internal.fade_screen(
481                    False,
482                    endcall=ba.Call(
483                        ba.pushcall,
484                        ba.Call(
485                            ba.internal.new_host_session, ba.DualTeamSession
486                        ),
487                    ),
488                )
489            ba.containerwidget(edit=self._root_widget, transition='out_left')
490            return
491
492        game = (
493            'Easy:Onslaught Training'
494            if mode == 'easy'
495            else 'Easy:Rookie Football'
496            if mode == 'medium'
497            else 'Easy:Uber Onslaught'
498        )
499        cfg = ba.app.config
500        cfg['Selected Coop Game'] = game
501        cfg.commit()
502        if ba.app.launch_coop_game(game, force=True):
503            ba.containerwidget(edit=self._root_widget, transition='out_left')
504
505    def _do_full_menu(self) -> None:
506        from bastd.ui.mainmenu import MainMenuWindow
507
508        self._save_state()
509        ba.containerwidget(edit=self._root_widget, transition='out_left')
510        ba.app.did_menu_intro = True  # prevent delayed transition-in
511        ba.app.ui.set_main_menu_window(MainMenuWindow().get_root_widget())
class KioskWindow(ba.ui.Window):
 17class KioskWindow(ba.Window):
 18    """Kiosk mode window."""
 19
 20    def __init__(self, transition: str = 'in_right'):
 21        # pylint: disable=too-many-locals, too-many-statements
 22        from bastd.ui.confirm import QuitWindow
 23
 24        self._width = 720.0
 25        self._height = 340.0
 26
 27        def _do_cancel() -> None:
 28            QuitWindow(swish=True, back=True)
 29
 30        super().__init__(
 31            root_widget=ba.containerwidget(
 32                size=(self._width, self._height),
 33                transition=transition,
 34                on_cancel_call=_do_cancel,
 35                background=False,
 36                stack_offset=(0, -130),
 37            )
 38        )
 39
 40        self._r = 'kioskWindow'
 41
 42        self._show_multiplayer = False
 43
 44        # Let's reset all random player names every time we hit the main menu.
 45        ba.internal.reset_random_player_names()
 46
 47        # Reset achievements too (at least locally).
 48        ba.app.config['Achievements'] = {}
 49
 50        t_delay_base = 0.0
 51        t_delay_scale = 0.0
 52        if not ba.app.did_menu_intro:
 53            t_delay_base = 1.0
 54            t_delay_scale = 1.0
 55
 56        model_opaque = ba.getmodel('level_select_button_opaque')
 57        model_transparent = ba.getmodel('level_select_button_transparent')
 58        mask_tex = ba.gettexture('mapPreviewMask')
 59
 60        y_extra = 130.0 + (0.0 if self._show_multiplayer else -130.0)
 61        b_width = 250.0
 62        b_height = 200.0
 63        b_space = 280.0
 64        b_v = 80.0 + y_extra
 65        label_height = 130.0 + y_extra
 66        img_width = 180.0
 67        img_v = 158.0 + y_extra
 68
 69        if self._show_multiplayer:
 70            tdelay = t_delay_base + t_delay_scale * 1.3
 71            ba.textwidget(
 72                parent=self._root_widget,
 73                size=(0, 0),
 74                position=(self._width * 0.5, self._height + y_extra - 44),
 75                transition_delay=tdelay,
 76                text=ba.Lstr(resource=self._r + '.singlePlayerExamplesText'),
 77                flatness=1.0,
 78                scale=1.2,
 79                h_align='center',
 80                v_align='center',
 81                shadow=1.0,
 82            )
 83        else:
 84            tdelay = t_delay_base + t_delay_scale * 0.7
 85            ba.textwidget(
 86                parent=self._root_widget,
 87                size=(0, 0),
 88                position=(self._width * 0.5, self._height + y_extra - 34),
 89                transition_delay=tdelay,
 90                text=(
 91                    ba.Lstr(
 92                        resource='demoText',
 93                        fallback_resource='mainMenu.demoMenuText',
 94                    )
 95                    if ba.app.demo_mode
 96                    else 'ARCADE'
 97                ),
 98                flatness=1.0,
 99                scale=1.2,
100                h_align='center',
101                v_align='center',
102                shadow=1.0,
103            )
104        h = self._width * 0.5 - b_space
105        tdelay = t_delay_base + t_delay_scale * 0.7
106        self._b1 = btn = ba.buttonwidget(
107            parent=self._root_widget,
108            autoselect=True,
109            size=(b_width, b_height),
110            on_activate_call=ba.Call(self._do_game, 'easy'),
111            transition_delay=tdelay,
112            position=(h - b_width * 0.5, b_v),
113            label='',
114            button_type='square',
115        )
116        ba.textwidget(
117            parent=self._root_widget,
118            draw_controller=btn,
119            transition_delay=tdelay,
120            size=(0, 0),
121            position=(h, label_height),
122            maxwidth=b_width * 0.7,
123            text=ba.Lstr(resource=self._r + '.easyText'),
124            scale=1.3,
125            h_align='center',
126            v_align='center',
127        )
128        ba.imagewidget(
129            parent=self._root_widget,
130            draw_controller=btn,
131            size=(img_width, 0.5 * img_width),
132            transition_delay=tdelay,
133            position=(h - img_width * 0.5, img_v),
134            texture=ba.gettexture('doomShroomPreview'),
135            model_opaque=model_opaque,
136            model_transparent=model_transparent,
137            mask_texture=mask_tex,
138        )
139        h = self._width * 0.5
140        tdelay = t_delay_base + t_delay_scale * 0.65
141        self._b2 = btn = ba.buttonwidget(
142            parent=self._root_widget,
143            autoselect=True,
144            size=(b_width, b_height),
145            on_activate_call=ba.Call(self._do_game, 'medium'),
146            position=(h - b_width * 0.5, b_v),
147            label='',
148            button_type='square',
149            transition_delay=tdelay,
150        )
151        ba.textwidget(
152            parent=self._root_widget,
153            draw_controller=btn,
154            transition_delay=tdelay,
155            size=(0, 0),
156            position=(h, label_height),
157            maxwidth=b_width * 0.7,
158            text=ba.Lstr(resource=self._r + '.mediumText'),
159            scale=1.3,
160            h_align='center',
161            v_align='center',
162        )
163        ba.imagewidget(
164            parent=self._root_widget,
165            draw_controller=btn,
166            size=(img_width, 0.5 * img_width),
167            transition_delay=tdelay,
168            position=(h - img_width * 0.5, img_v),
169            texture=ba.gettexture('footballStadiumPreview'),
170            model_opaque=model_opaque,
171            model_transparent=model_transparent,
172            mask_texture=mask_tex,
173        )
174        h = self._width * 0.5 + b_space
175        tdelay = t_delay_base + t_delay_scale * 0.6
176        self._b3 = btn = ba.buttonwidget(
177            parent=self._root_widget,
178            autoselect=True,
179            size=(b_width, b_height),
180            on_activate_call=ba.Call(self._do_game, 'hard'),
181            transition_delay=tdelay,
182            position=(h - b_width * 0.5, b_v),
183            label='',
184            button_type='square',
185        )
186        ba.textwidget(
187            parent=self._root_widget,
188            draw_controller=btn,
189            transition_delay=tdelay,
190            size=(0, 0),
191            position=(h, label_height),
192            maxwidth=b_width * 0.7,
193            text='Hard',
194            scale=1.3,
195            h_align='center',
196            v_align='center',
197        )
198        ba.imagewidget(
199            parent=self._root_widget,
200            draw_controller=btn,
201            transition_delay=tdelay,
202            size=(img_width, 0.5 * img_width),
203            position=(h - img_width * 0.5, img_v),
204            texture=ba.gettexture('courtyardPreview'),
205            model_opaque=model_opaque,
206            model_transparent=model_transparent,
207            mask_texture=mask_tex,
208        )
209        if not ba.app.did_menu_intro:
210            ba.app.did_menu_intro = True
211
212        self._b4: ba.Widget | None
213        self._b5: ba.Widget | None
214        self._b6: ba.Widget | None
215
216        if bool(False):
217            ba.textwidget(
218                parent=self._root_widget,
219                size=(0, 0),
220                position=(self._width * 0.5, self._height + y_extra - 44),
221                transition_delay=tdelay,
222                text=ba.Lstr(resource=self._r + '.versusExamplesText'),
223                flatness=1.0,
224                scale=1.2,
225                h_align='center',
226                v_align='center',
227                shadow=1.0,
228            )
229            h = self._width * 0.5 - b_space
230            tdelay = t_delay_base + t_delay_scale * 0.7
231            self._b4 = btn = ba.buttonwidget(
232                parent=self._root_widget,
233                autoselect=True,
234                size=(b_width, b_height),
235                on_activate_call=ba.Call(self._do_game, 'ctf'),
236                transition_delay=tdelay,
237                position=(h - b_width * 0.5, b_v),
238                label='',
239                button_type='square',
240            )
241            ba.textwidget(
242                parent=self._root_widget,
243                draw_controller=btn,
244                transition_delay=tdelay,
245                size=(0, 0),
246                position=(h, label_height),
247                maxwidth=b_width * 0.7,
248                text=ba.Lstr(translate=('gameNames', 'Capture the Flag')),
249                scale=1.3,
250                h_align='center',
251                v_align='center',
252            )
253            ba.imagewidget(
254                parent=self._root_widget,
255                draw_controller=btn,
256                size=(img_width, 0.5 * img_width),
257                transition_delay=tdelay,
258                position=(h - img_width * 0.5, img_v),
259                texture=ba.gettexture('bridgitPreview'),
260                model_opaque=model_opaque,
261                model_transparent=model_transparent,
262                mask_texture=mask_tex,
263            )
264
265            h = self._width * 0.5
266            tdelay = t_delay_base + t_delay_scale * 0.65
267            self._b5 = btn = ba.buttonwidget(
268                parent=self._root_widget,
269                autoselect=True,
270                size=(b_width, b_height),
271                on_activate_call=ba.Call(self._do_game, 'hockey'),
272                position=(h - b_width * 0.5, b_v),
273                label='',
274                button_type='square',
275                transition_delay=tdelay,
276            )
277            ba.textwidget(
278                parent=self._root_widget,
279                draw_controller=btn,
280                transition_delay=tdelay,
281                size=(0, 0),
282                position=(h, label_height),
283                maxwidth=b_width * 0.7,
284                text=ba.Lstr(translate=('gameNames', 'Hockey')),
285                scale=1.3,
286                h_align='center',
287                v_align='center',
288            )
289            ba.imagewidget(
290                parent=self._root_widget,
291                draw_controller=btn,
292                size=(img_width, 0.5 * img_width),
293                transition_delay=tdelay,
294                position=(h - img_width * 0.5, img_v),
295                texture=ba.gettexture('hockeyStadiumPreview'),
296                model_opaque=model_opaque,
297                model_transparent=model_transparent,
298                mask_texture=mask_tex,
299            )
300            h = self._width * 0.5 + b_space
301            tdelay = t_delay_base + t_delay_scale * 0.6
302            self._b6 = btn = ba.buttonwidget(
303                parent=self._root_widget,
304                autoselect=True,
305                size=(b_width, b_height),
306                on_activate_call=ba.Call(self._do_game, 'epic'),
307                transition_delay=tdelay,
308                position=(h - b_width * 0.5, b_v),
309                label='',
310                button_type='square',
311            )
312            ba.textwidget(
313                parent=self._root_widget,
314                draw_controller=btn,
315                transition_delay=tdelay,
316                size=(0, 0),
317                position=(h, label_height),
318                maxwidth=b_width * 0.7,
319                text=ba.Lstr(resource=self._r + '.epicModeText'),
320                scale=1.3,
321                h_align='center',
322                v_align='center',
323            )
324            ba.imagewidget(
325                parent=self._root_widget,
326                draw_controller=btn,
327                transition_delay=tdelay,
328                size=(img_width, 0.5 * img_width),
329                position=(h - img_width * 0.5, img_v),
330                texture=ba.gettexture('tipTopPreview'),
331                model_opaque=model_opaque,
332                model_transparent=model_transparent,
333                mask_texture=mask_tex,
334            )
335        else:
336            self._b4 = self._b5 = self._b6 = None
337
338        self._b7: ba.Widget | None
339        if ba.app.arcade_mode:
340            self._b7 = ba.buttonwidget(
341                parent=self._root_widget,
342                autoselect=True,
343                size=(b_width, 50),
344                color=(0.45, 0.55, 0.45),
345                textcolor=(0.7, 0.8, 0.7),
346                scale=0.5,
347                position=(self._width * 0.5 - 60.0, b_v - 70.0),
348                transition_delay=tdelay,
349                label=ba.Lstr(resource=self._r + '.fullMenuText'),
350                on_activate_call=self._do_full_menu,
351            )
352        else:
353            self._b7 = None
354        self._restore_state()
355        self._update()
356        self._update_timer = ba.Timer(
357            1.0,
358            ba.WeakCall(self._update),
359            timetype=ba.TimeType.REAL,
360            repeat=True,
361        )
362
363    def _restore_state(self) -> None:
364        sel_name = ba.app.ui.window_states.get(type(self))
365        sel: ba.Widget | None
366        if sel_name == 'b1':
367            sel = self._b1
368        elif sel_name == 'b2':
369            sel = self._b2
370        elif sel_name == 'b3':
371            sel = self._b3
372        elif sel_name == 'b4':
373            sel = self._b4
374        elif sel_name == 'b5':
375            sel = self._b5
376        elif sel_name == 'b6':
377            sel = self._b6
378        elif sel_name == 'b7':
379            sel = self._b7
380        else:
381            sel = self._b1
382        if sel:
383            ba.containerwidget(edit=self._root_widget, selected_child=sel)
384
385    def _save_state(self) -> None:
386        sel = self._root_widget.get_selected_child()
387        if sel == self._b1:
388            sel_name = 'b1'
389        elif sel == self._b2:
390            sel_name = 'b2'
391        elif sel == self._b3:
392            sel_name = 'b3'
393        elif sel == self._b4:
394            sel_name = 'b4'
395        elif sel == self._b5:
396            sel_name = 'b5'
397        elif sel == self._b6:
398            sel_name = 'b6'
399        elif sel == self._b7:
400            sel_name = 'b7'
401        else:
402            sel_name = 'b1'
403        ba.app.ui.window_states[type(self)] = sel_name
404
405    def _update(self) -> None:
406        # Kiosk-mode is designed to be used signed-out... try for force
407        # the issue.
408        if ba.internal.get_v1_account_state() == 'signed_in':
409            # _bs.sign_out()
410            # FIXME: Try to delete player profiles here too.
411            pass
412        else:
413            # Also make sure there's no player profiles.
414            appconfig = ba.app.config
415            appconfig['Player Profiles'] = {}
416
417    def _do_game(self, mode: str) -> None:
418        self._save_state()
419        if mode in ['epic', 'ctf', 'hockey']:
420            appconfig = ba.app.config
421            if 'Team Tournament Playlists' not in appconfig:
422                appconfig['Team Tournament Playlists'] = {}
423            if 'Free-for-All Playlists' not in appconfig:
424                appconfig['Free-for-All Playlists'] = {}
425            appconfig['Show Tutorial'] = False
426            if mode == 'epic':
427                appconfig['Free-for-All Playlists']['Just Epic Elim'] = [
428                    {
429                        'settings': {
430                            'Epic Mode': 1,
431                            'Lives Per Player': 1,
432                            'Respawn Times': 1.0,
433                            'Time Limit': 0,
434                            'map': 'Tip Top',
435                        },
436                        'type': 'bs_elimination.EliminationGame',
437                    }
438                ]
439                appconfig['Free-for-All Playlist Selection'] = 'Just Epic Elim'
440                ba.internal.fade_screen(
441                    False,
442                    endcall=ba.Call(
443                        ba.pushcall,
444                        ba.Call(
445                            ba.internal.new_host_session, ba.FreeForAllSession
446                        ),
447                    ),
448                )
449            else:
450                if mode == 'ctf':
451                    appconfig['Team Tournament Playlists']['Just CTF'] = [
452                        {
453                            'settings': {
454                                'Epic Mode': False,
455                                'Flag Idle Return Time': 30,
456                                'Flag Touch Return Time': 0,
457                                'Respawn Times': 1.0,
458                                'Score to Win': 3,
459                                'Time Limit': 0,
460                                'map': 'Bridgit',
461                            },
462                            'type': 'bs_capture_the_flag.CTFGame',
463                        }
464                    ]
465                    appconfig['Team Tournament Playlist Selection'] = 'Just CTF'
466                else:
467                    appconfig['Team Tournament Playlists']['Just Hockey'] = [
468                        {
469                            'settings': {
470                                'Respawn Times': 1.0,
471                                'Score to Win': 1,
472                                'Time Limit': 0,
473                                'map': 'Hockey Stadium',
474                            },
475                            'type': 'bs_hockey.HockeyGame',
476                        }
477                    ]
478                    appconfig[
479                        'Team Tournament Playlist Selection'
480                    ] = 'Just Hockey'
481                ba.internal.fade_screen(
482                    False,
483                    endcall=ba.Call(
484                        ba.pushcall,
485                        ba.Call(
486                            ba.internal.new_host_session, ba.DualTeamSession
487                        ),
488                    ),
489                )
490            ba.containerwidget(edit=self._root_widget, transition='out_left')
491            return
492
493        game = (
494            'Easy:Onslaught Training'
495            if mode == 'easy'
496            else 'Easy:Rookie Football'
497            if mode == 'medium'
498            else 'Easy:Uber Onslaught'
499        )
500        cfg = ba.app.config
501        cfg['Selected Coop Game'] = game
502        cfg.commit()
503        if ba.app.launch_coop_game(game, force=True):
504            ba.containerwidget(edit=self._root_widget, transition='out_left')
505
506    def _do_full_menu(self) -> None:
507        from bastd.ui.mainmenu import MainMenuWindow
508
509        self._save_state()
510        ba.containerwidget(edit=self._root_widget, transition='out_left')
511        ba.app.did_menu_intro = True  # prevent delayed transition-in
512        ba.app.ui.set_main_menu_window(MainMenuWindow().get_root_widget())

Kiosk mode window.

KioskWindow(transition: str = 'in_right')
 20    def __init__(self, transition: str = 'in_right'):
 21        # pylint: disable=too-many-locals, too-many-statements
 22        from bastd.ui.confirm import QuitWindow
 23
 24        self._width = 720.0
 25        self._height = 340.0
 26
 27        def _do_cancel() -> None:
 28            QuitWindow(swish=True, back=True)
 29
 30        super().__init__(
 31            root_widget=ba.containerwidget(
 32                size=(self._width, self._height),
 33                transition=transition,
 34                on_cancel_call=_do_cancel,
 35                background=False,
 36                stack_offset=(0, -130),
 37            )
 38        )
 39
 40        self._r = 'kioskWindow'
 41
 42        self._show_multiplayer = False
 43
 44        # Let's reset all random player names every time we hit the main menu.
 45        ba.internal.reset_random_player_names()
 46
 47        # Reset achievements too (at least locally).
 48        ba.app.config['Achievements'] = {}
 49
 50        t_delay_base = 0.0
 51        t_delay_scale = 0.0
 52        if not ba.app.did_menu_intro:
 53            t_delay_base = 1.0
 54            t_delay_scale = 1.0
 55
 56        model_opaque = ba.getmodel('level_select_button_opaque')
 57        model_transparent = ba.getmodel('level_select_button_transparent')
 58        mask_tex = ba.gettexture('mapPreviewMask')
 59
 60        y_extra = 130.0 + (0.0 if self._show_multiplayer else -130.0)
 61        b_width = 250.0
 62        b_height = 200.0
 63        b_space = 280.0
 64        b_v = 80.0 + y_extra
 65        label_height = 130.0 + y_extra
 66        img_width = 180.0
 67        img_v = 158.0 + y_extra
 68
 69        if self._show_multiplayer:
 70            tdelay = t_delay_base + t_delay_scale * 1.3
 71            ba.textwidget(
 72                parent=self._root_widget,
 73                size=(0, 0),
 74                position=(self._width * 0.5, self._height + y_extra - 44),
 75                transition_delay=tdelay,
 76                text=ba.Lstr(resource=self._r + '.singlePlayerExamplesText'),
 77                flatness=1.0,
 78                scale=1.2,
 79                h_align='center',
 80                v_align='center',
 81                shadow=1.0,
 82            )
 83        else:
 84            tdelay = t_delay_base + t_delay_scale * 0.7
 85            ba.textwidget(
 86                parent=self._root_widget,
 87                size=(0, 0),
 88                position=(self._width * 0.5, self._height + y_extra - 34),
 89                transition_delay=tdelay,
 90                text=(
 91                    ba.Lstr(
 92                        resource='demoText',
 93                        fallback_resource='mainMenu.demoMenuText',
 94                    )
 95                    if ba.app.demo_mode
 96                    else 'ARCADE'
 97                ),
 98                flatness=1.0,
 99                scale=1.2,
100                h_align='center',
101                v_align='center',
102                shadow=1.0,
103            )
104        h = self._width * 0.5 - b_space
105        tdelay = t_delay_base + t_delay_scale * 0.7
106        self._b1 = btn = ba.buttonwidget(
107            parent=self._root_widget,
108            autoselect=True,
109            size=(b_width, b_height),
110            on_activate_call=ba.Call(self._do_game, 'easy'),
111            transition_delay=tdelay,
112            position=(h - b_width * 0.5, b_v),
113            label='',
114            button_type='square',
115        )
116        ba.textwidget(
117            parent=self._root_widget,
118            draw_controller=btn,
119            transition_delay=tdelay,
120            size=(0, 0),
121            position=(h, label_height),
122            maxwidth=b_width * 0.7,
123            text=ba.Lstr(resource=self._r + '.easyText'),
124            scale=1.3,
125            h_align='center',
126            v_align='center',
127        )
128        ba.imagewidget(
129            parent=self._root_widget,
130            draw_controller=btn,
131            size=(img_width, 0.5 * img_width),
132            transition_delay=tdelay,
133            position=(h - img_width * 0.5, img_v),
134            texture=ba.gettexture('doomShroomPreview'),
135            model_opaque=model_opaque,
136            model_transparent=model_transparent,
137            mask_texture=mask_tex,
138        )
139        h = self._width * 0.5
140        tdelay = t_delay_base + t_delay_scale * 0.65
141        self._b2 = btn = ba.buttonwidget(
142            parent=self._root_widget,
143            autoselect=True,
144            size=(b_width, b_height),
145            on_activate_call=ba.Call(self._do_game, 'medium'),
146            position=(h - b_width * 0.5, b_v),
147            label='',
148            button_type='square',
149            transition_delay=tdelay,
150        )
151        ba.textwidget(
152            parent=self._root_widget,
153            draw_controller=btn,
154            transition_delay=tdelay,
155            size=(0, 0),
156            position=(h, label_height),
157            maxwidth=b_width * 0.7,
158            text=ba.Lstr(resource=self._r + '.mediumText'),
159            scale=1.3,
160            h_align='center',
161            v_align='center',
162        )
163        ba.imagewidget(
164            parent=self._root_widget,
165            draw_controller=btn,
166            size=(img_width, 0.5 * img_width),
167            transition_delay=tdelay,
168            position=(h - img_width * 0.5, img_v),
169            texture=ba.gettexture('footballStadiumPreview'),
170            model_opaque=model_opaque,
171            model_transparent=model_transparent,
172            mask_texture=mask_tex,
173        )
174        h = self._width * 0.5 + b_space
175        tdelay = t_delay_base + t_delay_scale * 0.6
176        self._b3 = btn = ba.buttonwidget(
177            parent=self._root_widget,
178            autoselect=True,
179            size=(b_width, b_height),
180            on_activate_call=ba.Call(self._do_game, 'hard'),
181            transition_delay=tdelay,
182            position=(h - b_width * 0.5, b_v),
183            label='',
184            button_type='square',
185        )
186        ba.textwidget(
187            parent=self._root_widget,
188            draw_controller=btn,
189            transition_delay=tdelay,
190            size=(0, 0),
191            position=(h, label_height),
192            maxwidth=b_width * 0.7,
193            text='Hard',
194            scale=1.3,
195            h_align='center',
196            v_align='center',
197        )
198        ba.imagewidget(
199            parent=self._root_widget,
200            draw_controller=btn,
201            transition_delay=tdelay,
202            size=(img_width, 0.5 * img_width),
203            position=(h - img_width * 0.5, img_v),
204            texture=ba.gettexture('courtyardPreview'),
205            model_opaque=model_opaque,
206            model_transparent=model_transparent,
207            mask_texture=mask_tex,
208        )
209        if not ba.app.did_menu_intro:
210            ba.app.did_menu_intro = True
211
212        self._b4: ba.Widget | None
213        self._b5: ba.Widget | None
214        self._b6: ba.Widget | None
215
216        if bool(False):
217            ba.textwidget(
218                parent=self._root_widget,
219                size=(0, 0),
220                position=(self._width * 0.5, self._height + y_extra - 44),
221                transition_delay=tdelay,
222                text=ba.Lstr(resource=self._r + '.versusExamplesText'),
223                flatness=1.0,
224                scale=1.2,
225                h_align='center',
226                v_align='center',
227                shadow=1.0,
228            )
229            h = self._width * 0.5 - b_space
230            tdelay = t_delay_base + t_delay_scale * 0.7
231            self._b4 = btn = ba.buttonwidget(
232                parent=self._root_widget,
233                autoselect=True,
234                size=(b_width, b_height),
235                on_activate_call=ba.Call(self._do_game, 'ctf'),
236                transition_delay=tdelay,
237                position=(h - b_width * 0.5, b_v),
238                label='',
239                button_type='square',
240            )
241            ba.textwidget(
242                parent=self._root_widget,
243                draw_controller=btn,
244                transition_delay=tdelay,
245                size=(0, 0),
246                position=(h, label_height),
247                maxwidth=b_width * 0.7,
248                text=ba.Lstr(translate=('gameNames', 'Capture the Flag')),
249                scale=1.3,
250                h_align='center',
251                v_align='center',
252            )
253            ba.imagewidget(
254                parent=self._root_widget,
255                draw_controller=btn,
256                size=(img_width, 0.5 * img_width),
257                transition_delay=tdelay,
258                position=(h - img_width * 0.5, img_v),
259                texture=ba.gettexture('bridgitPreview'),
260                model_opaque=model_opaque,
261                model_transparent=model_transparent,
262                mask_texture=mask_tex,
263            )
264
265            h = self._width * 0.5
266            tdelay = t_delay_base + t_delay_scale * 0.65
267            self._b5 = btn = ba.buttonwidget(
268                parent=self._root_widget,
269                autoselect=True,
270                size=(b_width, b_height),
271                on_activate_call=ba.Call(self._do_game, 'hockey'),
272                position=(h - b_width * 0.5, b_v),
273                label='',
274                button_type='square',
275                transition_delay=tdelay,
276            )
277            ba.textwidget(
278                parent=self._root_widget,
279                draw_controller=btn,
280                transition_delay=tdelay,
281                size=(0, 0),
282                position=(h, label_height),
283                maxwidth=b_width * 0.7,
284                text=ba.Lstr(translate=('gameNames', 'Hockey')),
285                scale=1.3,
286                h_align='center',
287                v_align='center',
288            )
289            ba.imagewidget(
290                parent=self._root_widget,
291                draw_controller=btn,
292                size=(img_width, 0.5 * img_width),
293                transition_delay=tdelay,
294                position=(h - img_width * 0.5, img_v),
295                texture=ba.gettexture('hockeyStadiumPreview'),
296                model_opaque=model_opaque,
297                model_transparent=model_transparent,
298                mask_texture=mask_tex,
299            )
300            h = self._width * 0.5 + b_space
301            tdelay = t_delay_base + t_delay_scale * 0.6
302            self._b6 = btn = ba.buttonwidget(
303                parent=self._root_widget,
304                autoselect=True,
305                size=(b_width, b_height),
306                on_activate_call=ba.Call(self._do_game, 'epic'),
307                transition_delay=tdelay,
308                position=(h - b_width * 0.5, b_v),
309                label='',
310                button_type='square',
311            )
312            ba.textwidget(
313                parent=self._root_widget,
314                draw_controller=btn,
315                transition_delay=tdelay,
316                size=(0, 0),
317                position=(h, label_height),
318                maxwidth=b_width * 0.7,
319                text=ba.Lstr(resource=self._r + '.epicModeText'),
320                scale=1.3,
321                h_align='center',
322                v_align='center',
323            )
324            ba.imagewidget(
325                parent=self._root_widget,
326                draw_controller=btn,
327                transition_delay=tdelay,
328                size=(img_width, 0.5 * img_width),
329                position=(h - img_width * 0.5, img_v),
330                texture=ba.gettexture('tipTopPreview'),
331                model_opaque=model_opaque,
332                model_transparent=model_transparent,
333                mask_texture=mask_tex,
334            )
335        else:
336            self._b4 = self._b5 = self._b6 = None
337
338        self._b7: ba.Widget | None
339        if ba.app.arcade_mode:
340            self._b7 = ba.buttonwidget(
341                parent=self._root_widget,
342                autoselect=True,
343                size=(b_width, 50),
344                color=(0.45, 0.55, 0.45),
345                textcolor=(0.7, 0.8, 0.7),
346                scale=0.5,
347                position=(self._width * 0.5 - 60.0, b_v - 70.0),
348                transition_delay=tdelay,
349                label=ba.Lstr(resource=self._r + '.fullMenuText'),
350                on_activate_call=self._do_full_menu,
351            )
352        else:
353            self._b7 = None
354        self._restore_state()
355        self._update()
356        self._update_timer = ba.Timer(
357            1.0,
358            ba.WeakCall(self._update),
359            timetype=ba.TimeType.REAL,
360            repeat=True,
361        )
Inherited Members
ba.ui.Window
get_root_widget