Source code for baclassic._appmode

# Released under the MIT License. See LICENSE for details.
#
"""Contains ClassicAppMode."""
from __future__ import annotations

import logging
from functools import partial
from typing import TYPE_CHECKING, override

from bacommon.app import AppExperience
from babase import (
    app,
    AppMode,
    AppIntentExec,
    AppIntentDefault,
    invoke_main_menu,
    screenmessage,
)

import _baclassic

if TYPE_CHECKING:
    from typing import Callable

    from babase import AppIntent
    from bauiv1 import UIV1AppSubsystem, MainWindow, MainWindowState


class ClassicAppMode(AppMode):
    """AppMode for the classic BombSquad experience."""

[docs] @override @classmethod def get_app_experience(cls) -> AppExperience: return AppExperience.MELEE
@override @classmethod def _supports_intent(cls, intent: AppIntent) -> bool: # We support default and exec intents currently. return isinstance(intent, AppIntentExec | AppIntentDefault)
[docs] @override def handle_intent(self, intent: AppIntent) -> None: if isinstance(intent, AppIntentExec): _baclassic.classic_app_mode_handle_app_intent_exec(intent.code) return assert isinstance(intent, AppIntentDefault) _baclassic.classic_app_mode_handle_app_intent_default()
[docs] @override def on_activate(self) -> None: # Let the native layer do its thing. _baclassic.classic_app_mode_activate() # Wire up the root ui to do what we want. ui = app.ui_v1 ui.root_ui_calls[ui.RootUIElement.ACCOUNT_BUTTON] = ( self._root_ui_account_press ) ui.root_ui_calls[ui.RootUIElement.MENU_BUTTON] = ( self._root_ui_menu_press ) ui.root_ui_calls[ui.RootUIElement.SQUAD_BUTTON] = ( self._root_ui_squad_press ) ui.root_ui_calls[ui.RootUIElement.SETTINGS_BUTTON] = ( self._root_ui_settings_press ) ui.root_ui_calls[ui.RootUIElement.STORE_BUTTON] = ( self._root_ui_store_press ) ui.root_ui_calls[ui.RootUIElement.INVENTORY_BUTTON] = ( self._root_ui_inventory_press ) ui.root_ui_calls[ui.RootUIElement.GET_TOKENS_BUTTON] = ( self._root_ui_get_tokens_press ) ui.root_ui_calls[ui.RootUIElement.INBOX_BUTTON] = ( self._root_ui_inbox_press ) ui.root_ui_calls[ui.RootUIElement.TICKETS_METER] = ( self._root_ui_tickets_meter_press ) ui.root_ui_calls[ui.RootUIElement.TOKENS_METER] = ( self._root_ui_tokens_meter_press ) ui.root_ui_calls[ui.RootUIElement.TROPHY_METER] = ( self._root_ui_trophy_meter_press ) ui.root_ui_calls[ui.RootUIElement.LEVEL_METER] = ( self._root_ui_level_meter_press ) ui.root_ui_calls[ui.RootUIElement.ACHIEVEMENTS_BUTTON] = ( self._root_ui_achievements_press ) ui.root_ui_calls[ui.RootUIElement.CHEST_SLOT_1] = partial( self._root_ui_chest_slot_pressed, 1 ) ui.root_ui_calls[ui.RootUIElement.CHEST_SLOT_2] = partial( self._root_ui_chest_slot_pressed, 2 ) ui.root_ui_calls[ui.RootUIElement.CHEST_SLOT_3] = partial( self._root_ui_chest_slot_pressed, 3 ) ui.root_ui_calls[ui.RootUIElement.CHEST_SLOT_4] = partial( self._root_ui_chest_slot_pressed, 4 )
[docs] @override def on_deactivate(self) -> None: # Save where we were in the UI so we return there next time. if app.classic is not None: app.classic.save_ui_state() # Let the native layer do its thing. _baclassic.classic_app_mode_deactivate()
[docs] @override def on_app_active_changed(self) -> None: # If we've gone inactive, bring up the main menu, which has the # side effect of pausing the action (when possible). if not app.active: invoke_main_menu()
def _root_ui_menu_press(self) -> None: from babase import push_back_press ui = app.ui_v1 # If *any* main-window is up, kill it and resume play. old_window = ui.get_main_window() if old_window is not None: classic = app.classic assert classic is not None classic.resume() ui.clear_main_window() return push_back_press() def _root_ui_account_press(self) -> None: import bauiv1 from bauiv1lib.account.settings import AccountSettingsWindow self._auxiliary_window_nav( win_type=AccountSettingsWindow, win_create_call=lambda: AccountSettingsWindow( origin_widget=bauiv1.get_special_widget('account_button') ), ) def _root_ui_squad_press(self) -> None: import bauiv1 btn = bauiv1.get_special_widget('squad_button') center = btn.get_screen_space_center() if bauiv1.app.classic is not None: bauiv1.app.classic.party_icon_activate(center) else: logging.warning('party_icon_activate: no classic.') def _root_ui_settings_press(self) -> None: import bauiv1 from bauiv1lib.settings.allsettings import AllSettingsWindow self._auxiliary_window_nav( win_type=AllSettingsWindow, win_create_call=lambda: AllSettingsWindow( origin_widget=bauiv1.get_special_widget('settings_button') ), ) def _auxiliary_window_nav( self, win_type: type[MainWindow], win_create_call: Callable[[], MainWindow], ) -> None: """Navigate to or away from a particular type of Auxiliary window.""" # pylint: disable=unidiomatic-typecheck ui = app.ui_v1 current_main_window = ui.get_main_window() # Scan our ancestors for auxiliary states matching our type as # well as auxiliary states in general. aux_matching_state: MainWindowState | None = None aux_state: MainWindowState | None = None if current_main_window is None: raise RuntimeError( 'Not currently handling no-top-level-window case.' ) state = current_main_window.main_window_back_state while state is not None: assert state.window_type is not None if state.is_auxiliary: if state.window_type is win_type: aux_matching_state = state else: aux_state = state state = state.parent # If there's an ancestor auxiliary window-state matching our # type, back out past it (example: poking settings, navigating # down a level or two, and then poking settings again should # back out of settings). if aux_matching_state is not None: current_main_window.main_window_back_state = ( aux_matching_state.parent ) current_main_window.main_window_back() return # If there's an ancestory auxiliary state *not* matching our # type, crop the state and swap in our new auxiliary UI # (example: poking settings, then poking account, then poking # back should end up where things were before the settings # poke). if aux_state is not None: # Blow away the window stack and build a fresh one. ui.clear_main_window() ui.set_main_window( win_create_call(), from_window=False, # Disable from-check. back_state=aux_state.parent, suppress_warning=True, is_auxiliary=True, ) return # Ok, no auxiliary states found. Now if current window is auxiliary # and the type matches, simply do a back. if ( current_main_window.main_window_is_auxiliary and type(current_main_window) is win_type ): current_main_window.main_window_back() return # If current window is auxiliary but type doesn't match, # swap it out for our new auxiliary UI. if current_main_window.main_window_is_auxiliary: ui.clear_main_window() ui.set_main_window( win_create_call(), from_window=False, # Disable from-check. back_state=current_main_window.main_window_back_state, suppress_warning=True, is_auxiliary=True, ) return # Ok, no existing auxiliary stuff was found period. Just # navigate forward to this UI. current_main_window.main_window_replace( win_create_call(), is_auxiliary=True ) def _root_ui_achievements_press(self) -> None: import bauiv1 from bauiv1lib.achievements import AchievementsWindow self._auxiliary_window_nav( win_type=AchievementsWindow, win_create_call=lambda: AchievementsWindow( origin_widget=bauiv1.get_special_widget('achievements_button') ), ) def _root_ui_inbox_press(self) -> None: import bauiv1 from bauiv1lib.inbox import InboxWindow self._auxiliary_window_nav( win_type=InboxWindow, win_create_call=lambda: InboxWindow( origin_widget=bauiv1.get_special_widget('inbox_button') ), ) def _root_ui_store_press(self) -> None: import bauiv1 from bauiv1lib.store.browser import StoreBrowserWindow self._auxiliary_window_nav( win_type=StoreBrowserWindow, win_create_call=lambda: StoreBrowserWindow( origin_widget=bauiv1.get_special_widget('store_button') ), ) def _root_ui_tickets_meter_press(self) -> None: import bauiv1 from bauiv1lib.resourcetypeinfo import ResourceTypeInfoWindow ResourceTypeInfoWindow( 'tickets', origin_widget=bauiv1.get_special_widget('tickets_meter') ) def _root_ui_tokens_meter_press(self) -> None: import bauiv1 from bauiv1lib.resourcetypeinfo import ResourceTypeInfoWindow ResourceTypeInfoWindow( 'tokens', origin_widget=bauiv1.get_special_widget('tokens_meter') ) def _root_ui_trophy_meter_press(self) -> None: import bauiv1 from bauiv1lib.account import show_sign_in_prompt from bauiv1lib.league.rankwindow import LeagueRankWindow plus = bauiv1.app.plus assert plus is not None if plus.get_v1_account_state() != 'signed_in': show_sign_in_prompt() return self._auxiliary_window_nav( win_type=LeagueRankWindow, win_create_call=lambda: LeagueRankWindow( origin_widget=bauiv1.get_special_widget('trophy_meter') ), ) def _root_ui_level_meter_press(self) -> None: import bauiv1 from bauiv1lib.resourcetypeinfo import ResourceTypeInfoWindow ResourceTypeInfoWindow( 'xp', origin_widget=bauiv1.get_special_widget('level_meter') ) def _root_ui_inventory_press(self) -> None: import bauiv1 from bauiv1lib.inventory import InventoryWindow self._auxiliary_window_nav( win_type=InventoryWindow, win_create_call=lambda: InventoryWindow( origin_widget=bauiv1.get_special_widget('inventory_button') ), ) def _root_ui_get_tokens_press(self) -> None: import bauiv1 from bauiv1lib.gettokens import GetTokensWindow self._auxiliary_window_nav( win_type=GetTokensWindow, win_create_call=lambda: GetTokensWindow( origin_widget=bauiv1.get_special_widget('get_tokens_button') ), ) def _root_ui_chest_slot_pressed(self, index: int) -> None: print(f'CHEST {index} PRESSED') screenmessage('UNDER CONSTRUCTION.')