mirror of
https://github.com/bombsquad-community/plugin-manager.git
synced 2025-10-08 14:54:36 +00:00
Add files via upload
This commit is contained in:
parent
d6def17e7e
commit
d64237a5cd
4 changed files with 837 additions and 0 deletions
40
plugins/utilities/custom_death.py
Normal file
40
plugins/utilities/custom_death.py
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# ba_meta require api 7
|
||||||
|
# (see https://ballistica.net/wiki/meta-tag-system)
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import ba
|
||||||
|
from bastd.actor.spaz import Spaz
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
Spaz.oldhandlemessage = Spaz.handlemessage
|
||||||
|
|
||||||
|
|
||||||
|
def handlemessage(self, msg: Any) -> Any:
|
||||||
|
if isinstance(msg, ba.DieMessage):
|
||||||
|
if self.node:
|
||||||
|
self.node.color_texture = ba.gettexture('bonesColor')
|
||||||
|
self.node.color_mask_texture = ba.gettexture('bonesColorMask')
|
||||||
|
self.node.head_model = ba.getmodel('bonesHead')
|
||||||
|
self.node.torso_model = ba.getmodel('bonesTorso')
|
||||||
|
self.node.pelvis_model = ba.getmodel('bonesPelvis')
|
||||||
|
self.node.upper_arm_model = ba.getmodel('bonesUpperArm')
|
||||||
|
self.node.forearm_model = ba.getmodel('bonesForeArm')
|
||||||
|
self.node.hand_model = ba.getmodel('bonesHand')
|
||||||
|
self.node.upper_leg_model = ba.getmodel('bonesUpperLeg')
|
||||||
|
self.node.lower_leg_model = ba.getmodel('bonesLowerLeg')
|
||||||
|
self.node.toes_model = ba.getmodel('bonesToes')
|
||||||
|
self.node.style = 'bones'
|
||||||
|
self.oldhandlemessage(msg)
|
||||||
|
else:
|
||||||
|
return self.oldhandlemessage(msg)
|
||||||
|
|
||||||
|
|
||||||
|
# ba_meta export plugin
|
||||||
|
class CustomDeath(ba.Plugin):
|
||||||
|
Spaz.handlemessage = handlemessage
|
||||||
368
plugins/utilities/max_players.py
Normal file
368
plugins/utilities/max_players.py
Normal file
|
|
@ -0,0 +1,368 @@
|
||||||
|
"""===========MAX_PLAYERS==========="""
|
||||||
|
|
||||||
|
# ba_meta require api 7
|
||||||
|
# (see https://ballistica.net/wiki/meta-tag-system)
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import ba
|
||||||
|
import _ba
|
||||||
|
from ba._session import Session
|
||||||
|
from ba._coopsession import CoopSession, TEAM_COLORS, TEAM_NAMES
|
||||||
|
from ba._multiteamsession import MultiTeamSession
|
||||||
|
from bastd.ui.gather import GatherWindow
|
||||||
|
from bastd.ui.popup import PopupWindow
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import List, Any, Optional, Sequence
|
||||||
|
|
||||||
|
|
||||||
|
cfg = ba.app.config
|
||||||
|
cmp = {'coop_max_players': 4,
|
||||||
|
'teams_max_players': 8,
|
||||||
|
'ffa_max_players': 8}
|
||||||
|
|
||||||
|
lang = ba.app.lang.language
|
||||||
|
if lang == 'Spanish':
|
||||||
|
title_text = 'Máximo de Jugadores'
|
||||||
|
title_short_text = 'Jugadores'
|
||||||
|
coop_text = 'Cooperativo'
|
||||||
|
teams_text = 'Equipos'
|
||||||
|
ffa_text = 'Todos Contra Todos'
|
||||||
|
else:
|
||||||
|
title_text = 'Max Players'
|
||||||
|
title_short_text = 'Players'
|
||||||
|
coop_text = 'Co-op'
|
||||||
|
teams_text = 'Teams'
|
||||||
|
ffa_text = 'FFA'
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigNumberEdit:
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
parent: ba.Widget,
|
||||||
|
position: Tuple[float, float],
|
||||||
|
value: int,
|
||||||
|
config: str,
|
||||||
|
text: str):
|
||||||
|
self._increment = 1
|
||||||
|
self._minval = 1
|
||||||
|
self._maxval = 100
|
||||||
|
self._value = value
|
||||||
|
self._config = config
|
||||||
|
|
||||||
|
textscale = 1.0
|
||||||
|
self.nametext = ba.textwidget(
|
||||||
|
parent=parent,
|
||||||
|
position=(position[0], position[1]),
|
||||||
|
size=(100, 30),
|
||||||
|
text=text,
|
||||||
|
maxwidth=150,
|
||||||
|
color=(0.8, 0.8, 0.8, 1.0),
|
||||||
|
h_align='left',
|
||||||
|
v_align='center',
|
||||||
|
scale=textscale)
|
||||||
|
self.valuetext = ba.textwidget(
|
||||||
|
parent=parent,
|
||||||
|
position=(position[0]+150, position[1]),
|
||||||
|
size=(60, 28),
|
||||||
|
editable=False,
|
||||||
|
color=(0.3, 1.0, 0.3, 1.0),
|
||||||
|
h_align='right',
|
||||||
|
v_align='center',
|
||||||
|
text=str(value),
|
||||||
|
padding=2)
|
||||||
|
self.minusbutton = ba.buttonwidget(
|
||||||
|
parent=parent,
|
||||||
|
position=(position[0]+240, position[1]),
|
||||||
|
size=(28, 28),
|
||||||
|
label='-',
|
||||||
|
autoselect=True,
|
||||||
|
on_activate_call=ba.Call(self._down),
|
||||||
|
repeat=True)
|
||||||
|
self.plusbutton = ba.buttonwidget(
|
||||||
|
parent=parent,
|
||||||
|
position=(position[0]+290, position[1]),
|
||||||
|
size=(28, 28),
|
||||||
|
label='+',
|
||||||
|
autoselect=True,
|
||||||
|
on_activate_call=ba.Call(self._up),
|
||||||
|
repeat=True)
|
||||||
|
|
||||||
|
def _up(self) -> None:
|
||||||
|
self._value = min(self._maxval, self._value + self._increment)
|
||||||
|
self._update_display()
|
||||||
|
|
||||||
|
def _down(self) -> None:
|
||||||
|
self._value = max(self._minval, self._value - self._increment)
|
||||||
|
self._update_display()
|
||||||
|
|
||||||
|
def _update_display(self) -> None:
|
||||||
|
ba.textwidget(edit=self.valuetext, text=str(self._value))
|
||||||
|
cfg['Config Max Players'][self._config] = self._value
|
||||||
|
cfg.apply_and_commit()
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsMaxPlayers(PopupWindow):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
# pylint: disable=too-many-locals
|
||||||
|
uiscale = ba.app.ui.uiscale
|
||||||
|
self._transitioning_out = False
|
||||||
|
self._width = 400
|
||||||
|
self._height = 220
|
||||||
|
bg_color = (0.5, 0.4, 0.6)
|
||||||
|
|
||||||
|
# creates our _root_widget
|
||||||
|
PopupWindow.__init__(self,
|
||||||
|
position=(0.0, 0.0),
|
||||||
|
size=(self._width, self._height),
|
||||||
|
scale=1.2,
|
||||||
|
bg_color=bg_color)
|
||||||
|
|
||||||
|
self._cancel_button = ba.buttonwidget(
|
||||||
|
parent=self.root_widget,
|
||||||
|
position=(25, self._height - 40),
|
||||||
|
size=(50, 50),
|
||||||
|
scale=0.58,
|
||||||
|
label='',
|
||||||
|
color=bg_color,
|
||||||
|
on_activate_call=self._on_cancel_press,
|
||||||
|
autoselect=True,
|
||||||
|
icon=ba.gettexture('crossOut'),
|
||||||
|
iconscale=1.2)
|
||||||
|
ba.containerwidget(edit=self.root_widget,
|
||||||
|
cancel_button=self._cancel_button)
|
||||||
|
|
||||||
|
ba.textwidget(
|
||||||
|
parent=self.root_widget,
|
||||||
|
position=(self._width * 0.5, self._height - 30),
|
||||||
|
size=(0, 0),
|
||||||
|
h_align='center',
|
||||||
|
v_align='center',
|
||||||
|
scale=0.8,
|
||||||
|
text=title_text,
|
||||||
|
maxwidth=200,
|
||||||
|
color=ba.app.ui.title_color)
|
||||||
|
|
||||||
|
posx = 33
|
||||||
|
posy = self._height
|
||||||
|
|
||||||
|
# co-op
|
||||||
|
ConfigNumberEdit(parent=self.root_widget,
|
||||||
|
position=(posx, posy*0.6),
|
||||||
|
value=cfg['Config Max Players']['coop_max_players'],
|
||||||
|
config='coop_max_players',
|
||||||
|
text=coop_text)
|
||||||
|
|
||||||
|
# teams
|
||||||
|
ConfigNumberEdit(parent=self.root_widget,
|
||||||
|
position=(posx, posy*0.38),
|
||||||
|
value=cfg['Config Max Players']['teams_max_players'],
|
||||||
|
config='teams_max_players',
|
||||||
|
text=teams_text)
|
||||||
|
|
||||||
|
# ffa
|
||||||
|
ConfigNumberEdit(parent=self.root_widget,
|
||||||
|
position=(posx, posy*0.16),
|
||||||
|
value=cfg['Config Max Players']['ffa_max_players'],
|
||||||
|
config='ffa_max_players',
|
||||||
|
text=ffa_text)
|
||||||
|
|
||||||
|
def _on_cancel_press(self) -> None:
|
||||||
|
self._transition_out()
|
||||||
|
|
||||||
|
def _transition_out(self) -> None:
|
||||||
|
if not self._transitioning_out:
|
||||||
|
self._transitioning_out = True
|
||||||
|
ba.containerwidget(edit=self.root_widget, transition='out_scale')
|
||||||
|
|
||||||
|
def on_popup_cancel(self) -> None:
|
||||||
|
ba.playsound(ba.getsound('swish'))
|
||||||
|
self._transition_out()
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
"""Instantiate a co-op mode session."""
|
||||||
|
# pylint: disable=cyclic-import
|
||||||
|
from ba._campaign import getcampaign
|
||||||
|
from bastd.activity.coopjoin import CoopJoinActivity
|
||||||
|
|
||||||
|
_ba.increment_analytics_count('Co-op session start')
|
||||||
|
app = _ba.app
|
||||||
|
|
||||||
|
# If they passed in explicit min/max, honor that.
|
||||||
|
# Otherwise defer to user overrides or defaults.
|
||||||
|
if 'min_players' in app.coop_session_args:
|
||||||
|
min_players = app.coop_session_args['min_players']
|
||||||
|
else:
|
||||||
|
min_players = 1
|
||||||
|
if 'max_players' in app.coop_session_args:
|
||||||
|
max_players = app.coop_session_args['max_players']
|
||||||
|
else:
|
||||||
|
max_players = app.config.get(
|
||||||
|
'Coop Game Max Players',
|
||||||
|
cfg['Config Max Players']['coop_max_players'])
|
||||||
|
|
||||||
|
# print('FIXME: COOP SESSION WOULD CALC DEPS.')
|
||||||
|
depsets: Sequence[ba.DependencySet] = []
|
||||||
|
|
||||||
|
Session.__init__(self,
|
||||||
|
depsets,
|
||||||
|
team_names=TEAM_NAMES,
|
||||||
|
team_colors=TEAM_COLORS,
|
||||||
|
min_players=min_players,
|
||||||
|
max_players=max_players)
|
||||||
|
|
||||||
|
# Tournament-ID if we correspond to a co-op tournament (otherwise None)
|
||||||
|
self.tournament_id: Optional[str] = (
|
||||||
|
app.coop_session_args.get('tournament_id'))
|
||||||
|
|
||||||
|
self.campaign = getcampaign(app.coop_session_args['campaign'])
|
||||||
|
self.campaign_level_name: str = app.coop_session_args['level']
|
||||||
|
|
||||||
|
self._ran_tutorial_activity = False
|
||||||
|
self._tutorial_activity: Optional[ba.Activity] = None
|
||||||
|
self._custom_menu_ui: List[Dict[str, Any]] = []
|
||||||
|
|
||||||
|
# Start our joining screen.
|
||||||
|
self.setactivity(_ba.newactivity(CoopJoinActivity))
|
||||||
|
|
||||||
|
self._next_game_instance: Optional[ba.GameActivity] = None
|
||||||
|
self._next_game_level_name: Optional[str] = None
|
||||||
|
self._update_on_deck_game_instances()
|
||||||
|
|
||||||
|
|
||||||
|
def get_max_players(self) -> int:
|
||||||
|
"""Return max number of ba.Players allowed to join the game at once."""
|
||||||
|
if self.use_teams:
|
||||||
|
return _ba.app.config.get(
|
||||||
|
'Team Game Max Players',
|
||||||
|
cfg['Config Max Players']['teams_max_players'])
|
||||||
|
return _ba.app.config.get(
|
||||||
|
'Free-for-All Max Players',
|
||||||
|
cfg['Config Max Players']['ffa_max_players'])
|
||||||
|
|
||||||
|
|
||||||
|
GatherWindow.__old_init__ = GatherWindow.__init__
|
||||||
|
|
||||||
|
|
||||||
|
def __gather_init__(self,
|
||||||
|
transition: Optional[str] = 'in_right',
|
||||||
|
origin_widget: ba.Widget = None):
|
||||||
|
self.__old_init__(transition, origin_widget)
|
||||||
|
|
||||||
|
def _do_max_players():
|
||||||
|
SettingsMaxPlayers()
|
||||||
|
self._max_players_button = ba.buttonwidget(
|
||||||
|
parent=self._root_widget,
|
||||||
|
position=(self._width*0.72, self._height*0.91),
|
||||||
|
size=(220, 60),
|
||||||
|
scale=1.0,
|
||||||
|
color=(0.6, 0.0, 0.9),
|
||||||
|
icon=ba.gettexture('usersButton'),
|
||||||
|
iconscale=1.5,
|
||||||
|
autoselect=True,
|
||||||
|
label=title_short_text,
|
||||||
|
button_type='regular',
|
||||||
|
on_activate_call=_do_max_players)
|
||||||
|
|
||||||
|
|
||||||
|
def _save_state(self) -> None:
|
||||||
|
try:
|
||||||
|
for tab in self._tabs.values():
|
||||||
|
tab.save_state()
|
||||||
|
|
||||||
|
sel = self._root_widget.get_selected_child()
|
||||||
|
selected_tab_ids = [
|
||||||
|
tab_id for tab_id, tab in self._tab_row.tabs.items()
|
||||||
|
if sel == tab.button
|
||||||
|
]
|
||||||
|
if sel == self._back_button:
|
||||||
|
sel_name = 'Back'
|
||||||
|
elif sel == self._max_players_button:
|
||||||
|
sel_name = 'Max Players'
|
||||||
|
elif selected_tab_ids:
|
||||||
|
assert len(selected_tab_ids) == 1
|
||||||
|
sel_name = f'Tab:{selected_tab_ids[0].value}'
|
||||||
|
elif sel == self._tab_container:
|
||||||
|
sel_name = 'TabContainer'
|
||||||
|
else:
|
||||||
|
raise ValueError(f'unrecognized selection: \'{sel}\'')
|
||||||
|
ba.app.ui.window_states[type(self)] = {
|
||||||
|
'sel_name': sel_name,
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
ba.print_exception(f'Error saving state for {self}.')
|
||||||
|
|
||||||
|
|
||||||
|
def _restore_state(self) -> None:
|
||||||
|
from efro.util import enum_by_value
|
||||||
|
try:
|
||||||
|
for tab in self._tabs.values():
|
||||||
|
tab.restore_state()
|
||||||
|
|
||||||
|
sel: Optional[ba.Widget]
|
||||||
|
winstate = ba.app.ui.window_states.get(type(self), {})
|
||||||
|
sel_name = winstate.get('sel_name', None)
|
||||||
|
assert isinstance(sel_name, (str, type(None)))
|
||||||
|
current_tab = self.TabID.ABOUT
|
||||||
|
gather_tab_val = ba.app.config.get('Gather Tab')
|
||||||
|
try:
|
||||||
|
stored_tab = enum_by_value(self.TabID, gather_tab_val)
|
||||||
|
if stored_tab in self._tab_row.tabs:
|
||||||
|
current_tab = stored_tab
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
self._set_tab(current_tab)
|
||||||
|
if sel_name == 'Back':
|
||||||
|
sel = self._back_button
|
||||||
|
elif sel_name == 'Max Players':
|
||||||
|
sel = self._back_button
|
||||||
|
elif sel_name == 'TabContainer':
|
||||||
|
sel = self._tab_container
|
||||||
|
elif isinstance(sel_name, str) and sel_name.startswith('Tab:'):
|
||||||
|
try:
|
||||||
|
sel_tab_id = enum_by_value(self.TabID,
|
||||||
|
sel_name.split(':')[-1])
|
||||||
|
except ValueError:
|
||||||
|
sel_tab_id = self.TabID.ABOUT
|
||||||
|
sel = self._tab_row.tabs[sel_tab_id].button
|
||||||
|
else:
|
||||||
|
sel = self._tab_row.tabs[current_tab].button
|
||||||
|
ba.containerwidget(edit=self._root_widget, selected_child=sel)
|
||||||
|
except Exception:
|
||||||
|
ba.print_exception('Error restoring gather-win state.')
|
||||||
|
|
||||||
|
# ba_meta export plugin
|
||||||
|
|
||||||
|
|
||||||
|
class MaxPlayersPlugin(ba.Plugin):
|
||||||
|
|
||||||
|
def has_settings_ui(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def show_settings_ui(self, source_widget: ba.Widget | None) -> None:
|
||||||
|
SettingsMaxPlayers()
|
||||||
|
|
||||||
|
if 'Config Max Players' in ba.app.config:
|
||||||
|
old_config = ba.app.config['Config Max Players']
|
||||||
|
for setting in cmp:
|
||||||
|
if setting not in old_config:
|
||||||
|
ba.app.config['Config Max Players'].update({setting: cmp[setting]})
|
||||||
|
remove_list = []
|
||||||
|
for setting in old_config:
|
||||||
|
if setting not in cmp:
|
||||||
|
remove_list.append(setting)
|
||||||
|
for element in remove_list:
|
||||||
|
ba.app.config['Config Max Players'].pop(element)
|
||||||
|
else:
|
||||||
|
ba.app.config['Config Max Players'] = cmp
|
||||||
|
ba.app.config.apply_and_commit()
|
||||||
|
|
||||||
|
CoopSession.__init__ = __init__
|
||||||
|
MultiTeamSession.get_max_players = get_max_players
|
||||||
|
GatherWindow.__init__ = __gather_init__
|
||||||
|
GatherWindow._save_state = _save_state
|
||||||
|
GatherWindow._restore_state = _restore_state
|
||||||
381
plugins/utilities/quick_custom_game.py
Normal file
381
plugins/utilities/quick_custom_game.py
Normal file
|
|
@ -0,0 +1,381 @@
|
||||||
|
# ba_meta require api 7
|
||||||
|
# (see https://ballistica.net/wiki/meta-tag-system)
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import ba
|
||||||
|
import _ba
|
||||||
|
from bastd.ui.play import PlayWindow
|
||||||
|
from bastd.ui.playlist.addgame import PlaylistAddGameWindow
|
||||||
|
from ba._freeforallsession import FreeForAllSession
|
||||||
|
from bastd.activity.multiteamjoin import MultiTeamJoinActivity
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
lang = ba.app.lang.language
|
||||||
|
|
||||||
|
if lang == 'Spanish':
|
||||||
|
custom_txt = 'personalizar...'
|
||||||
|
else:
|
||||||
|
custom_txt = 'custom...'
|
||||||
|
|
||||||
|
|
||||||
|
if 'quick_game_button' in ba.app.config:
|
||||||
|
config = ba.app.config['quick_game_button']
|
||||||
|
else:
|
||||||
|
config = {'selected': None, 'config': None}
|
||||||
|
ba.app.config['quick_game_button'] = config
|
||||||
|
ba.app.config.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def start_game(session: ba.Session, fadeout: bool = True):
|
||||||
|
def callback():
|
||||||
|
if fadeout:
|
||||||
|
_ba.unlock_all_input()
|
||||||
|
try:
|
||||||
|
_ba.new_host_session(session)
|
||||||
|
except Exception:
|
||||||
|
from bastd import mainmenu
|
||||||
|
ba.print_exception('exception running session', session)
|
||||||
|
|
||||||
|
# Drop back into a main menu session.
|
||||||
|
_ba.new_host_session(mainmenu.MainMenuSession)
|
||||||
|
|
||||||
|
if fadeout:
|
||||||
|
_ba.fade_screen(False, time=0.25, endcall=callback)
|
||||||
|
_ba.lock_all_input()
|
||||||
|
else:
|
||||||
|
callback()
|
||||||
|
|
||||||
|
|
||||||
|
class SimplePlaylist:
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
settings: dict,
|
||||||
|
gametype: type[ba.GameActivity]):
|
||||||
|
self.settings = settings
|
||||||
|
self.gametype = gametype
|
||||||
|
|
||||||
|
def pull_next(self) -> None:
|
||||||
|
if 'map' not in self.settings['settings']:
|
||||||
|
settings = dict(
|
||||||
|
map=self.settings['map'], **self.settings['settings'])
|
||||||
|
else:
|
||||||
|
settings = self.settings['settings']
|
||||||
|
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
|
||||||
|
ba.Session.__init__(self, depsets=[],
|
||||||
|
team_names=None,
|
||||||
|
team_colors=None,
|
||||||
|
min_players=1,
|
||||||
|
max_players=self.get_max_players())
|
||||||
|
|
||||||
|
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)
|
||||||
|
config['selected'] = self._gametype.__name__
|
||||||
|
config['config'] = self._config
|
||||||
|
ba.app.config.commit()
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
self._next_game: Type[ba.GameActivity] = (
|
||||||
|
self._next_game_spec['resolved_type'])
|
||||||
|
|
||||||
|
# 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(_ba.newactivity(MultiTeamJoinActivity))
|
||||||
|
|
||||||
|
|
||||||
|
class SelectGameWindow(PlaylistAddGameWindow):
|
||||||
|
|
||||||
|
def __init__(self, transition: str = 'in_right'):
|
||||||
|
class EditController:
|
||||||
|
_sessiontype = ba.FreeForAllSession
|
||||||
|
|
||||||
|
def get_session_type(self) -> Type[ba.Session]:
|
||||||
|
return self._sessiontype
|
||||||
|
|
||||||
|
self._editcontroller = EditController()
|
||||||
|
self._r = 'addGameWindow'
|
||||||
|
uiscale = ba.app.ui.uiscale
|
||||||
|
self._width = 750 if uiscale is ba.UIScale.SMALL else 650
|
||||||
|
x_inset = 50 if uiscale is ba.UIScale.SMALL else 0
|
||||||
|
self._height = (346 if uiscale is ba.UIScale.SMALL else
|
||||||
|
380 if uiscale is ba.UIScale.MEDIUM else 440)
|
||||||
|
top_extra = 30 if uiscale is ba.UIScale.SMALL else 20
|
||||||
|
self._scroll_width = 210
|
||||||
|
|
||||||
|
self._root_widget = ba.containerwidget(
|
||||||
|
size=(self._width, self._height + top_extra),
|
||||||
|
transition=transition,
|
||||||
|
scale=(2.17 if uiscale is ba.UIScale.SMALL else
|
||||||
|
1.5 if uiscale is ba.UIScale.MEDIUM else 1.0),
|
||||||
|
stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0))
|
||||||
|
|
||||||
|
self._back_button = ba.buttonwidget(parent=self._root_widget,
|
||||||
|
position=(58 + x_inset,
|
||||||
|
self._height - 53),
|
||||||
|
size=(165, 70),
|
||||||
|
scale=0.75,
|
||||||
|
text_scale=1.2,
|
||||||
|
label=ba.Lstr(resource='backText'),
|
||||||
|
autoselect=True,
|
||||||
|
button_type='back',
|
||||||
|
on_activate_call=self._back)
|
||||||
|
self._select_button = select_button = ba.buttonwidget(
|
||||||
|
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,
|
||||||
|
label=ba.Lstr(resource='selectText'),
|
||||||
|
on_activate_call=self._add)
|
||||||
|
|
||||||
|
if ba.app.ui.use_toolbars:
|
||||||
|
ba.widget(edit=select_button,
|
||||||
|
right_widget=_ba.get_special_widget('party_button'))
|
||||||
|
|
||||||
|
ba.textwidget(parent=self._root_widget,
|
||||||
|
position=(self._width * 0.5, self._height - 28),
|
||||||
|
size=(0, 0),
|
||||||
|
scale=1.0,
|
||||||
|
text=ba.Lstr(resource=self._r + '.titleText'),
|
||||||
|
h_align='center',
|
||||||
|
color=ba.app.ui.title_color,
|
||||||
|
maxwidth=250,
|
||||||
|
v_align='center')
|
||||||
|
v = self._height - 64
|
||||||
|
|
||||||
|
self._selected_title_text = ba.textwidget(
|
||||||
|
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,
|
||||||
|
h_align='left',
|
||||||
|
v_align='center')
|
||||||
|
v -= 30
|
||||||
|
|
||||||
|
self._selected_description_text = ba.textwidget(
|
||||||
|
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,
|
||||||
|
h_align='left')
|
||||||
|
|
||||||
|
scroll_height = self._height - 100
|
||||||
|
|
||||||
|
v = self._height - 60
|
||||||
|
|
||||||
|
self._scrollwidget = ba.scrollwidget(parent=self._root_widget,
|
||||||
|
position=(x_inset + 61,
|
||||||
|
v - scroll_height),
|
||||||
|
size=(self._scroll_width,
|
||||||
|
scroll_height),
|
||||||
|
highlight=False)
|
||||||
|
ba.widget(edit=self._scrollwidget,
|
||||||
|
up_widget=self._back_button,
|
||||||
|
left_widget=self._back_button,
|
||||||
|
right_widget=select_button)
|
||||||
|
self._column: Optional[ba.Widget] = None
|
||||||
|
|
||||||
|
v -= 35
|
||||||
|
ba.containerwidget(edit=self._root_widget,
|
||||||
|
cancel_button=self._back_button,
|
||||||
|
start_button=select_button)
|
||||||
|
self._selected_game_type: Optional[Type[ba.GameActivity]] = None
|
||||||
|
|
||||||
|
ba.containerwidget(edit=self._root_widget,
|
||||||
|
selected_child=self._scrollwidget)
|
||||||
|
|
||||||
|
self._game_types: list[type[ba.GameActivity]] = []
|
||||||
|
|
||||||
|
# Get actual games loading in the bg.
|
||||||
|
ba.app.meta.load_exported_classes(ba.GameActivity,
|
||||||
|
self._on_game_types_loaded,
|
||||||
|
completion_cb_in_bg_thread=True)
|
||||||
|
|
||||||
|
# Refresh with our initial empty list. We'll refresh again once
|
||||||
|
# game loading is complete.
|
||||||
|
self._refresh()
|
||||||
|
|
||||||
|
if config['selected']:
|
||||||
|
for gt in self._game_types:
|
||||||
|
if gt.__name__ == config['selected']:
|
||||||
|
self._refresh(selected=gt)
|
||||||
|
self._set_selected_game_type(gt)
|
||||||
|
|
||||||
|
def _refresh(self,
|
||||||
|
select_get_more_games_button: bool = False,
|
||||||
|
selected: bool = None) -> None:
|
||||||
|
# from ba.internal import get_game_types
|
||||||
|
|
||||||
|
if self._column is not None:
|
||||||
|
self._column.delete()
|
||||||
|
|
||||||
|
self._column = ba.columnwidget(parent=self._scrollwidget,
|
||||||
|
border=2,
|
||||||
|
margin=0)
|
||||||
|
|
||||||
|
for i, gametype in enumerate(self._game_types):
|
||||||
|
|
||||||
|
def _doit() -> None:
|
||||||
|
if self._select_button:
|
||||||
|
ba.timer(0.1,
|
||||||
|
self._select_button.activate,
|
||||||
|
timetype=ba.TimeType.REAL)
|
||||||
|
|
||||||
|
txt = ba.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=ba.Call(
|
||||||
|
self._set_selected_game_type, gametype),
|
||||||
|
always_highlight=True,
|
||||||
|
selectable=True,
|
||||||
|
on_activate_call=_doit)
|
||||||
|
if i == 0:
|
||||||
|
ba.widget(edit=txt, up_widget=self._back_button)
|
||||||
|
|
||||||
|
self._get_more_games_button = ba.buttonwidget(
|
||||||
|
parent=self._column,
|
||||||
|
autoselect=True,
|
||||||
|
label=ba.Lstr(resource=self._r + '.getMoreGamesText'),
|
||||||
|
color=(0.54, 0.52, 0.67),
|
||||||
|
textcolor=(0.7, 0.65, 0.7),
|
||||||
|
on_activate_call=self._on_get_more_games_press,
|
||||||
|
size=(178, 50))
|
||||||
|
if select_get_more_games_button:
|
||||||
|
ba.containerwidget(edit=self._column,
|
||||||
|
selected_child=self._get_more_games_button,
|
||||||
|
visible_child=self._get_more_games_button)
|
||||||
|
|
||||||
|
def _add(self) -> None:
|
||||||
|
_ba.lock_all_input() # Make sure no more commands happen.
|
||||||
|
ba.timer(0.1, _ba.unlock_all_input, timetype=ba.TimeType.REAL)
|
||||||
|
gameconfig = {}
|
||||||
|
if config['selected'] == self._selected_game_type.__name__:
|
||||||
|
if config['config']:
|
||||||
|
gameconfig = config['config']
|
||||||
|
if 'map' in gameconfig:
|
||||||
|
gameconfig['settings']['map'] = gameconfig.pop('map')
|
||||||
|
self._selected_game_type.create_settings_ui(
|
||||||
|
self._editcontroller.get_session_type(),
|
||||||
|
gameconfig,
|
||||||
|
self._edit_game_done)
|
||||||
|
|
||||||
|
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:
|
||||||
|
ba.app.ui.clear_main_menu_window(transition='out_right')
|
||||||
|
ba.app.ui.set_main_menu_window(
|
||||||
|
SelectGameWindow(transition='in_left').get_root_widget())
|
||||||
|
|
||||||
|
def _back(self) -> None:
|
||||||
|
ba.containerwidget(edit=self._root_widget, transition='out_right')
|
||||||
|
ba.app.ui.set_main_menu_window(
|
||||||
|
PlayWindow(transition='in_left').get_root_widget())
|
||||||
|
|
||||||
|
|
||||||
|
PlayWindow._old_init = PlayWindow.__init__
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self._old_init()
|
||||||
|
|
||||||
|
width = 800
|
||||||
|
height = 550
|
||||||
|
|
||||||
|
def do_quick_game() -> None:
|
||||||
|
self._save_state()
|
||||||
|
ba.containerwidget(edit=self._root_widget, transition='out_left')
|
||||||
|
ba.app.ui.set_main_menu_window(
|
||||||
|
SelectGameWindow().get_root_widget())
|
||||||
|
|
||||||
|
self._quick_game_button = ba.buttonwidget(
|
||||||
|
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),
|
||||||
|
textcolor=(0.7, 0.65, 0.7))
|
||||||
|
|
||||||
|
self._restore_state()
|
||||||
|
|
||||||
|
|
||||||
|
def states(self) -> None:
|
||||||
|
return {
|
||||||
|
'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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _save_state(self) -> None:
|
||||||
|
swapped = {v: k for k, v in states(self).items()}
|
||||||
|
if self._root_widget.get_selected_child() in swapped:
|
||||||
|
ba.app.ui.window_states[
|
||||||
|
self.__class__.__name__] = swapped[
|
||||||
|
self._root_widget.get_selected_child()]
|
||||||
|
else:
|
||||||
|
ba.print_exception(f'Error saving state for {self}.')
|
||||||
|
|
||||||
|
|
||||||
|
def _restore_state(self) -> None:
|
||||||
|
if not hasattr(self, '_quick_game_button'):
|
||||||
|
return # ensure that our monkey patched init ran
|
||||||
|
if self.__class__.__name__ not in ba.app.ui.window_states:
|
||||||
|
ba.containerwidget(edit=self._root_widget,
|
||||||
|
selected_child=self._coop_button)
|
||||||
|
return
|
||||||
|
sel = states(self).get(
|
||||||
|
ba.app.ui.window_states[self.__class__.__name__], None)
|
||||||
|
if sel:
|
||||||
|
ba.containerwidget(edit=self._root_widget, selected_child=sel)
|
||||||
|
else:
|
||||||
|
ba.containerwidget(edit=self._root_widget,
|
||||||
|
selected_child=self._coop_button)
|
||||||
|
ba.print_exception(f'Error restoring state for {self}.')
|
||||||
|
|
||||||
|
|
||||||
|
# ba_meta export plugin
|
||||||
|
class QuickGamePlugin(ba.Plugin):
|
||||||
|
PlayWindow.__init__ = __init__
|
||||||
|
PlayWindow._save_state = _save_state
|
||||||
|
PlayWindow._restore_state = _restore_state
|
||||||
48
plugins/utilities/random_colors.py
Normal file
48
plugins/utilities/random_colors.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# ba_meta require api 7
|
||||||
|
# (see https://ballistica.net/wiki/meta-tag-system)
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import ba
|
||||||
|
import random
|
||||||
|
from bastd.actor import bomb
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Sequence
|
||||||
|
|
||||||
|
|
||||||
|
class NewBlast(bomb.Blast):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
position: Sequence[float] = (0.0, 1.0, 0.0),
|
||||||
|
velocity: Sequence[float] = (0.0, 0.0, 0.0),
|
||||||
|
blast_radius: float = 2.0,
|
||||||
|
blast_type: str = 'normal',
|
||||||
|
source_player: ba.Player | None = None,
|
||||||
|
hit_type: str = 'explosion',
|
||||||
|
hit_subtype: str = 'normal',
|
||||||
|
):
|
||||||
|
super().__init__(position, velocity, blast_radius, blast_type,
|
||||||
|
source_player, hit_type, hit_subtype)
|
||||||
|
scorch_radius = light_radius = self.radius
|
||||||
|
if self.blast_type == 'tnt':
|
||||||
|
scorch_radius *= 1.15
|
||||||
|
scorch = ba.newnode(
|
||||||
|
'scorch',
|
||||||
|
attrs={
|
||||||
|
'position': position,
|
||||||
|
'size': scorch_radius * 0.5,
|
||||||
|
'big': (self.blast_type == 'tnt'),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
random_color = (random.random(), random.random(), random.random())
|
||||||
|
scorch.color = ba.safecolor(random_color)
|
||||||
|
ba.animate(scorch, 'presence', {3.000: 1, 13.000: 0})
|
||||||
|
ba.timer(13.0, scorch.delete)
|
||||||
|
|
||||||
|
|
||||||
|
# ba_meta export plugin
|
||||||
|
class RandomColorsPlugin(ba.Plugin):
|
||||||
|
bomb.Blast = NewBlast
|
||||||
Loading…
Add table
Add a link
Reference in a new issue