diff --git a/plugins/utilities/CustomDeath.py b/plugins/utilities/CustomDeath.py new file mode 100644 index 0000000..809db73 --- /dev/null +++ b/plugins/utilities/CustomDeath.py @@ -0,0 +1,38 @@ +# 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 diff --git a/plugins/utilities/MaxPlayers.py b/plugins/utilities/MaxPlayers.py new file mode 100644 index 0000000..dce5ec0 --- /dev/null +++ b/plugins/utilities/MaxPlayers.py @@ -0,0 +1,356 @@ +"""===========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 diff --git a/plugins/utilities/QuickCustonGame.py b/plugins/utilities/QuickCustonGame.py new file mode 100644 index 0000000..dcc93c4 --- /dev/null +++ b/plugins/utilities/QuickCustonGame.py @@ -0,0 +1,373 @@ +# 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 diff --git a/plugins/utilities/RandomColors.py b/plugins/utilities/RandomColors.py new file mode 100644 index 0000000..eacf0be --- /dev/null +++ b/plugins/utilities/RandomColors.py @@ -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 diff --git a/plugins/utilities/chat_cmd.py b/plugins/utilities/chat_cmd.py new file mode 100644 index 0000000..cc9150d --- /dev/null +++ b/plugins/utilities/chat_cmd.py @@ -0,0 +1,531 @@ +"""python 3.9 | chatcmd for a beutiful game - BombSquad OwO""" +# modded by IM_NOT_PRANAV#7874 + +# biggggggg thankssssssssssssss to FireFighter1037 for helping everything + +# -*- coding: utf-8 -*- +# ba_meta require api 7 +from _ba import env,get_foreground_host_activity,get_foreground_host_session,get_game_roster, get_chat_messages,set_party_icon_always_visible, chatmessage as cmsg, screenmessage as smsg +import ba + +#our prefix that what we starts cmds with +px='/' + +#main class +class _cmds: + + def _process_cmd(): + set_party_icon_always_visible(True) + messages=get_chat_messages() + if len(messages)>1: + lastmsg = messages[len(messages)-1] + + m=lastmsg.split(' ')[1] + if m.startswith(px): + return _cmds._handle() + else: + pass + + def _handle(): + messages=get_chat_messages() + if len(messages)>1: + lastmsg = messages[len(messages)-1] + + m=lastmsg.split(' ')[1] #cmd + n=lastmsg.split(' ')[2:] #aguments + + roster=get_game_roster() + session=get_foreground_host_session() + session_players=session.sessionplayers + + activity=get_foreground_host_activity() + activity_players=activity.players + + if m == px: + cmsg(px+'help for help') + + elif m == px+'help' : + if n==[]: + cmsg('===========================================') + cmsg(f' {px}help 1 - for page 1 | simple commands') + cmsg(f' {px}help 2 - for page 2 | all or number of list cmds') + cmsg(f' {px}help 3 - for page 3 | Other useful cmds') + cmsg('===========================================') + elif n[0]=='1': + cmsg('============================') + cmsg(f' {px}help 1 page 1 |') + cmsg(f' {px}help 1 page 2 |') + cmsg('============================') + if n[1] in [ 'page' , 'Page' , ]: + if n[2]=='1': + cmsg('============== Help 1, Page 1 ==============') + cmsg(f' your command prefix is or all commands starts with - {px}') + cmsg(f' {px}list or {px}l -- to see ids of players and execute commands') + cmsg(f' {px}uniqeid or {px}id -- to see accountid/uniqeid of player') + cmsg(f' {px}quit or {px}restart -- to restart the game') + cmsg(f' {px}mute/unmute -- to mute chat for everyone in your game') + elif n[2]=='2': + cmsg('============== Help 1, Page 2 ==============') + cmsg(f' {px}pause -- to pause everyone in your game') + cmsg(f' {px}nv or {px}night -- to make night in your game') + cmsg(f' {px}dv or {px}day -- to make night in your game') + cmsg(f' {px}camera_mode -- to rotate camera ,repat to off') + cmsg('===========================================') + elif n[0]=='2': + cmsg('============================') + cmsg(f' {px}help 2 page 1 |') + cmsg(f' {px}help 2 page 2 |') + cmsg(f' {px}help 2 page 3 |') + cmsg('============================') + if n[1] in [ 'page' , 'Page' ]: + if n[2] == '1': + cmsg('============== Help 2 Page 1 ==============') + cmsg(f' {px}kill all or {px}kill number of list | kills the player') + cmsg(f' {px}heal all or {px}heal number of list | heals the players') + cmsg(f' {px}freeze all or {px}freeze number of list | freeze the player') + cmsg(f' {px}unfreeze/thaw all or {px}unfreeze/thaw number of list | unfreeze the player') + cmsg(f' {px}gloves all or {px}gloves number of list | give gloves to player') + cmsg('============================') + elif n[2] == '2': + cmsg('============== Help 2 Page 2 ==============') + cmsg(f' {px}shield all or {px}shield number of list | give shield the player') + cmsg(f' {px}fall all or {px}fall number of list | teleport in down and fall up the player') + cmsg(f' {px}curse all or {px}curse number of list | curse the player') + cmsg(f' {px}creepy all or {px}creepy number of list | make creepy actor of player') + cmsg(f' {px}inv all or {px}inv number of list | makes invisible player') + cmsg(f' {px}celebrate all or {px}celebrate number of list | celebrate action to the player') + cmsg('============================') + elif n[2] == '3': + cmsg('============== Help 2 Page 3 ==============') + cmsg(f' {px}gm all or {px}gm number of list | give bs gods like powers to player') + cmsg(f' {px}sp all or {px}sp number of list | give superrrrrrr damages when punch to player') + cmsg(f' {px}sleep all or {px}sleep number of list | sleep up the player') + cmsg(f' {px}fly all or {px}fly number of list | fly up the player ') + cmsg(f' {px}hug number of list | hugup the player') + cmsg('============================') + + elif n[0]=='3': + cmsg('============================') + cmsg(f" {px}d_bomb bombType | changes default bomb | do {px}d_bomb help for bomb names ") + cmsg(f' {px}dbc (number of bombs) | changes default count of player') + cmsg('============================') + + + elif m in [ px+'list' , px+'l' , px+'clientids' , px+'ids' , px+'playerids' ]: + cmsg('======= Indexs ======') + for i in session_players: + cmsg(i.getname()+' --> '+str(session_players.index(i))+'\n') + if not roster ==[]: + for i in roster: + cmsg(f'======For {px}kick only======') + cmsg(str(i['players'][0]['nam_full'])+' - '+str(i['client_id'])) + + elif m in [ px+'uniqeid' , px+'id' , px+'pb-id' , px+'pb' , px+'accountid' ]: + if n==[]: + cmsg(f'use : {px}uniqeid number of list') + else: + try: + id=session_players[int(n[0])] + cmsg(id.getname()+"'s accountid is "+id.get_v1_account_id()) + except: + cmsg('could not found player') + + elif m in [ px+'quit' , px+'restart' ]: + ba.quit() + + elif m in [ px+'mute' , px+'mutechat' ]: + cfg=ba.app.config + cfg['Chat Muted']=True + cfg.apply_and_commit() + cmsg('muted') + smsg(f'chat muted use {px}unmute and click on send to unmute') + + elif m in [ px+'unmute' , px+'unmutechat' ]: + cfg=ba.app.config + cfg['Chat Muted']=False + cfg.apply_and_commit() + cmsg('un_muted') + smsg('chat un_muted') + + elif m in [ px+'end' , px+'next' ]: + if n==[]: + try: + activity.end_game() + cmsg('Game ended Hope you scored great') + except: + cmsg('Game already ended') + + elif m in [ px+'dv' , px+'day' ]: + if activity.globalsnode.tint==(1.0,1.0,1.0): + cmsg(f'alwardy {px}dv is on ,do {px}nv for night') + else: + activity.globalsnode.tint=(1.0,1.0,1.0) + cmsg('day mode on!') + + elif m in [ px+'nv' , px+'night' ]: + if activity.globalsnode.tint==(0.5, 0.7, 1.0): + cmsg(f'alwardy {px}nv is on ,do {px}dv for day') + else: + activity.globalsnode.tint=(0.5, 0.7, 1.0) + cmsg('night mode on!') + + elif m in [ px+'sm' , px+'slow' , px+'slowmo' ]: + if n==[]: + if not activity.globalsnode.slow_motion: + activity.globalsnode.slow_motion=True + cmsg('Game in Epic Mode Now') + else: + activity.globalsnode.slow_motion=False + cmsg('Game in normal mode now ') + + elif m in [ px+'pause' , px+'pausegame' ]: + if n == []: + if not activity.globalsnode.paused: + activity.globalsnode.paused=True + cmsg('Game Paused') + else: + activity.globalsnode.paused=False + cmsg('Game un paused') + + elif m in [ px+'cameraMode', px+'camera_mode' , px+'rotate_camera' ]: + if n == []: + if not activity.globalsnode.camera_mode == 'rotate': + activity.globalsnode.camera_mode = 'rotate' + cmsg('camera mode is rotate now') + else: + activity.globalsnode.camera_mode = 'follow' + cmsg('camera mode is normal now') + + elif m in [ px+'remove' , px+'rm' ]: + if n == []: + cmsg(f'{px}remove all or {px}remove number in list') + elif n[0] == 'all': + for i in session_players: + i.remove_from_game() + cmsg('Removed All') + else: + try: + r=session_players[int(n[0])] + r.remove_from_game() + cmsg('Removed') #cant use getname() activity alwrady finish + except: + cmsg('could not found player') + elif m in [ px+'inv' , px+'invisible' ]: + if n==[]: + cmsg(f'help : {px}inv all or {px}inv number of list') + elif n[0]=='all': + for i in activity_players: + body=i.actor.node + if not body.torso_model==None: + body.head_model=None + body.torso_model=None + body.upper_arm_model=None + body.forearm_model=None + body.pelvis_model=None + body.hand_model=None + body.toes_model=None + body.upper_leg_model=None + body.lower_leg_model=None + body.style='cyborg' + cmsg('All invisible now Dont get cought') + else: + cmsg('alwardy invisible') + else: + body=activity_players[int(n[0])].actor.node + is_name=session_players[int(n[0])].getname() + if not body.torso_model==None: + body.head_model=None + body.torso_model=None + body.upper_arm_model=None + body.forearm_model=None + body.pelvis_model=None + body.hand_model=None + body.toes_model=None + body.upper_leg_model=None + body.lower_leg_model=None + body.style='cyborg' + cmsg(is_name+' using invisiblelity ') + else: + cmsg('alwardy invisible') + + elif m in [ px+'hl' , px+'headless' ]: + if n==[]: + cmsg(f'help : {px}spaz all or {px}spaz number of list') + elif n[0]=='all': + for i in activity_players: + body=i.actor.node + if not body.head_model==None: + body.head_model=None + body.style='cyborg' + cmsg('headless ? xD') + else: + cmsg('alwardy headless are you really headless?') + else: + body=activity_players[int(n[0])].actor.node + is_name=session_players[int(n[0])].getname() + if not body.head_model==None: + body.head_model=None + body.style='cyborg' + cmsg(is_name+'is headless now xD') + else: + cmsg('alwardy headless are you really headless?') + + elif m in [ px+'creepy' , px+'creep' ]: + if n==[]: + cmsg(f'use: {px}creepy all or {px}creepy number of list') + elif n[0]=='all': + for i in activity_players: + body=i.actor.node + body.head_model=None + body.handlemessage(ba.PowerupMessage(poweruptype='punch')) + body.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('dont creep out childs all will be scared') + else: + try: + body=activity_players[int(n[0])].actor.node + body.head_model=None + body.handlemessage(ba.PowerupMessage(poweruptype='punch')) + body.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('dont creep out childs all will be scared') + except: + cmsg('could not found player to make') + + elif m in [ px+'kill' , px+'die' ]: + if n == []: + cmsg(f'Use : {px}kill all or {px}kill number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.DieMessage()) + cmsg('Killed all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.DieMessage()) + cmsg('Killed '+is_name) + + elif m in [ px+'heal' , px+'heath' ]: + if n == []: + cmsg(f'Use: {px}heal all or {px}heal number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) + cmsg('Heald all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) + cmsg('Heald '+is_name) + + elif m in [ px+'curse' , px+'cur' ]: + if n == []: + cmsg(f'Use: {px}curse all or {px}curse number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='curse')) + cmsg('Cursed all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='curse')) + cmsg('Cursed '+is_name) + + elif m in [ px+'sleep' ]: + if n == []: + cmsg(f'Use: {px}sleep all or {px}sleep number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage('knockout', 8000) + cmsg('Sleep all its Night :)') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage('knockout', 8000) + cmsg(is_name+' sleeped now') + + elif m in [ px+'sp' , px+'superpunch' ]: + if n == []: + cmsg(f'Use : {px}sp/superpunch all or {px}sp/superpunch number of list') + elif n[0]=='all': + for i in activity_players: + if not i.actor._punch_power_scale==15: + i.actor._punch_power_scale=15 + i.actor._punch_cooldown=0 + cmsg('Everyone enjoy your Super punches') + else: + i.actor._punch_power_scale=1.2 + i.actor._punch_cooldown=400 + cmsg('Super punches off now') + else: + try: + if not activity_players[int(n[0])].actor._punch_power_scale==15: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor._punch_power_scale=15 + activity_players[int(n[0])].actor._punch_cooldown=0 + cmsg(is_name+' using super punches get away from him') + else: + activity_players[int(n[0])].actor._punch_power_scale=1.2 + activity_players[int(n[0])].actor._punch_cooldown=400 + cmsg(':( ') + except: + pass + + elif m in [ px+'gloves' , px+'punch' ]: + if n == []: + cmsg(f'Use: {px}gloves all or {px}gloves number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='punch')) + cmsg('Free Gloves enjoy all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='punch')) + cmsg(is_name+' using gloves') + + + elif m in [ px+'shield' , px+'protect' ]: + if n == []: + cmsg(f'Use: {px}shield all or {px}shield number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg('Everyone enjoy free shield :)') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.PowerupMessage(poweruptype='shield')) + cmsg(is_name+' using shield') + + elif m in [ px+'freeze' , px+'ice' ]: + if n == []: + cmsg(f'Use: {px}freeze all or {px}freeze number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.FreezeMessage()) + cmsg('Freezed all') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.FreezeMessage()) + cmsg('Un freezed '+is_name) + + elif m in [ px+'unfreeze' , px+'thaw' ]: + if n == []: + cmsg(f'Use: {px}unfreeze/thaw all or {px}unfreeze/thaw number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.ThawMessage()) + cmsg('Un freezed all ') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.ThawMessage()) + cmsg('Un freezed '+is_name) + + elif m in [ px+'fall' ]: + if n == []: + cmsg(f'Use: {px}fall all or {px}fall number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.StandMessage()) + cmsg('Felt everyone') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.StandMessage()) + cmsg(is_name+' got felt') + + elif m in [ px+'celebrate' , px+'celeb' ]: + if n == []: + cmsg(f'Use: {px}celebrate all or {px}celebrate number of list') + elif n[0]=='all': + for i in activity_players: + i.actor.node.handlemessage(ba.CelebrateMessage()) + cmsg('Celebrate all :)') + else: + is_name=session_players[int(n[0])].getname() + activity_players[int(n[0])].actor.node.handlemessage(ba.CelebrateMessage()) + cmsg(is_name+' is celebrating bt why?') + + elif m in [ px+'fly' ]: + if n==[]: + cmsg(f'Use: {px}fly all or {px}fly number of list') + elif n[0]=='all': + for i in activity_players: + if not i.actor.node.fly==True: + i.actor.node.fly=True + cmsg('fly all dont go out ok') + else: + i.actor.node.fly=False + cmsg('flying mode off') + else: + try: + is_name=session_players[int(n[0])].getname() + if not activity_players[int(n[0])].actor.node.fly==True: + activity_players[int(n[0])].actor.node.fly=True + cmsg(is_name+' is flying') + else: + activity_players[int(n[0])].actor.node.fly=False + cmsg('fly off :(') + except: + cmsg('player not found') + pass + + elif m in [ px+'gm' , px+'godmode' ]: + if n==[]: + cmsg(f'Use: {px}gm all or {px}gm number of list') + elif n[0]=='all': + for i in activity_players: + if not i.actor.node.hockey==True: + i.actor.node.hockey=True + i.actor.node.invincible=True + i.actor._punch_power_scale=7 + cmsg('Gmed all ') + else: + i.actor.node.hockey=False + i.actor.node.invincible=False + i.actor._punch_power_scale=1.2 + cmsg('Un gmed all') + else: + try: + is_name=session_players[int(n[0])].getname() + if not activity_players[int(n[0])].actor.node.hockey==True: + activity_players[int(n[0])].actor.node.hockey=True + activity_players[int(n[0])].actor.node.invincible=True + activity_players[int(n[0])].actor._punch_power_scale=7 + cmsg('Gmed '+is_name) + else: + activity_players[int(n[0])].actor.node.hockey=False + activity_players[int(n[0])].actor.node.invincible=False + activity_players[int(n[0])].actor._punch_power_scale=1.2 + cmsg('un gmed '+is_name) + except: + cmsg('could not found player') + elif m in [ px+'d_bomb', px+'default_bomb' ]: + if n == []: + cmsg(f'Use: {px}d_bomb/default_bomb all or {px}d_bomb number of list ,type {px}d_bomb help for help') + elif n[0]=='help': + cmsg("bombtypes - ['ice', 'impact', 'land_mine', 'normal', 'sticky','tnt']") + elif n[0] in [ 'ice' , 'impact', 'land_mine' , 'normal' , 'sticky' , 'tnt']: + for i in activity_players: + i.actor.bomb_type=n[0] + cmsg('default bomb type - '+str(n[0])+' now') + else: + cmsg('unkwon bombtype , type {px}d_bomb help for help') + + elif m in [ px+'d_bomb_count', px+'default_bomb_count' , px+'dbc' ]: + if n == []: + cmsg(f'Use: {px}d_bomb_count/default_bomb/dbc all or {px}d_bomb_count/default_bomb_count/dbc number of list') + else: + try: + for i in activity_players: + i.actor.set_bomb_count(int(n[0])) + cmsg('default bomb count is '+(str(n[0]))+' now') + except: + cmsg('Must use number to use') + elif m in [ px+'credits' ]: + if n==[]: + cmsg(u'\U0001F95A created by Nazz \U0001F95A') + cmsg(u'\U0001F95A Nazz are past/present/future \U0001F95A') + cmsg(u'\U0001F95A everything is Nazz \U0001F95A') + + + +# ba.timer(0.05, _update, repeat=True) +def same(): + ba.timer(0.5, _cmds._process_cmd, True) + +# ba_meta export plugin +class _enableee(ba.Plugin): + same() \ No newline at end of file