Source code for bauiv1lib.kiosk

# Released under the MIT License. See LICENSE for details.
#
"""UI functionality for running the game in kiosk mode."""

from __future__ import annotations

from typing import override

import bascenev1 as bs
import bauiv1 as bui


[docs] class KioskWindow(bui.MainWindow): """Kiosk mode window.""" def __init__( self, transition: str | None = 'in_right', origin_widget: bui.Widget | None = None, ): # pylint: disable=too-many-locals, too-many-statements from bauiv1lib.confirm import QuitWindow assert bui.app.classic is not None self._width = 720.0 self._height = 340.0 def _do_cancel() -> None: QuitWindow(swish=True, quit_type=bui.QuitType.BACK) super().__init__( root_widget=bui.containerwidget( size=(self._width, self._height), # transition=transition, on_cancel_call=_do_cancel, background=False, stack_offset=(0, -130), ), transition=transition, origin_widget=origin_widget, ) self._r = 'kioskWindow' self._show_multiplayer = False # Let's reset all random player names every time we hit the main menu. bs.reset_random_player_names() # Reset achievements too (at least locally). bui.app.config['Achievements'] = {} t_delay_base = 0.0 t_delay_scale = 0.0 if not bui.app.classic.did_menu_intro: t_delay_base = 1.0 t_delay_scale = 1.0 mesh_opaque = bui.getmesh('level_select_button_opaque') mesh_transparent = bui.getmesh('level_select_button_transparent') mask_tex = bui.gettexture('mapPreviewMask') y_extra = 130.0 + (0.0 if self._show_multiplayer else -130.0) b_width = 250.0 b_height = 200.0 b_space = 280.0 b_v = 80.0 + y_extra label_height = 130.0 + y_extra img_width = 180.0 img_v = 158.0 + y_extra if self._show_multiplayer: tdelay = t_delay_base + t_delay_scale * 1.3 bui.textwidget( parent=self._root_widget, size=(0, 0), position=(self._width * 0.5, self._height + y_extra - 44), transition_delay=tdelay, text=bui.Lstr(resource=f'{self._r}.singlePlayerExamplesText'), flatness=1.0, scale=1.2, h_align='center', v_align='center', shadow=1.0, ) else: tdelay = t_delay_base + t_delay_scale * 0.7 bui.textwidget( parent=self._root_widget, size=(0, 0), position=(self._width * 0.5, self._height + y_extra - 34), transition_delay=tdelay, text=( bui.Lstr( resource='demoText', fallback_resource='mainMenu.demoMenuText', ) if bui.app.env.demo else 'ARCADE' ), flatness=1.0, scale=1.2, h_align='center', v_align='center', shadow=1.0, ) h = self._width * 0.5 - b_space tdelay = t_delay_base + t_delay_scale * 0.7 self._b1 = btn = bui.buttonwidget( parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=bui.Call(self._do_game, 'easy'), transition_delay=tdelay, position=(h - b_width * 0.5, b_v), label='', button_type='square', ) bui.textwidget( parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=bui.Lstr(resource=f'{self._r}.easyText'), scale=1.3, h_align='center', v_align='center', ) bui.imagewidget( parent=self._root_widget, draw_controller=btn, size=(img_width, 0.5 * img_width), transition_delay=tdelay, position=(h - img_width * 0.5, img_v), texture=bui.gettexture('doomShroomPreview'), mesh_opaque=mesh_opaque, mesh_transparent=mesh_transparent, mask_texture=mask_tex, ) h = self._width * 0.5 tdelay = t_delay_base + t_delay_scale * 0.65 self._b2 = btn = bui.buttonwidget( parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=bui.Call(self._do_game, 'medium'), position=(h - b_width * 0.5, b_v), label='', button_type='square', transition_delay=tdelay, ) bui.textwidget( parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=bui.Lstr(resource=f'{self._r}.mediumText'), scale=1.3, h_align='center', v_align='center', ) bui.imagewidget( parent=self._root_widget, draw_controller=btn, size=(img_width, 0.5 * img_width), transition_delay=tdelay, position=(h - img_width * 0.5, img_v), texture=bui.gettexture('footballStadiumPreview'), mesh_opaque=mesh_opaque, mesh_transparent=mesh_transparent, mask_texture=mask_tex, ) h = self._width * 0.5 + b_space tdelay = t_delay_base + t_delay_scale * 0.6 self._b3 = btn = bui.buttonwidget( parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=bui.Call(self._do_game, 'hard'), transition_delay=tdelay, position=(h - b_width * 0.5, b_v), label='', button_type='square', ) bui.textwidget( parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text='Hard', scale=1.3, h_align='center', v_align='center', ) bui.imagewidget( parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(img_width, 0.5 * img_width), position=(h - img_width * 0.5, img_v), texture=bui.gettexture('courtyardPreview'), mesh_opaque=mesh_opaque, mesh_transparent=mesh_transparent, mask_texture=mask_tex, ) if not bui.app.classic.did_menu_intro: bui.app.classic.did_menu_intro = True self._b4: bui.Widget | None self._b5: bui.Widget | None self._b6: bui.Widget | None if bool(False): bui.textwidget( parent=self._root_widget, size=(0, 0), position=(self._width * 0.5, self._height + y_extra - 44), transition_delay=tdelay, text=bui.Lstr(resource=f'{self._r}.versusExamplesText'), flatness=1.0, scale=1.2, h_align='center', v_align='center', shadow=1.0, ) h = self._width * 0.5 - b_space tdelay = t_delay_base + t_delay_scale * 0.7 self._b4 = btn = bui.buttonwidget( parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=bui.Call(self._do_game, 'ctf'), transition_delay=tdelay, position=(h - b_width * 0.5, b_v), label='', button_type='square', ) bui.textwidget( parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=bui.Lstr(translate=('gameNames', 'Capture the Flag')), scale=1.3, h_align='center', v_align='center', ) bui.imagewidget( parent=self._root_widget, draw_controller=btn, size=(img_width, 0.5 * img_width), transition_delay=tdelay, position=(h - img_width * 0.5, img_v), texture=bui.gettexture('bridgitPreview'), mesh_opaque=mesh_opaque, mesh_transparent=mesh_transparent, mask_texture=mask_tex, ) h = self._width * 0.5 tdelay = t_delay_base + t_delay_scale * 0.65 self._b5 = btn = bui.buttonwidget( parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=bui.Call(self._do_game, 'hockey'), position=(h - b_width * 0.5, b_v), label='', button_type='square', transition_delay=tdelay, ) bui.textwidget( parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=bui.Lstr(translate=('gameNames', 'Hockey')), scale=1.3, h_align='center', v_align='center', ) bui.imagewidget( parent=self._root_widget, draw_controller=btn, size=(img_width, 0.5 * img_width), transition_delay=tdelay, position=(h - img_width * 0.5, img_v), texture=bui.gettexture('hockeyStadiumPreview'), mesh_opaque=mesh_opaque, mesh_transparent=mesh_transparent, mask_texture=mask_tex, ) h = self._width * 0.5 + b_space tdelay = t_delay_base + t_delay_scale * 0.6 self._b6 = btn = bui.buttonwidget( parent=self._root_widget, autoselect=True, size=(b_width, b_height), on_activate_call=bui.Call(self._do_game, 'epic'), transition_delay=tdelay, position=(h - b_width * 0.5, b_v), label='', button_type='square', ) bui.textwidget( parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(0, 0), position=(h, label_height), maxwidth=b_width * 0.7, text=bui.Lstr(resource=f'{self._r}.epicModeText'), scale=1.3, h_align='center', v_align='center', ) bui.imagewidget( parent=self._root_widget, draw_controller=btn, transition_delay=tdelay, size=(img_width, 0.5 * img_width), position=(h - img_width * 0.5, img_v), texture=bui.gettexture('tipTopPreview'), mesh_opaque=mesh_opaque, mesh_transparent=mesh_transparent, mask_texture=mask_tex, ) else: self._b4 = self._b5 = self._b6 = None self._b7: bui.Widget | None if bui.app.env.arcade: self._b7 = bui.buttonwidget( parent=self._root_widget, autoselect=True, size=(b_width, 50), color=(0.45, 0.55, 0.45), textcolor=(0.7, 0.8, 0.7), scale=0.5, position=(self._width * 0.5 - 60.0, b_v - 70.0), transition_delay=tdelay, label=bui.Lstr(resource=f'{self._r}.fullMenuText'), on_activate_call=self._do_full_menu, ) else: self._b7 = None self._restore_state() self._update() self._update_timer = bui.AppTimer( 1.0, bui.WeakCall(self._update), repeat=True )
[docs] @override def get_main_window_state(self) -> bui.MainWindowState: # Support recreating our window for back/refresh purposes. cls = type(self) return bui.BasicMainWindowState( create_call=lambda transition, origin_widget: cls( transition=transition, origin_widget=origin_widget ) )
[docs] @override def on_main_window_close(self) -> None: self._save_state()
def _restore_state(self) -> None: assert bui.app.classic is not None sel_name = bui.app.ui_v1.window_states.get(type(self)) sel: bui.Widget | None if sel_name == 'b1': sel = self._b1 elif sel_name == 'b2': sel = self._b2 elif sel_name == 'b3': sel = self._b3 elif sel_name == 'b4': sel = self._b4 elif sel_name == 'b5': sel = self._b5 elif sel_name == 'b6': sel = self._b6 elif sel_name == 'b7': sel = self._b7 else: sel = self._b1 if sel: bui.containerwidget(edit=self._root_widget, selected_child=sel) def _save_state(self) -> None: sel = self._root_widget.get_selected_child() if sel == self._b1: sel_name = 'b1' elif sel == self._b2: sel_name = 'b2' elif sel == self._b3: sel_name = 'b3' elif sel == self._b4: sel_name = 'b4' elif sel == self._b5: sel_name = 'b5' elif sel == self._b6: sel_name = 'b6' elif sel == self._b7: sel_name = 'b7' else: sel_name = 'b1' assert bui.app.classic is not None bui.app.ui_v1.window_states[type(self)] = sel_name def _update(self) -> None: plus = bui.app.plus assert plus is not None # Kiosk-mode is designed to be used signed-out... try for force # the issue. if plus.get_v1_account_state() == 'signed_in': # _bs.sign_out() # FIXME: Try to delete player profiles here too. pass else: # Also make sure there's no player profiles. appconfig = bui.app.config appconfig['Player Profiles'] = {} def _do_game(self, mode: str) -> None: assert bui.app.classic is not None self._save_state() if mode in ['epic', 'ctf', 'hockey']: appconfig = bui.app.config if 'Team Tournament Playlists' not in appconfig: appconfig['Team Tournament Playlists'] = {} if 'Free-for-All Playlists' not in appconfig: appconfig['Free-for-All Playlists'] = {} appconfig['Show Tutorial'] = False if mode == 'epic': appconfig['Free-for-All Playlists']['Just Epic Elim'] = [ { 'settings': { 'Epic Mode': 1, 'Lives Per Player': 1, 'Respawn Times': 1.0, 'Time Limit': 0, 'map': 'Tip Top', }, 'type': 'bs_elimination.EliminationGame', } ] appconfig['Free-for-All Playlist Selection'] = 'Just Epic Elim' bui.fade_screen( False, endcall=bui.Call( bui.pushcall, bui.Call(bs.new_host_session, bs.FreeForAllSession), ), ) else: if mode == 'ctf': appconfig['Team Tournament Playlists']['Just CTF'] = [ { 'settings': { 'Epic Mode': False, 'Flag Idle Return Time': 30, 'Flag Touch Return Time': 0, 'Respawn Times': 1.0, 'Score to Win': 3, 'Time Limit': 0, 'map': 'Bridgit', }, 'type': 'bs_capture_the_flag.CTFGame', } ] appconfig['Team Tournament Playlist Selection'] = 'Just CTF' else: appconfig['Team Tournament Playlists']['Just Hockey'] = [ { 'settings': { 'Respawn Times': 1.0, 'Score to Win': 1, 'Time Limit': 0, 'map': 'Hockey Stadium', }, 'type': 'bs_hockey.HockeyGame', } ] appconfig['Team Tournament Playlist Selection'] = ( 'Just Hockey' ) bui.fade_screen( False, endcall=bui.Call( bui.pushcall, bui.Call(bs.new_host_session, bs.DualTeamSession), ), ) bui.containerwidget(edit=self._root_widget, transition='out_left') return game = ( 'Easy:Onslaught Training' if mode == 'easy' else ( 'Easy:Rookie Football' if mode == 'medium' else 'Easy:Uber Onslaught' ) ) cfg = bui.app.config cfg['Selected Coop Game'] = game cfg.commit() if bui.app.classic.launch_coop_game(game, force=True): bui.containerwidget(edit=self._root_widget, transition='out_left') def _do_full_menu(self) -> None: # pylint: disable=cyclic-import from bauiv1lib.mainmenu import MainMenuWindow # no-op if we're not in control. if not self.main_window_has_control(): return assert bui.app.classic is not None self._save_state() bui.app.classic.did_menu_intro = True # prevent delayed transition-in self.main_window_replace(MainMenuWindow())
# Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum