bombsquad-plugin-manager/plugins/utilities/quick_custom_game.py

411 lines
13 KiB
Python
Raw Normal View History

# Porting to api 8 made easier by baport.(https://github.com/bombsquad-community/baport)
# ba_meta require api 8
2022-11-07 00:15:03 +05:30
# (see https://ballistica.net/wiki/meta-tag-system)
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
import _babase
from bauiv1lib.play import PlayWindow
from bauiv1lib.playlist.addgame import PlaylistAddGameWindow
from bascenev1._freeforallsession import FreeForAllSession
from bascenev1lib.activity.multiteamjoin import MultiTeamJoinActivity
2022-11-07 00:15:03 +05:30
if TYPE_CHECKING:
pass
lang = bs.app.lang.language
2022-11-07 00:15:03 +05:30
2024-01-20 22:05:35 +03:00
if lang == "Spanish":
custom_txt = "personalizar..."
2022-11-07 00:15:03 +05:30
else:
2024-01-20 22:05:35 +03:00
custom_txt = "custom..."
2022-11-07 00:15:03 +05:30
2024-01-20 22:05:35 +03:00
if "quick_game_button" in babase.app.config:
config = babase.app.config["quick_game_button"]
2022-11-07 00:15:03 +05:30
else:
2024-01-20 22:05:35 +03:00
config = {"selected": None, "config": None}
babase.app.config["quick_game_button"] = config
babase.app.config.commit()
2022-11-07 00:15:03 +05:30
def start_game(session: bs.Session, fadeout: bool = True):
2022-11-07 00:15:03 +05:30
def callback():
if fadeout:
_babase.unlock_all_input()
2022-11-07 00:15:03 +05:30
try:
bs.new_host_session(session)
2022-11-07 00:15:03 +05:30
except Exception:
from bascenev1lib import mainmenu
2024-01-20 22:05:35 +03:00
babase.print_exception("exception running session", session)
2022-11-07 00:15:03 +05:30
# Drop back into a main menu session.
bs.new_host_session(mainmenu.MainMenuSession)
2022-11-07 00:15:03 +05:30
if fadeout:
_babase.fade_screen(False, time=0.25, endcall=callback)
_babase.lock_all_input()
2022-11-07 00:15:03 +05:30
else:
callback()
class SimplePlaylist:
2024-01-20 22:05:35 +03:00
def __init__(self, settings: dict, gametype: type[bs.GameActivity]):
2022-11-07 00:15:03 +05:30
self.settings = settings
self.gametype = gametype
def pull_next(self) -> None:
2024-01-20 22:05:35 +03:00
if "map" not in self.settings["settings"]:
settings = dict(map=self.settings["map"], **self.settings["settings"])
2022-11-07 00:15:03 +05:30
else:
2024-01-20 22:05:35 +03:00
settings = self.settings["settings"]
2022-11-07 00:15:03 +05:30
return dict(resolved_type=self.gametype, settings=settings)
class CustomSession(FreeForAllSession):
def __init__(self, *args, **kwargs):
# pylint: disable=cyclic-import
self.use_teams = False
self._tutorial_activity_instance = None
2024-01-20 22:05:35 +03:00
bs.Session.__init__(
self,
depsets=[],
team_names=None,
team_colors=None,
min_players=1,
max_players=self.get_max_players(),
)
2022-11-07 00:15:03 +05:30
self._series_length = 1
self._ffa_series_length = 1
# Which game activity we're on.
self._game_number = 0
self._playlist = SimplePlaylist(self._config, self._gametype)
2024-01-20 22:05:35 +03:00
config["selected"] = self._gametype.__name__
config["config"] = self._config
babase.app.config.commit()
2022-11-07 00:15:03 +05:30
# Get a game on deck ready to go.
self._current_game_spec: Optional[Dict[str, Any]] = None
self._next_game_spec: Dict[str, Any] = self._playlist.pull_next()
2024-01-20 22:05:35 +03:00
self._next_game: Type[bs.GameActivity] = self._next_game_spec["resolved_type"]
2022-11-07 00:15:03 +05:30
# Go ahead and instantiate the next game we'll
# use so it has lots of time to load.
self._instantiate_next_game()
# Start in our custom join screen.
self.setactivity(bs.newactivity(MultiTeamJoinActivity))
2022-11-07 00:15:03 +05:30
class SelectGameWindow(PlaylistAddGameWindow):
2024-01-20 22:05:35 +03:00
def __init__(self, transition: str = "in_right"):
2022-11-07 00:15:03 +05:30
class EditController:
_sessiontype = bs.FreeForAllSession
2022-11-07 00:15:03 +05:30
def get_session_type(self) -> Type[bs.Session]:
2022-11-07 00:15:03 +05:30
return self._sessiontype
self._editcontroller = EditController()
2024-01-20 22:05:35 +03:00
self._r = "addGameWindow"
uiscale = bui.app.ui_v1.uiscale
self._width = 750 if uiscale is babase.UIScale.SMALL else 650
x_inset = 50 if uiscale is babase.UIScale.SMALL else 0
2024-01-20 22:05:35 +03:00
self._height = (
346
if uiscale is babase.UIScale.SMALL
else 380
if uiscale is babase.UIScale.MEDIUM
else 440
)
top_extra = 30 if uiscale is babase.UIScale.SMALL else 20
2022-11-07 00:15:03 +05:30
self._scroll_width = 210
self._root_widget = bui.containerwidget(
2022-11-07 00:15:03 +05:30
size=(self._width, self._height + top_extra),
transition=transition,
2024-01-20 22:05:35 +03:00
scale=(
2.17
if uiscale is babase.UIScale.SMALL
else 1.5
if uiscale is babase.UIScale.MEDIUM
else 1.0
),
stack_offset=(0, 1) if uiscale is babase.UIScale.SMALL else (0, 0),
)
self._back_button = bui.buttonwidget(
parent=self._root_widget,
position=(58 + x_inset, self._height - 53),
size=(165, 70),
scale=0.75,
text_scale=1.2,
label=babase.Lstr(resource="backText"),
autoselect=True,
button_type="back",
on_activate_call=self._back,
)
self._select_button = select_button = bui.buttonwidget(
2022-11-07 00:15:03 +05:30
parent=self._root_widget,
position=(self._width - (172 + x_inset), self._height - 50),
autoselect=True,
size=(160, 60),
scale=0.75,
text_scale=1.2,
2024-01-20 22:05:35 +03:00
label=babase.Lstr(resource="selectText"),
on_activate_call=self._add,
)
2022-11-07 00:15:03 +05:30
if bui.app.ui_v1.use_toolbars:
2024-01-20 22:05:35 +03:00
bui.widget(
edit=select_button, right_widget=bui.get_special_widget("party_button")
)
bui.textwidget(
parent=self._root_widget,
position=(self._width * 0.5, self._height - 28),
size=(0, 0),
scale=1.0,
text=babase.Lstr(resource=self._r + ".titleText"),
h_align="center",
color=bui.app.ui_v1.title_color,
maxwidth=250,
v_align="center",
)
2022-11-07 00:15:03 +05:30
v = self._height - 64
self._selected_title_text = bui.textwidget(
2022-11-07 00:15:03 +05:30
parent=self._root_widget,
position=(x_inset + self._scroll_width + 50 + 30, v - 15),
size=(0, 0),
scale=1.0,
color=(0.7, 1.0, 0.7, 1.0),
maxwidth=self._width - self._scroll_width - 150 - x_inset * 2,
2024-01-20 22:05:35 +03:00
h_align="left",
v_align="center",
)
2022-11-07 00:15:03 +05:30
v -= 30
self._selected_description_text = bui.textwidget(
2022-11-07 00:15:03 +05:30
parent=self._root_widget,
position=(x_inset + self._scroll_width + 50 + 30, v),
size=(0, 0),
scale=0.7,
color=(0.5, 0.8, 0.5, 1.0),
maxwidth=self._width - self._scroll_width - 150 - x_inset * 2,
2024-01-20 22:05:35 +03:00
h_align="left",
)
2022-11-07 00:15:03 +05:30
scroll_height = self._height - 100
v = self._height - 60
2024-01-20 22:05:35 +03:00
self._scrollwidget = bui.scrollwidget(
parent=self._root_widget,
position=(x_inset + 61, v - scroll_height),
size=(self._scroll_width, scroll_height),
highlight=False,
)
bui.widget(
edit=self._scrollwidget,
up_widget=self._back_button,
left_widget=self._back_button,
right_widget=select_button,
)
self._column: Optional[bui.Widget] = None
2022-11-07 00:15:03 +05:30
v -= 35
2024-01-20 22:05:35 +03:00
bui.containerwidget(
edit=self._root_widget,
cancel_button=self._back_button,
start_button=select_button,
)
self._selected_game_type: Optional[Type[bs.GameActivity]] = None
2022-11-07 00:15:03 +05:30
2024-01-20 22:05:35 +03:00
bui.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget)
2022-11-07 00:15:03 +05:30
self._game_types: list[type[bs.GameActivity]] = []
2022-11-07 00:15:03 +05:30
# Get actual games loading in the bg.
2024-01-20 22:05:35 +03:00
babase.app.meta.load_exported_classes(
bs.GameActivity, self._on_game_types_loaded, completion_cb_in_bg_thread=True
)
2022-11-07 00:15:03 +05:30
# Refresh with our initial empty list. We'll refresh again once
# game loading is complete.
self._refresh()
2024-01-20 22:05:35 +03:00
if config["selected"]:
2022-11-07 00:15:03 +05:30
for gt in self._game_types:
2024-01-20 22:05:35 +03:00
if gt.__name__ == config["selected"]:
2022-11-07 00:15:03 +05:30
self._refresh(selected=gt)
self._set_selected_game_type(gt)
2024-01-20 22:05:35 +03:00
def _refresh(
self, select_get_more_games_button: bool = False, selected: bool = None
) -> None:
# from babase.internal import get_game_types
2022-11-07 00:15:03 +05:30
if self._column is not None:
self._column.delete()
2024-01-20 22:05:35 +03:00
self._column = bui.columnwidget(parent=self._scrollwidget, border=2, margin=0)
2022-11-07 00:15:03 +05:30
for i, gametype in enumerate(self._game_types):
def _doit() -> None:
if self._select_button:
2024-01-20 22:05:35 +03:00
bs.apptimer(0.1, self._select_button.activate)
txt = bui.textwidget(
parent=self._column,
position=(0, 0),
size=(self._width - 88, 24),
text=gametype.get_display_string(),
h_align="left",
v_align="center",
color=(0.8, 0.8, 0.8, 1.0),
maxwidth=self._scroll_width * 0.8,
on_select_call=babase.Call(self._set_selected_game_type, gametype),
always_highlight=True,
selectable=True,
on_activate_call=_doit,
)
2022-11-07 00:15:03 +05:30
if i == 0:
bui.widget(edit=txt, up_widget=self._back_button)
2022-11-07 00:15:03 +05:30
self._get_more_games_button = bui.buttonwidget(
2022-11-07 00:15:03 +05:30
parent=self._column,
autoselect=True,
2024-01-20 22:05:35 +03:00
label=babase.Lstr(resource=self._r + ".getMoreGamesText"),
2022-11-07 00:15:03 +05:30
color=(0.54, 0.52, 0.67),
textcolor=(0.7, 0.65, 0.7),
on_activate_call=self._on_get_more_games_press,
2024-01-20 22:05:35 +03:00
size=(178, 50),
)
2022-11-07 00:15:03 +05:30
if select_get_more_games_button:
2024-01-20 22:05:35 +03:00
bui.containerwidget(
edit=self._column,
selected_child=self._get_more_games_button,
visible_child=self._get_more_games_button,
)
2022-11-07 00:15:03 +05:30
def _add(self) -> None:
_babase.lock_all_input() # Make sure no more commands happen.
bs.apptimer(0.1, _babase.unlock_all_input)
2022-11-07 00:15:03 +05:30
gameconfig = {}
2024-01-20 22:05:35 +03:00
if config["selected"] == self._selected_game_type.__name__:
if config["config"]:
gameconfig = config["config"]
if "map" in gameconfig:
gameconfig["settings"]["map"] = gameconfig.pop("map")
2022-11-07 00:15:03 +05:30
self._selected_game_type.create_settings_ui(
2024-01-20 22:05:35 +03:00
self._editcontroller.get_session_type(), gameconfig, self._edit_game_done
)
2022-11-07 00:15:03 +05:30
def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None:
if config:
CustomSession._config = config
CustomSession._gametype = self._selected_game_type
start_game(CustomSession)
else:
2024-01-20 22:05:35 +03:00
bui.app.ui_v1.clear_main_menu_window(transition="out_right")
bui.app.ui_v1.set_main_menu_window(
2024-01-20 22:05:35 +03:00
SelectGameWindow(transition="in_left").get_root_widget(),
from_window=None,
)
2022-11-07 00:15:03 +05:30
def _back(self) -> None:
2024-01-20 22:05:35 +03:00
if not self._root_widget or self._root_widget.transitioning_out:
return
bui.containerwidget(edit=self._root_widget, transition="out_right")
bui.app.ui_v1.set_main_menu_window(
2024-01-20 22:05:35 +03:00
PlayWindow(transition="in_left").get_root_widget(),
from_window=self._root_widget,
)
2022-11-07 00:15:03 +05:30
PlayWindow._old_init = PlayWindow.__init__
def __init__(self, *args, **kwargs):
self._old_init()
width = 800
height = 550
def do_quick_game() -> None:
2024-01-20 22:05:35 +03:00
if not self._root_widget or self._root_widget.transitioning_out:
return
2022-11-07 00:15:03 +05:30
self._save_state()
2024-01-20 22:05:35 +03:00
bui.containerwidget(edit=self._root_widget, transition="out_left")
bui.app.ui_v1.set_main_menu_window(
2024-01-20 22:05:35 +03:00
SelectGameWindow().get_root_widget(), from_window=self._root_widget
)
2022-11-07 00:15:03 +05:30
self._quick_game_button = bui.buttonwidget(
2022-11-07 00:15:03 +05:30
parent=self._root_widget,
position=(width - 55 - 120, height - 132),
autoselect=True,
size=(120, 60),
scale=1.1,
text_scale=1.2,
label=custom_txt,
on_activate_call=do_quick_game,
color=(0.54, 0.52, 0.67),
2024-01-20 22:05:35 +03:00
textcolor=(0.7, 0.65, 0.7),
)
2022-11-07 00:15:03 +05:30
self._restore_state()
def states(self) -> None:
return {
2024-01-20 22:05:35 +03:00
"Team Games": self._teams_button,
"Co-op Games": self._coop_button,
"Free-for-All Games": self._free_for_all_button,
"Back": self._back_button,
"Quick Game": self._quick_game_button,
2022-11-07 00:15:03 +05:30
}
def _save_state(self) -> None:
swapped = {v: k for k, v in states(self).items()}
if self._root_widget.get_selected_child() in swapped:
2024-01-20 22:05:35 +03:00
bui.app.ui_v1.window_states[self.__class__.__name__] = swapped[
self._root_widget.get_selected_child()
]
2022-11-07 00:15:03 +05:30
else:
2024-01-20 22:05:35 +03:00
babase.print_exception(f"Error saving state for {self}.")
2022-11-07 00:15:03 +05:30
def _restore_state(self) -> None:
2024-01-20 22:05:35 +03:00
if not hasattr(self, "_quick_game_button"):
2022-11-07 00:15:03 +05:30
return # ensure that our monkey patched init ran
if self.__class__.__name__ not in bui.app.ui_v1.window_states:
2024-01-20 22:05:35 +03:00
bui.containerwidget(edit=self._root_widget, selected_child=self._coop_button)
2022-11-07 00:15:03 +05:30
return
2024-01-20 22:05:35 +03:00
sel = states(self).get(bui.app.ui_v1.window_states[self.__class__.__name__], None)
2022-11-07 00:15:03 +05:30
if sel:
bui.containerwidget(edit=self._root_widget, selected_child=sel)
2022-11-07 00:15:03 +05:30
else:
2024-01-20 22:05:35 +03:00
bui.containerwidget(edit=self._root_widget, selected_child=self._coop_button)
babase.print_exception(f"Error restoring state for {self}.")
2022-11-07 00:15:03 +05:30
# ba_meta export plugin
class QuickGamePlugin(babase.Plugin):
2022-11-07 00:15:03 +05:30
PlayWindow.__init__ = __init__
PlayWindow._save_state = _save_state
PlayWindow._restore_state = _restore_state