From 59974adb993d31ca9c5b90a487e0c88ce724bb4b Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 17 Dec 2022 22:28:44 +0530 Subject: [PATCH 01/82] Play back press sound only once --- plugin_manager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index 51051ad..0b89e5e 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1420,7 +1420,6 @@ class PluginManagerWindow(ba.Window): ) def _back(self) -> None: - play_sound() from bastd.ui.settings.allsettings import AllSettingsWindow ba.containerwidget(edit=self._root_widget, transition=self._transition_out) From 6a2e077dd396be9ec39bc994acab619356535a52 Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Sun, 18 Dec 2022 15:41:50 +0530 Subject: [PATCH 02/82] Moved download button --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b7d90c6..6d07109 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,3 @@ -[![DownloadIcon]][DownloadLink] - -[DownloadIcon]:https://img.shields.io/badge/Download-5555ff?style=for-the-badge&logoColor=white&logo=DocuSign -[DownloadLink]:https://cdn.jsdelivr.net/gh/bombsquad-community/plugin-manager/plugin_manager.py - [![CI](https://github.com/bombsquad-community/plugin-manager/actions/workflows/ci.yml/badge.svg)](https://github.com/bombsquad-community/plugin-manager/actions/workflows/ci.yml) # plugin-manager @@ -10,6 +5,11 @@ A plugin manager for the game - [Bombsquad](https://www.froemling.net/apps/bombsquad). Plugin manager is a plugin in itself, which makes further modding of your game more convenient by providing easier access to community created content. +[![DownloadIcon]][DownloadLink] + +[DownloadIcon]:https://img.shields.io/badge/Download-5555ff?style=for-the-badge&logoColor=white&logo=DocuSign +[DownloadLink]:https://cdn.jsdelivr.net/gh/bombsquad-community/plugin-manager/plugin_manager.py + ![Plugin Manager GIF](https://user-images.githubusercontent.com/106954762/190505304-519c4b91-2461-42b1-be57-655a3fb0cbe8.gif) ## Features From f86623a09ad4c5935ed0f7e85d12374b50f29431 Mon Sep 17 00:00:00 2001 From: imayushsaini Date: Sun, 18 Dec 2022 11:24:08 +0000 Subject: [PATCH 03/82] [ci] auto-format --- plugins/utilities/advanced_party_window.py | 6 +- plugins/utilities/easy_connect.py | 109 +++++++++++---------- 2 files changed, 60 insertions(+), 55 deletions(-) diff --git a/plugins/utilities/advanced_party_window.py b/plugins/utilities/advanced_party_window.py index d40b718..8f36b02 100644 --- a/plugins/utilities/advanced_party_window.py +++ b/plugins/utilities/advanced_party_window.py @@ -67,7 +67,7 @@ ssl._create_default_https_context = ssl._create_unverified_context def newconnect_to_party(address, port=43210, print_progress=False): global ip_add global p_port - + dd = _ba.get_connection_to_host_info() if (dd != {}): _ba.disconnect_from_host() @@ -1724,7 +1724,7 @@ def fetchAccountInfo(account, loading_widget): if account in fdata: servers = fdata[account] url = f'https://{BCSSERVER}/player?key={base64.b64encode(account.encode("utf-8")).decode("utf-8")}&base64=true' - + data = urllib.request.urlopen(url) account_data = json.loads(data.read().decode('utf-8'))[0] pbid = account_data["pbid"] @@ -2175,6 +2175,8 @@ class CustomAccountViewerWindow(viewer.AccountViewerWindow): ba.print_exception('Error displaying account info.') # ba_meta export plugin + + class bySmoothy(ba.Plugin): def __init__(self): if _ba.env().get("build_number", 0) >= 20577: diff --git a/plugins/utilities/easy_connect.py b/plugins/utilities/easy_connect.py index 3b3a26e..d14745c 100644 --- a/plugins/utilities/easy_connect.py +++ b/plugins/utilities/easy_connect.py @@ -63,6 +63,7 @@ https://ballistica.net/discord """ BCSURL = 'https://bcsserver.bombsquad.ga/bannedservers' + def is_game_version_lower_than(version): """ Returns a boolean value indicating whether the current game @@ -79,6 +80,7 @@ if is_game_version_lower_than("1.7.7"): else: ba_internal = ba.internal + def updateBannedServersCache(): response = None config = ba.app.config @@ -508,61 +510,62 @@ def popup_menu_selected_choice(self, window: popup.PopupMenu, def _update_party_lists(self) -> None: - if not self._party_lists_dirty: - return - starttime = time.time() - config = ba.app.config - bannedservers = config.get('Banned Servers',[]) - assert len(self._parties_sorted) == len(self._parties) + if not self._party_lists_dirty: + return + starttime = time.time() + config = ba.app.config + bannedservers = config.get('Banned Servers', []) + assert len(self._parties_sorted) == len(self._parties) - self._parties_sorted.sort( - key=lambda p: ( - p[1].ping if p[1].ping is not None else 999999.0, - p[1].index, - ) + self._parties_sorted.sort( + key=lambda p: ( + p[1].ping if p[1].ping is not None else 999999.0, + p[1].index, + ) + ) + + # If signed out or errored, show no parties. + if ( + ba.internal.get_v1_account_state() != 'signed_in' + or not self._have_valid_server_list + ): + self._parties_displayed = {} + else: + if self._filter_value: + filterval = self._filter_value.lower() + self._parties_displayed = { + k: v + for k, v in self._parties_sorted + if (filterval in v.name.lower() or filterval in v.address) and (v.address not in bannedservers if ENABLE_SERVER_BANNING else True) + } + else: + self._parties_displayed = { + k: v + for k, v in self._parties_sorted + if (v.address not in bannedservers if ENABLE_SERVER_BANNING else True) + } + + # Any time our selection disappears from the displayed list, go back to + # auto-selecting the top entry. + if ( + self._selection is not None + and self._selection.entry_key not in self._parties_displayed + ): + self._have_user_selected_row = False + + # Whenever the user hasn't selected something, keep the first visible + # row selected. + if not self._have_user_selected_row and self._parties_displayed: + firstpartykey = next(iter(self._parties_displayed)) + self._selection = Selection(firstpartykey, SelectionComponent.NAME) + + self._party_lists_dirty = False + if DEBUG_PROCESSING: + print( + f'Sorted {len(self._parties_sorted)} parties in' + f' {time.time()-starttime:.5f}s.' ) - # If signed out or errored, show no parties. - if ( - ba.internal.get_v1_account_state() != 'signed_in' - or not self._have_valid_server_list - ): - self._parties_displayed = {} - else: - if self._filter_value: - filterval = self._filter_value.lower() - self._parties_displayed = { - k: v - for k, v in self._parties_sorted - if (filterval in v.name.lower() or filterval in v.address) and (v.address not in bannedservers if ENABLE_SERVER_BANNING else True) - } - else: - self._parties_displayed = { - k: v - for k, v in self._parties_sorted - if (v.address not in bannedservers if ENABLE_SERVER_BANNING else True) - } - - # Any time our selection disappears from the displayed list, go back to - # auto-selecting the top entry. - if ( - self._selection is not None - and self._selection.entry_key not in self._parties_displayed - ): - self._have_user_selected_row = False - - # Whenever the user hasn't selected something, keep the first visible - # row selected. - if not self._have_user_selected_row and self._parties_displayed: - firstpartykey = next(iter(self._parties_displayed)) - self._selection = Selection(firstpartykey, SelectionComponent.NAME) - - self._party_lists_dirty = False - if DEBUG_PROCESSING: - print( - f'Sorted {len(self._parties_sorted)} parties in' - f' {time.time()-starttime:.5f}s.' - ) def replace(): manualtab.ManualGatherTab._build_favorites_tab = new_build_favorites_tab @@ -697,5 +700,5 @@ class InitalRun(ba.Plugin): def __init__(self): replace() config = ba.app.config - if config["launchCount"]% 5 ==0: + if config["launchCount"] % 5 == 0: updateBannedServersCache() From 64e8a5c629ed7b4c21ca213c3486ea0d5c6e722c Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 19 Dec 2022 01:45:20 +0530 Subject: [PATCH 04/82] Create metadata entry --- plugins/utilities.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8737a94..f9d2b2c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -299,6 +299,7 @@ } ], "versions": { + "1.2.1": null, "1.2.0": { "api_version": 7, "commit_sha": "b7036af", @@ -324,6 +325,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "e994af5", @@ -362,6 +364,7 @@ } ], "versions": { + "1.0.1": null, "1.0.0": { "api_version": 7, "commit_sha": "e994af5", @@ -567,4 +570,4 @@ } } } -} \ No newline at end of file +} From edaf26311b9ebc3dfd0b6d35f737131d458e5f07 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 18 Dec 2022 20:16:09 +0000 Subject: [PATCH 05/82] [ci] apply-version-metadata --- plugins/utilities.json | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index f9d2b2c..80af302 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -299,7 +299,12 @@ } ], "versions": { - "1.2.1": null, + "1.2.1": { + "api_version": 7, + "commit_sha": "64e8a5c", + "released_on": "18-12-2022", + "md5sum": "5237713243bd3ba5dd20a5efc568f40d" + }, "1.2.0": { "api_version": 7, "commit_sha": "b7036af", @@ -325,7 +330,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 7, + "commit_sha": "64e8a5c", + "released_on": "18-12-2022", + "md5sum": "7807b532802d17b77a0017c46ac1cbfb" + }, "1.0.0": { "api_version": 7, "commit_sha": "e994af5", @@ -364,7 +374,12 @@ } ], "versions": { - "1.0.1": null, + "1.0.1": { + "api_version": 7, + "commit_sha": "64e8a5c", + "released_on": "18-12-2022", + "md5sum": "8efcf38604e5519d66a858cc38868641" + }, "1.0.0": { "api_version": 7, "commit_sha": "e994af5", @@ -570,4 +585,4 @@ } } } -} +} \ No newline at end of file From 6e9d698b592b5dd4d27f0e43b979889065d3cd3d Mon Sep 17 00:00:00 2001 From: * Date: Tue, 20 Dec 2022 16:41:44 +0530 Subject: [PATCH 06/82] Updated share_replay to v1.3.0 --- plugins/utilities.json | 3 +- plugins/utilities/share_replay.py | 500 +++++++++++++++++++----------- 2 files changed, 323 insertions(+), 180 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 80af302..d134e88 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,6 +14,7 @@ } ], "versions": { + "1.3.0": null, "1.2.1": { "api_version": 7, "commit_sha": "7753b87", @@ -585,4 +586,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index 9909816..f442dcd 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -1,10 +1,24 @@ +""" + Plugin by LoupGarou a.k.a Loup/Soup + Discord →ʟօʊքɢǟʀօʊ#3063 +Share replays easily with your friends or have a backup + +Exported replays are stored in replays folder which is inside mods folder +You can start sharing replays by opening the watch window and going to share replay tab + +Feel free to let me know if you use this plugin,i love to hear that :) + +Message me in discord if you find some bug +Use this code for your experiments or plugin but please dont rename this plugin and distribute with your name,don't do that,its bad' +""" + # ba_meta require api 7 from __future__ import annotations from typing import TYPE_CHECKING, cast if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union -from os import listdir, mkdir, path, sep +from os import listdir, mkdir, path, sep,remove from shutil import copy, copytree import ba @@ -12,12 +26,23 @@ import _ba from enum import Enum from bastd.ui.tabs import TabRow from bastd.ui.confirm import ConfirmWindow -from bastd.ui.watch import WatchWindow as ww +from bastd.ui.watch import WatchWindow from bastd.ui.popup import PopupWindow -# mod by ʟօʊքɢǟʀօʊ -# export replays to mods folder and share with your friends or have a backup +title = "SHARE REPLAY" +internal_dir = _ba.get_replays_dir()+sep +external_dir = path.join(_ba.env()["python_directory_user"], "replays"+sep) +uiscale = ba.app.ui.uiscale + +# colors +pink = (1, 0.2, 0.8) +green = (0.4, 1, 0.4) +red = (1, 0, 0) +blue = (0.26, 0.65, 0.94) +blue_highlight = (0.4, 0.7, 1) +b_color = (0.6, 0.53, 0.63) +b_textcolor = (0.75, 0.7, 0.8) def Print(*args, color=None, top=None): out = "" @@ -35,174 +60,31 @@ def cprint(*args): _ba.chatmessage(out) -title = "SHARE REPLAY" -internal_dir = _ba.get_replays_dir()+sep -external_dir = path.join(_ba.env()["python_directory_user"], "replays"+sep) - -# colors -pink = (1, 0.2, 0.8) -green = (0.4, 1, 0.4) -red = (1, 0, 0) -blue = (0.26, 0.65, 0.94) -blue_highlight = (0.4, 0.7, 1) - if not path.exists(external_dir): mkdir(external_dir) Print("You are ready to share replays", color=pink) -class Help(PopupWindow): - def __init__(self): - uiscale = ba.app.ui.uiscale - self.width = 1000 - self.height = 300 - PopupWindow.__init__(self, - position=(0.0, 0.0), - size=(self.width, self.height), - scale=1.2,) +def override(cls: ClassType) -> Callable[[MethodType], MethodType]: + def decorator(newfunc: MethodType) -> MethodType: + funcname = newfunc.__code__.co_name + if hasattr(cls, funcname): + oldfunc = getattr(cls, funcname) + setattr(cls, f'_old_{funcname}', oldfunc) - ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) - ba.textwidget(parent=self.root_widget, position=(0, self.height * 0.6), - text=f">Replays are exported to\n {external_dir}\n>Copy replays to the above folder to be able to import them into the game\n>I would live to hear from you,meet me on discord\n -LoupGarou(author)") + setattr(cls, funcname, newfunc) + return newfunc - def close(self): - ba.playsound(ba.getsound('swish')) - ba.containerwidget(edit=self.root_widget, transition="out_right",) + return decorator -class SettingWindow(): - def __init__(self): - self.draw_ui() - ba.containerwidget(edit=self.root, cancel_button=self.close_button) - self.selected_name = None - # setting tab when window opens - self.on_tab_select(self.TabId.INTERNAL) - self.tab_id = self.TabId.INTERNAL - - class TabId(Enum): - INTERNAL = "internal" - EXTERNAL = "external" +class CommonUtilities: def sync_confirmation(self): ConfirmWindow(text="WARNING:\nreplays with same name in mods folder\n will be overwritten", action=self.sync, cancel_is_selected=True) - def on_select_text(self, widget, name): - existing_widgets = self.scroll2.get_children() - for i in existing_widgets: - ba.textwidget(edit=i, color=(1, 1, 1)) - ba.textwidget(edit=widget, color=(1, 1, 0)) - self.selected_name = name - - def on_tab_select(self, tab_id): - self.tab_id = tab_id - if tab_id == self.TabId.INTERNAL: - dir_list = listdir(internal_dir) - ba.buttonwidget(edit=self.share_button, label="EXPORT", icon=ba.gettexture("upButton"),) - else: - dir_list = listdir(external_dir) - ba.buttonwidget(edit=self.share_button, label="IMPORT", - icon=ba.gettexture("downButton"),) - self.tab_row.update_appearance(tab_id) - dir_list = sorted(dir_list) - existing_widgets = self.scroll2.get_children() - if existing_widgets: - for i in existing_widgets: - i.delete() - height = 900 - # making textwidgets for all replays - for i in dir_list: - height -= 40 - a = i - i = ba.textwidget( - parent=self.scroll2, - size=(500, 50), - text=i.split(".")[0], - position=(10, height), - selectable=True, - max_chars=40, - corner_scale=1.3, - click_activate=True,) - ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) - - def draw_ui(self): - self.uiscale = ba.app.ui.uiscale - self.root = ba.Window(ba.containerwidget( - size=(900, 670), on_outside_click_call=self.close, transition="in_right")).get_root_widget() - - self.close_button = ba.buttonwidget( - parent=self.root, - position=(90, 560), - button_type='backSmall', - size=(60, 60), - label=ba.charstr(ba.SpecialChar.BACK), - scale=1.5, - on_activate_call=self.close) - - ba.textwidget( - parent=self.root, - size=(200, 100), - position=(350, 550), - scale=2, - selectable=False, - h_align="center", - v_align="center", - text=title, - color=green) - - ba.buttonwidget( - parent=self.root, - position=(650, 580), - size=(35, 35), - texture=ba.gettexture("achievementEmpty"), - label="", - on_activate_call=Help) - - tabdefs = [(self.TabId.INTERNAL, 'INTERNAL'), (self.TabId.EXTERNAL, "EXTERNAL")] - self.tab_row = TabRow(self.root, tabdefs, pos=(150, 500-5), - size=(500, 300), on_select_call=self.on_tab_select) - - self.share_button = ba.buttonwidget( - parent=self.root, - position=(720, 400), - size=(110, 50), - scale=1.5, - button_type="square", - label="EXPORT", - text_scale=2, - icon=ba.gettexture("upButton"), - on_activate_call=self.share) - - sync_button = ba.buttonwidget( - parent=self.root, - position=(720, 300), - size=(110, 50), - scale=1.5, - button_type="square", - label="SYNC", - text_scale=2, - icon=ba.gettexture("ouyaYButton"), - on_activate_call=self.sync_confirmation) - - scroll = ba.scrollwidget( - parent=self.root, - size=(600, 400), - position=(100, 100),) - self.scroll2 = ba.columnwidget(parent=scroll, size=( - 500, 900)) - - def share(self): - if self.selected_name is None: - Print("Select a replay", color=red) - return - if self.tab_id == self.TabId.INTERNAL: - self.export() - else: - self.importx() - - # image={"texture":ba.gettexture("bombColor"),"tint_texture":None,"tint_color":None,"tint2_color":None}) - def sync(self): internal_list = listdir(internal_dir) external_list = listdir(external_dir) @@ -215,13 +97,233 @@ class SettingWindow(): copy(external_dir+sep+i, internal_dir+sep+i) Print("Synced all replays", color=pink) - def export(self): - copy(internal_dir+self.selected_name, external_dir+self.selected_name) - Print(self.selected_name[0:-4]+" exported", top=True, color=pink) + def _copy(self, selected_replay,tab_id): + if selected_replay is None: + Print("Select a replay", color=red) + return + elif tab_id==MyTabId.INTERNAL: + copy(internal_dir+selected_replay, external_dir+selected_replay) + Print(selected_replay[0:-4]+" exported", top=True, color=pink) + else: + copy(external_dir+selected_replay, internal_dir+selected_replay) + Print(selected_replay[0:-4]+" imported", top=True, color=green) + + def delete_replay(self,selected_replay,tab_id,cls_inst): + if selected_replay is None: + Print("Select a replay", color=red) + return + def do_it(): + if tab_id==MyTabId.INTERNAL: + remove(internal_dir+selected_replay) + elif tab_id==MyTabId.EXTERNAL: + remove(external_dir+selected_replay) + cls_inst.on_tab_select(tab_id) #updating the tab + Print(selected_replay[0:-4]+" was deleted", top=True, color=red) + ConfirmWindow(text=f"Delete \"{selected_replay.split('.')[0]}\" \nfrom {'internal directory' if tab_id==MyTabId.INTERNAL else 'external directory'}?", + action=do_it, cancel_is_selected=True) + + +CommonUtils = CommonUtilities() - def importx(self): - copy(external_dir+self.selected_name, internal_dir+self.selected_name) - Print(self.selected_name[0:-4]+" imported", top=True, color=green) + +class MyTabId(Enum): + INTERNAL = "internal" + EXTERNAL = "external" + SHARE_REPLAYS = "share_replay" + +class Help(PopupWindow): + def __init__(self): + self.width = 1200 + self.height = 250 + self.root_widget = ba.Window(ba.containerwidget( + size=(self.width, self.height), on_outside_click_call=self.close, transition="in_right")).get_root_widget() + + ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) + ba.textwidget(parent=self.root_widget, position=(0, self.height * 0.7),corner_scale=1.2 ,color=green, + text=f"»Replays are exported to\n {external_dir}\n»Copy replays to the above folder to be able to import them into the game\n»I would love to hear from you,meet me on discord\n -LoupGarou(author)") + + def close(self): + ba.playsound(ba.getsound('swish')) + ba.containerwidget(edit=self.root_widget, transition="out_right",) + + +class ShareTabUi(WatchWindow): + def __init__(self, root_widget=None): + self.tab_id = MyTabId.INTERNAL + self.selected_replay = None + + if root_widget is None: + self.root = ba.Window(ba.containerwidget( + size=(1000, 600), on_outside_click_call=self.close, transition="in_right")).get_root_widget() + + else: + self.root = root_widget + + self.draw_ui() + + + def on_select_text(self, widget, name): + existing_widgets = self.scroll2.get_children() + for i in existing_widgets: + ba.textwidget(edit=i, color=(1, 1, 1)) + ba.textwidget(edit=widget, color=(1.0, 1, 0.4)) + self.selected_replay = name + + def on_tab_select(self, tab_id): + self.selected_replay = None + self.tab_id = tab_id + t_scale = 1.6 + + if tab_id == MyTabId.INTERNAL: + dir_list = listdir(internal_dir) + ba.buttonwidget(edit=self.share_button, label="Export\nReplay") + else: + dir_list = listdir(external_dir) + ba.buttonwidget(edit=self.share_button, label="Import\nReplay") + + self.tab_row.update_appearance(tab_id) + dir_list = sorted(dir_list) + existing_widgets = self.scroll2.get_children() + if existing_widgets:# deleting textwidgets from old tab + for i in existing_widgets: + i.delete() + height = 900 + for i in dir_list:# making textwidgets for all replays + height -= 50 + a = i + i = ba.textwidget( + parent=self.scroll2, + size=(self._my_replays_scroll_width/t_scale, 30), + text=i.split(".")[0], + position=(20, height), + selectable=True, + max_chars=40, + corner_scale=t_scale, + click_activate=True, + always_highlight=True,) + ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) + + def draw_ui(self): + self._r = 'watchWindow' + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + scroll_buffer_h = 130 + 2 * x_inset + self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 + self._height = ( + 578 + if uiscale is ba.UIScale.SMALL + else 670 + if uiscale is ba.UIScale.MEDIUM + else 800) + self._scroll_width = self._width - scroll_buffer_h + self._scroll_height = self._height - 180 + # + c_width = self._scroll_width + c_height = self._scroll_height - 20 + sub_scroll_height = c_height - 63 + self._my_replays_scroll_width = sub_scroll_width = ( + 680 if uiscale is ba.UIScale.SMALL else 640 + ) + + v = c_height - 30 + b_width = 140 if uiscale is ba.UIScale.SMALL else 178 + b_height = ( + 107 + if uiscale is ba.UIScale.SMALL + else 142 + if uiscale is ba.UIScale.MEDIUM + else 190 + ) + b_space_extra = ( + 0 + if uiscale is ba.UIScale.SMALL + else -2 + if uiscale is ba.UIScale.MEDIUM + else -5 + ) + + b_color = (0.6, 0.53, 0.63) + b_textcolor = (0.75, 0.7, 0.8) + btnv = (c_height- (48 + if uiscale is ba.UIScale.SMALL + else 45 + if uiscale is ba.UIScale.MEDIUM + else 40) - b_height) + btnh = 40 if uiscale is ba.UIScale.SMALL else 40 + smlh = 190 if uiscale is ba.UIScale.SMALL else 225 + tscl = 1.0 if uiscale is ba.UIScale.SMALL else 1.2 + + stab_width=500 + stab_height=300 + stab_h=smlh + + v -= sub_scroll_height + 23 + scroll = ba.scrollwidget( + parent=self.root, + position=(smlh, v), + size=(sub_scroll_width, sub_scroll_height), + ) + + self.scroll2 = ba.columnwidget(parent=scroll, + size=(sub_scroll_width, sub_scroll_height)) + + tabdefs = [(MyTabId.INTERNAL, 'INTERNAL'), (MyTabId.EXTERNAL, "EXTERNAL")] + self.tab_row = TabRow(self.root, tabdefs, pos=(stab_h,sub_scroll_height), + size=(stab_width,stab_height), on_select_call=self.on_tab_select) + + helpbtn_space=20 + helpbtn_v=stab_h+stab_width+helpbtn_space+120 + helpbtn_h=sub_scroll_height+helpbtn_space + + ba.buttonwidget( + parent=self.root, + position=(helpbtn_v ,helpbtn_h ), + size=(35, 35), + button_type="square", + label="?", + text_scale=1.5, + color=b_color, + textcolor=b_textcolor, + on_activate_call=Help) + + call_copy=lambda:CommonUtils._copy(self.selected_replay,self.tab_id) + self.share_button = ba.buttonwidget( + parent=self.root, + size=(b_width, b_height), + position=(btnh, btnv), + button_type="square", + label="Export\nReplay", + text_scale=tscl, + color=b_color, + textcolor=b_textcolor, + on_activate_call=call_copy) + + btnv -= b_height + b_space_extra + sync_button = ba.buttonwidget( + parent=self.root, + size=(b_width, b_height), + position=(btnh, btnv), + button_type="square", + label="Sync\nReplay", + text_scale=tscl, + color=b_color, + textcolor=b_textcolor, + on_activate_call=CommonUtils.sync_confirmation) + + btnv -= b_height + b_space_extra + call_delete = lambda:CommonUtils.delete_replay(self.selected_replay,self.tab_id,self) + delete_replay_button = ba.buttonwidget( + parent=self.root, + size=(b_width, b_height), + position=(btnh, btnv), + button_type="square", + label=ba.Lstr(resource=self._r + '.deleteReplayButtonText'), + text_scale=tscl, + color=b_color, + textcolor=b_textcolor, + on_activate_call=call_delete) + + + self.on_tab_select(MyTabId.INTERNAL) def close(self): ba.playsound(ba.getsound('swish')) @@ -232,33 +334,73 @@ class SettingWindow(): #ba.widget(edit=self.enable_button, up_widget=decrease_button, down_widget=self.lower_text,left_widget=save_button, right_widget=save_button) -# -------------------------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------- -ww.__old_init__ = ww.__init__ +class ShareTab(WatchWindow): + @override(WatchWindow) + def __init__(self, + transition: str | None = 'in_right', + origin_widget: ba.Widget | None = None, + oldmethod=None): + self.my_tab_container = None + self._old___init__(transition, origin_widget) -def new_init(self, transition="in_right", origin_widget=None): - self.__old_init__(transition, origin_widget) - self._share_button = ba.buttonwidget( - parent=self._root_widget, - position=(self._width*0.70, self._height*0.80), - size=(220, 60), - scale=1.0, - color=green, - icon=ba.gettexture('usersButton'), - iconscale=1.5, - label=title, - on_activate_call=SettingWindow) + self._tab_row.tabs[self.TabID.MY_REPLAYS].button.delete() # deleting old tab button + + tabdefs = [(self.TabID.MY_REPLAYS, + ba.Lstr(resource=self._r + '.myReplaysText'),), + (MyTabId.SHARE_REPLAYS, "Share Replays"),] + + uiscale = ba.app.ui.uiscale + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + tab_buffer_h = 750 + 2 * x_inset + self._tab_row = TabRow( + self._root_widget, + tabdefs, + pos=((tab_buffer_h / 1.5) * 0.5, self._height - 130), + size=((self._width - tab_buffer_h)*2, 50), + on_select_call=self._set_tab) + + self._tab_row.update_appearance(self.TabID.MY_REPLAYS) + + @override(WatchWindow) + def _set_tab(self, tab_id, oldfunc=None): + self._old__set_tab(tab_id) + if self.my_tab_container: + self.my_tab_container.delete() + if tab_id == MyTabId.SHARE_REPLAYS: + + scroll_left = (self._width - self._scroll_width) * 0.5 + scroll_bottom = self._height - self._scroll_height - 79 - 48 + + c_width = self._scroll_width + c_height = self._scroll_height - 20 + sub_scroll_height = c_height - 63 + self._my_replays_scroll_width = sub_scroll_width = ( + 680 if uiscale is ba.UIScale.SMALL else 640 + ) + + self.my_tab_container = ba.containerwidget( + parent=self._root_widget, + position=(scroll_left, + scroll_bottom + (self._scroll_height - c_height) * 0.5,), + size=(c_width, c_height), + background=False, + selection_loops_to_parent=True, + ) + + ShareTabUi(self.my_tab_container) # ba_meta export plugin class Loup(ba.Plugin): def on_app_running(self): - ww.__init__ = new_init + WatchWindow.__init__ = ShareTab.__init__ def has_settings_ui(self): return True def show_settings_ui(self, button): - SettingWindow() + Print("Open share replay tab in replay window to share your replays",color=blue) From ec116b3506834cc38d0b67ad44e2dd6504b3d3ed Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Tue, 20 Dec 2022 11:14:11 +0000 Subject: [PATCH 07/82] [ci] auto-format --- plugins/utilities/share_replay.py | 294 +++++++++++++++--------------- 1 file changed, 147 insertions(+), 147 deletions(-) diff --git a/plugins/utilities/share_replay.py b/plugins/utilities/share_replay.py index f442dcd..cbf94bf 100644 --- a/plugins/utilities/share_replay.py +++ b/plugins/utilities/share_replay.py @@ -18,7 +18,7 @@ from typing import TYPE_CHECKING, cast if TYPE_CHECKING: from typing import Any, Sequence, Callable, List, Dict, Tuple, Optional, Union -from os import listdir, mkdir, path, sep,remove +from os import listdir, mkdir, path, sep, remove from shutil import copy, copytree import ba @@ -44,6 +44,7 @@ blue_highlight = (0.4, 0.7, 1) b_color = (0.6, 0.53, 0.63) b_textcolor = (0.75, 0.7, 0.8) + def Print(*args, color=None, top=None): out = "" for arg in args: @@ -65,7 +66,6 @@ if not path.exists(external_dir): Print("You are ready to share replays", color=pink) - def override(cls: ClassType) -> Callable[[MethodType], MethodType]: def decorator(newfunc: MethodType) -> MethodType: funcname = newfunc.__code__.co_name @@ -97,32 +97,33 @@ class CommonUtilities: copy(external_dir+sep+i, internal_dir+sep+i) Print("Synced all replays", color=pink) - def _copy(self, selected_replay,tab_id): + def _copy(self, selected_replay, tab_id): if selected_replay is None: Print("Select a replay", color=red) return - elif tab_id==MyTabId.INTERNAL: + elif tab_id == MyTabId.INTERNAL: copy(internal_dir+selected_replay, external_dir+selected_replay) Print(selected_replay[0:-4]+" exported", top=True, color=pink) - else: + else: copy(external_dir+selected_replay, internal_dir+selected_replay) Print(selected_replay[0:-4]+" imported", top=True, color=green) - - def delete_replay(self,selected_replay,tab_id,cls_inst): + + def delete_replay(self, selected_replay, tab_id, cls_inst): if selected_replay is None: Print("Select a replay", color=red) - return + return + def do_it(): - if tab_id==MyTabId.INTERNAL: - remove(internal_dir+selected_replay) - elif tab_id==MyTabId.EXTERNAL: - remove(external_dir+selected_replay) - cls_inst.on_tab_select(tab_id) #updating the tab + if tab_id == MyTabId.INTERNAL: + remove(internal_dir+selected_replay) + elif tab_id == MyTabId.EXTERNAL: + remove(external_dir+selected_replay) + cls_inst.on_tab_select(tab_id) # updating the tab Print(selected_replay[0:-4]+" was deleted", top=True, color=red) ConfirmWindow(text=f"Delete \"{selected_replay.split('.')[0]}\" \nfrom {'internal directory' if tab_id==MyTabId.INTERNAL else 'external directory'}?", - action=do_it, cancel_is_selected=True) - - + action=do_it, cancel_is_selected=True) + + CommonUtils = CommonUtilities() @@ -131,15 +132,16 @@ class MyTabId(Enum): EXTERNAL = "external" SHARE_REPLAYS = "share_replay" + class Help(PopupWindow): def __init__(self): self.width = 1200 - self.height = 250 + self.height = 250 self.root_widget = ba.Window(ba.containerwidget( - size=(self.width, self.height), on_outside_click_call=self.close, transition="in_right")).get_root_widget() + size=(self.width, self.height), on_outside_click_call=self.close, transition="in_right")).get_root_widget() ba.containerwidget(edit=self.root_widget, on_outside_click_call=self.close) - ba.textwidget(parent=self.root_widget, position=(0, self.height * 0.7),corner_scale=1.2 ,color=green, + ba.textwidget(parent=self.root_widget, position=(0, self.height * 0.7), corner_scale=1.2, color=green, text=f"»Replays are exported to\n {external_dir}\n»Copy replays to the above folder to be able to import them into the game\n»I would love to hear from you,meet me on discord\n -LoupGarou(author)") def close(self): @@ -158,9 +160,8 @@ class ShareTabUi(WatchWindow): else: self.root = root_widget - + self.draw_ui() - def on_select_text(self, widget, name): existing_widgets = self.scroll2.get_children() @@ -173,22 +174,22 @@ class ShareTabUi(WatchWindow): self.selected_replay = None self.tab_id = tab_id t_scale = 1.6 - + if tab_id == MyTabId.INTERNAL: dir_list = listdir(internal_dir) ba.buttonwidget(edit=self.share_button, label="Export\nReplay") - else: + else: dir_list = listdir(external_dir) ba.buttonwidget(edit=self.share_button, label="Import\nReplay") - + self.tab_row.update_appearance(tab_id) dir_list = sorted(dir_list) existing_widgets = self.scroll2.get_children() - if existing_widgets:# deleting textwidgets from old tab + if existing_widgets: # deleting textwidgets from old tab for i in existing_widgets: i.delete() - height = 900 - for i in dir_list:# making textwidgets for all replays + height = 900 + for i in dir_list: # making textwidgets for all replays height -= 50 a = i i = ba.textwidget( @@ -202,128 +203,127 @@ class ShareTabUi(WatchWindow): click_activate=True, always_highlight=True,) ba.textwidget(edit=i, on_activate_call=ba.Call(self.on_select_text, i, a)) - - def draw_ui(self): - self._r = 'watchWindow' - x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 - scroll_buffer_h = 130 + 2 * x_inset - self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 - self._height = ( - 578 - if uiscale is ba.UIScale.SMALL - else 670 - if uiscale is ba.UIScale.MEDIUM - else 800) - self._scroll_width = self._width - scroll_buffer_h - self._scroll_height = self._height - 180 - # - c_width = self._scroll_width - c_height = self._scroll_height - 20 - sub_scroll_height = c_height - 63 - self._my_replays_scroll_width = sub_scroll_width = ( - 680 if uiscale is ba.UIScale.SMALL else 640 - ) - v = c_height - 30 - b_width = 140 if uiscale is ba.UIScale.SMALL else 178 - b_height = ( - 107 - if uiscale is ba.UIScale.SMALL - else 142 - if uiscale is ba.UIScale.MEDIUM - else 190 - ) - b_space_extra = ( - 0 - if uiscale is ba.UIScale.SMALL - else -2 - if uiscale is ba.UIScale.MEDIUM - else -5 - ) + def draw_ui(self): + self._r = 'watchWindow' + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + scroll_buffer_h = 130 + 2 * x_inset + self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 + self._height = ( + 578 + if uiscale is ba.UIScale.SMALL + else 670 + if uiscale is ba.UIScale.MEDIUM + else 800) + self._scroll_width = self._width - scroll_buffer_h + self._scroll_height = self._height - 180 + # + c_width = self._scroll_width + c_height = self._scroll_height - 20 + sub_scroll_height = c_height - 63 + self._my_replays_scroll_width = sub_scroll_width = ( + 680 if uiscale is ba.UIScale.SMALL else 640 + ) - b_color = (0.6, 0.53, 0.63) - b_textcolor = (0.75, 0.7, 0.8) - btnv = (c_height- (48 - if uiscale is ba.UIScale.SMALL - else 45 - if uiscale is ba.UIScale.MEDIUM - else 40) - b_height) - btnh = 40 if uiscale is ba.UIScale.SMALL else 40 - smlh = 190 if uiscale is ba.UIScale.SMALL else 225 - tscl = 1.0 if uiscale is ba.UIScale.SMALL else 1.2 - - stab_width=500 - stab_height=300 - stab_h=smlh - - v -= sub_scroll_height + 23 - scroll = ba.scrollwidget( - parent=self.root, - position=(smlh, v), - size=(sub_scroll_width, sub_scroll_height), - ) - - self.scroll2 = ba.columnwidget(parent=scroll, - size=(sub_scroll_width, sub_scroll_height)) - - tabdefs = [(MyTabId.INTERNAL, 'INTERNAL'), (MyTabId.EXTERNAL, "EXTERNAL")] - self.tab_row = TabRow(self.root, tabdefs, pos=(stab_h,sub_scroll_height), - size=(stab_width,stab_height), on_select_call=self.on_tab_select) - - helpbtn_space=20 - helpbtn_v=stab_h+stab_width+helpbtn_space+120 - helpbtn_h=sub_scroll_height+helpbtn_space - - ba.buttonwidget( - parent=self.root, - position=(helpbtn_v ,helpbtn_h ), - size=(35, 35), - button_type="square", - label="?", - text_scale=1.5, - color=b_color, - textcolor=b_textcolor, - on_activate_call=Help) - - call_copy=lambda:CommonUtils._copy(self.selected_replay,self.tab_id) - self.share_button = ba.buttonwidget( - parent=self.root, - size=(b_width, b_height), - position=(btnh, btnv), - button_type="square", - label="Export\nReplay", - text_scale=tscl, - color=b_color, - textcolor=b_textcolor, - on_activate_call=call_copy) - - btnv -= b_height + b_space_extra - sync_button = ba.buttonwidget( - parent=self.root, - size=(b_width, b_height), - position=(btnh, btnv), - button_type="square", - label="Sync\nReplay", - text_scale=tscl, - color=b_color, - textcolor=b_textcolor, - on_activate_call=CommonUtils.sync_confirmation) - - btnv -= b_height + b_space_extra - call_delete = lambda:CommonUtils.delete_replay(self.selected_replay,self.tab_id,self) - delete_replay_button = ba.buttonwidget( - parent=self.root, - size=(b_width, b_height), - position=(btnh, btnv), - button_type="square", - label=ba.Lstr(resource=self._r + '.deleteReplayButtonText'), - text_scale=tscl, - color=b_color, - textcolor=b_textcolor, - on_activate_call=call_delete) + v = c_height - 30 + b_width = 140 if uiscale is ba.UIScale.SMALL else 178 + b_height = ( + 107 + if uiscale is ba.UIScale.SMALL + else 142 + if uiscale is ba.UIScale.MEDIUM + else 190 + ) + b_space_extra = ( + 0 + if uiscale is ba.UIScale.SMALL + else -2 + if uiscale is ba.UIScale.MEDIUM + else -5 + ) - - self.on_tab_select(MyTabId.INTERNAL) + b_color = (0.6, 0.53, 0.63) + b_textcolor = (0.75, 0.7, 0.8) + btnv = (c_height - (48 + if uiscale is ba.UIScale.SMALL + else 45 + if uiscale is ba.UIScale.MEDIUM + else 40) - b_height) + btnh = 40 if uiscale is ba.UIScale.SMALL else 40 + smlh = 190 if uiscale is ba.UIScale.SMALL else 225 + tscl = 1.0 if uiscale is ba.UIScale.SMALL else 1.2 + + stab_width = 500 + stab_height = 300 + stab_h = smlh + + v -= sub_scroll_height + 23 + scroll = ba.scrollwidget( + parent=self.root, + position=(smlh, v), + size=(sub_scroll_width, sub_scroll_height), + ) + + self.scroll2 = ba.columnwidget(parent=scroll, + size=(sub_scroll_width, sub_scroll_height)) + + tabdefs = [(MyTabId.INTERNAL, 'INTERNAL'), (MyTabId.EXTERNAL, "EXTERNAL")] + self.tab_row = TabRow(self.root, tabdefs, pos=(stab_h, sub_scroll_height), + size=(stab_width, stab_height), on_select_call=self.on_tab_select) + + helpbtn_space = 20 + helpbtn_v = stab_h+stab_width+helpbtn_space+120 + helpbtn_h = sub_scroll_height+helpbtn_space + + ba.buttonwidget( + parent=self.root, + position=(helpbtn_v, helpbtn_h), + size=(35, 35), + button_type="square", + label="?", + text_scale=1.5, + color=b_color, + textcolor=b_textcolor, + on_activate_call=Help) + + def call_copy(): return CommonUtils._copy(self.selected_replay, self.tab_id) + self.share_button = ba.buttonwidget( + parent=self.root, + size=(b_width, b_height), + position=(btnh, btnv), + button_type="square", + label="Export\nReplay", + text_scale=tscl, + color=b_color, + textcolor=b_textcolor, + on_activate_call=call_copy) + + btnv -= b_height + b_space_extra + sync_button = ba.buttonwidget( + parent=self.root, + size=(b_width, b_height), + position=(btnh, btnv), + button_type="square", + label="Sync\nReplay", + text_scale=tscl, + color=b_color, + textcolor=b_textcolor, + on_activate_call=CommonUtils.sync_confirmation) + + btnv -= b_height + b_space_extra + def call_delete(): return CommonUtils.delete_replay(self.selected_replay, self.tab_id, self) + delete_replay_button = ba.buttonwidget( + parent=self.root, + size=(b_width, b_height), + position=(btnh, btnv), + button_type="square", + label=ba.Lstr(resource=self._r + '.deleteReplayButtonText'), + text_scale=tscl, + color=b_color, + textcolor=b_textcolor, + on_activate_call=call_delete) + + self.on_tab_select(MyTabId.INTERNAL) def close(self): ba.playsound(ba.getsound('swish')) @@ -403,4 +403,4 @@ class Loup(ba.Plugin): return True def show_settings_ui(self, button): - Print("Open share replay tab in replay window to share your replays",color=blue) + Print("Open share replay tab in replay window to share your replays", color=blue) From 7833b30cf0c42d082698666be518cddde8965e26 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Tue, 20 Dec 2022 11:14:12 +0000 Subject: [PATCH 08/82] [ci] apply-version-metadata --- plugins/utilities.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d134e88..3eea4a5 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -14,7 +14,12 @@ } ], "versions": { - "1.3.0": null, + "1.3.0": { + "api_version": 7, + "commit_sha": "ec116b3", + "released_on": "20-12-2022", + "md5sum": "dbb9d85a5fb0041631dc12765a257fce" + }, "1.2.1": { "api_version": 7, "commit_sha": "7753b87", @@ -586,4 +591,4 @@ } } } -} +} \ No newline at end of file From f213f2429bcf1ed5380fa4da4f87736750485878 Mon Sep 17 00:00:00 2001 From: * Date: Tue, 27 Dec 2022 03:46:21 +0530 Subject: [PATCH 09/82] added random join plugin --- plugins/utilities.json | 17 +- plugins/utilities/random_join.py | 313 +++++++++++++++++++++++++++++++ 2 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 plugins/utilities/random_join.py diff --git a/plugins/utilities.json b/plugins/utilities.json index 3eea4a5..cb5357f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -3,6 +3,21 @@ "description": "Utilities", "plugins_base_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/utilities", "plugins": { + "random_join": { + "description": "Come visit the unknown servers around all the world! Plugin designed not to join servers with similar names more frequently than rare ones. Have fun!", + "external_url": "", + "authors": [ + {"name": "maxick", + "email": "", + "discord": "maxick#9227"}, + {"name": "LoupGarou", + "email": "LoupGarou5418@outlook.com", + "discord": "ʟօʊքɢǟʀօʊ#3063"} + ], + "versions": { + "1.0.0": null + } + }, "share_replay": { "description": "Export replays to mods folder and share them with friends or have a backup", "external_url": "", @@ -591,4 +606,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/random_join.py b/plugins/utilities/random_join.py new file mode 100644 index 0000000..01eb704 --- /dev/null +++ b/plugins/utilities/random_join.py @@ -0,0 +1,313 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, TypeVar + +import _ba +import ba +import ba.internal +import random +from bastd.ui.gather.publictab import PublicGatherTab, PartyEntry,PingThread +if TYPE_CHECKING: + from typing import Callable + +ClassType = TypeVar('ClassType') +MethodType = TypeVar('Methodtype') + + +def override(cls: ClassType) -> Callable[[MethodType], MethodType]: + def decorator(newfunc: MethodType) -> MethodType: + funcname = newfunc.__code__.co_name + if hasattr(cls, funcname): + oldfunc = getattr(cls, funcname) + setattr(cls, f'_old_{funcname}', oldfunc) + + setattr(cls, funcname, newfunc) + return newfunc + + return decorator + +# Can this stuff break mro? (P.S. yes, so we're not using super() anymore). +# Although it gives nice auto-completion. +# And anyways, why not just GatherPublicTab = NewGatherPublicTab? +# But hmm, if we imagine someone used `from blah.blah import Blah`, using +# `blah.Blah = NewBlah` AFTERWARDS would be meaningless. +class NewPublicGatherTab(PublicGatherTab,PingThread): + + @override(PublicGatherTab) + def _build_join_tab(self, region_width: float, + region_height: float, + oldfunc: Callable = None) -> None: + # noinspection PyUnresolvedReferences + self._old__build_join_tab(region_width, region_height) + + # Copy-pasted from original function. + c_width = region_width + c_height = region_height - 20 + sub_scroll_height = c_height - 125 + sub_scroll_width = 830 + v = c_height - 35 + v -= 60 + + self._random_join_button = ba.buttonwidget( + parent=self._container, + label='random', + size=(90, 45), + position=(710, v + 10), + on_activate_call=ba.WeakCall(self._join_random_server), + ) + ba.widget(edit=self._random_join_button, up_widget=self._host_text, + left_widget=self._filter_text) + + # We could place it somewhere under plugin settings which is kind of + # official way to customise plugins. Although it's too deep: + # Gather Window -> Main Menu -> Settings -> Advanced -(scroll)-> + # Plugins -(scroll probably)-> RandomJoin Settings. + self._random_join_settings_button = ba.buttonwidget( + parent=self._container, + icon=ba.gettexture('settingsIcon'), + size=(40, 40), + position=(820, v + 13), + on_activate_call=ba.WeakCall(self._show_random_join_settings), + ) + + @override(PublicGatherTab) + def _show_random_join_settings(self) -> None: + RandomJoinSettingsPopup( + origin_widget=self._random_join_settings_button) + + @override(PublicGatherTab) + def _get_parties_list(self) -> list[PartyEntry]: + if (self._parties_sorted and + (randomjoin.maximum_ping == 9999 or + # Ensure that we've pinged at least 10%. + len([p for k, p in self._parties_sorted + if p.ping is not None]) > len(self._parties_sorted) / 10)): + randomjoin.cached_parties = [p for k, p in self._parties_sorted] + return randomjoin.cached_parties + + @override(PublicGatherTab) + def _join_random_server(self) -> None: + name_prefixes = set() + parties = [p for p in self._get_parties_list() if + (p.size >= randomjoin.minimum_players + and p.size < p.size_max and (randomjoin.maximum_ping == 9999 + or (p.ping is not None + and p.ping <= randomjoin.maximum_ping)))] + + if not parties: + ba.screenmessage('No suitable servers found; wait', + color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) + return + + for party in parties: + name_prefixes.add(party.name[:6]) + + random.choice(list(name_prefixes)) + + party = random.choice( + [p for p in parties if p.name[:6] in name_prefixes]) + + ba.internal.connect_to_party(party.address, party.port) + + +class RandomJoinSettingsPopup(ba.Window): + def __init__(self, origin_widget: ba.Widget) -> None: + c_width = 600 + c_height = 400 + uiscale = ba.app.ui.uiscale + super().__init__(root_widget=ba.containerwidget( + scale=( + 1.8 + if uiscale is ba.UIScale.SMALL + else 1.55 + if uiscale is ba.UIScale.MEDIUM + else 1.0 + ), + scale_origin_stack_offset=origin_widget.get_screen_space_center(), + stack_offset=(0, -10) + if uiscale is ba.UIScale.SMALL + else (0, 15) + if uiscale is ba.UIScale.MEDIUM + else (0, 0), + size=(c_width, c_height), + transition='in_scale', + )) + + ba.textwidget( + parent=self._root_widget, + size=(0, 0), + h_align='center', + v_align='center', + text='Random Join Settings', + scale=1.5, + color=(0.6, 1.0, 0.6), + maxwidth=c_width * 0.8, + position=(c_width * 0.5, c_height - 60), + ) + + v = c_height - 120 + ba.textwidget( + parent=self._root_widget, + size=(0, 0), + h_align='right', + v_align='center', + text='Maximum ping', + maxwidth=c_width * 0.3, + position=(c_width * 0.4, v), + ) + self._maximum_ping_edit = ba.textwidget( + parent=self._root_widget, + size=(c_width * 0.3, 40), + h_align='left', + v_align='center', + text=str(randomjoin.maximum_ping), + editable=True, + description='Maximum ping (ms)', + position=(c_width * 0.6, v - 20), + autoselect=True, + max_chars=4, + ) + v -= 60 + ba.textwidget( + parent=self._root_widget, + size=(0, 0), + h_align='right', + v_align='center', + text='Minimum players', + maxwidth=c_width * 0.3, + position=(c_width * 0.4, v), + ) + self._minimum_players_edit = ba.textwidget( + parent=self._root_widget, + size=(c_width * 0.3, 40), + h_align='left', + v_align='center', + text=str(randomjoin.minimum_players), + editable=True, + description='Minimum number of players', + position=(c_width * 0.6, v - 20), + autoselect=True, + max_chars=4, + ) + v -= 60 + + # Cancel button. + self.cancel_button = btn = ba.buttonwidget( + parent=self._root_widget, + label=ba.Lstr(resource='cancelText'), + size=(180, 60), + color=(1.0, 0.2, 0.2), + position=(40, 30), + on_activate_call=self._cancel, + autoselect=True, + ) + ba.containerwidget(edit=self._root_widget, cancel_button=btn) + + # Save button. + self.savebtn = btn = ba.buttonwidget( + parent=self._root_widget, + label=ba.Lstr(resource='saveText'), + size=(180, 60), + position=(c_width - 200, 30), + on_activate_call=self._save, + autoselect=True, + ) + ba.containerwidget(edit=self._root_widget, start_button=btn) + + def _save(self) -> None: + errored = False + minimum_players: int | None = None + maximum_ping: int | None = None + try: + minimum_players = int( + ba.textwidget(query=self._minimum_players_edit)) + except ValueError: + ba.screenmessage('"Minimum players" should be integer', + color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) + errored = True + try: + maximum_ping = int( + ba.textwidget(query=self._maximum_ping_edit)) + except ValueError: + ba.screenmessage('"Maximum ping" should be integer', + color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) + errored = True + if errored: + return + + assert minimum_players is not None + assert maximum_ping is not None + + if minimum_players < 0: + ba.screenmessage('"Minimum players" should be at least 0', + color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) + errored = True + + if maximum_ping <= 0: + ba.screenmessage('"Maximum ping" should be greater than 0', + color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) + ba.screenmessage('(use 9999 as dont-care value)', + color=(1, 0, 0)) + errored = True + + if errored: + return + + randomjoin.maximum_ping = maximum_ping + randomjoin.minimum_players = minimum_players + + randomjoin.commit_config() + ba.playsound(ba.getsound('shieldUp')) + self._transition_out() + + def _cancel(self) -> None: + ba.playsound(ba.getsound('shieldDown')) + self._transition_out() + + def _transition_out(self) -> None: + ba.containerwidget(edit=self._root_widget, transition='out_scale') + + +class RandomJoin: + def __init__(self) -> None: + self.cached_parties: list[PartyEntry] = [] + self.maximum_ping: int = 9999 + self.minimum_players: int = 2 + self.load_config() + + def load_config(self) -> None: + cfg = ba.app.config.get('Random Join', { + 'maximum_ping': self.maximum_ping, + 'minimum_players': self.minimum_players, + }) + try: + self.maximum_ping = cfg['maximum_ping'] + self.minimum_players = cfg['minimum_players'] + except KeyError: + ba.screenmessage('Error: RandomJoin config is broken, resetting..', + color=(1, 0, 0), log=True) + ba.playsound(ba.getsound('error')) + self.commit_config() + + def commit_config(self) -> None: + ba.app.config['Random Join'] = { + 'maximum_ping': self.maximum_ping, + 'minimum_players': self.minimum_players, + } + ba.app.config.commit() + + +randomjoin = RandomJoin() + + +# ba_meta require api 7 +# ba_meta export ba.Plugin +class RandomJoinPlugin(ba.Plugin): + def on_app_running(self) -> None: + # I feel bad that all patching logic happens not here. + pass From 2454845a384a6220939659038a8b97effa1ccadf Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 26 Dec 2022 22:17:50 +0000 Subject: [PATCH 10/82] [ci] auto-format --- plugins/utilities/random_join.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/plugins/utilities/random_join.py b/plugins/utilities/random_join.py index 01eb704..955b1a2 100644 --- a/plugins/utilities/random_join.py +++ b/plugins/utilities/random_join.py @@ -6,7 +6,7 @@ import _ba import ba import ba.internal import random -from bastd.ui.gather.publictab import PublicGatherTab, PartyEntry,PingThread +from bastd.ui.gather.publictab import PublicGatherTab, PartyEntry, PingThread if TYPE_CHECKING: from typing import Callable @@ -31,8 +31,10 @@ def override(cls: ClassType) -> Callable[[MethodType], MethodType]: # And anyways, why not just GatherPublicTab = NewGatherPublicTab? # But hmm, if we imagine someone used `from blah.blah import Blah`, using # `blah.Blah = NewBlah` AFTERWARDS would be meaningless. -class NewPublicGatherTab(PublicGatherTab,PingThread): - + + +class NewPublicGatherTab(PublicGatherTab, PingThread): + @override(PublicGatherTab) def _build_join_tab(self, region_width: float, region_height: float, @@ -87,13 +89,13 @@ class NewPublicGatherTab(PublicGatherTab,PingThread): @override(PublicGatherTab) def _join_random_server(self) -> None: - name_prefixes = set() + name_prefixes = set() parties = [p for p in self._get_parties_list() if (p.size >= randomjoin.minimum_players and p.size < p.size_max and (randomjoin.maximum_ping == 9999 - or (p.ping is not None - and p.ping <= randomjoin.maximum_ping)))] - + or (p.ping is not None + and p.ping <= randomjoin.maximum_ping)))] + if not parties: ba.screenmessage('No suitable servers found; wait', color=(1, 0, 0)) From 09206d636ad0a58c010cbc661ddf8886da2b7442 Mon Sep 17 00:00:00 2001 From: Loup-Garou911XD Date: Mon, 26 Dec 2022 22:17:51 +0000 Subject: [PATCH 11/82] [ci] apply-version-metadata --- plugins/utilities.json | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index cb5357f..8f801af 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -7,15 +7,24 @@ "description": "Come visit the unknown servers around all the world! Plugin designed not to join servers with similar names more frequently than rare ones. Have fun!", "external_url": "", "authors": [ - {"name": "maxick", + { + "name": "maxick", "email": "", - "discord": "maxick#9227"}, - {"name": "LoupGarou", + "discord": "maxick#9227" + }, + { + "name": "LoupGarou", "email": "LoupGarou5418@outlook.com", - "discord": "ʟօʊքɢǟʀօʊ#3063"} + "discord": "ʟօʊքɢǟʀօʊ#3063" + } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "2454845", + "released_on": "26-12-2022", + "md5sum": "7bac6bfe837ff89e7da10a0ab45691d1" + } } }, "share_replay": { @@ -606,4 +615,4 @@ } } } -} +} \ No newline at end of file From 4b25b8a1a6a15025facd67e97b5cd729c5e66831 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 1 Jan 2023 20:55:13 +0100 Subject: [PATCH 12/82] Create autorun.py --- plugins/utilities/autorun.py | 254 +++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 plugins/utilities/autorun.py diff --git a/plugins/utilities/autorun.py b/plugins/utilities/autorun.py new file mode 100644 index 0000000..b920610 --- /dev/null +++ b/plugins/utilities/autorun.py @@ -0,0 +1,254 @@ +# ba_meta require api 7 + +""" + AutoRun by TheMikirog + Version 1 + + Run without holding any buttons. Made for beginners or players on mobile. + Keeps your character maneuverable. + Start running as usual to override. + + Heavily commented for easy modding learning! + + No Rights Reserved +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +# Let's import everything we need and nothing more. +import ba +import bastd +import math +from ba._generated.enums import TimeType +from bastd.actor.spaz import Spaz + +if TYPE_CHECKING: + pass + +""" + This mod is much more "technical" than my other mods. + I highly recommend checking out the code of this mod once you have a good understanding of programming. + At the very least check out my other heavily commented mods like my Hot Potato gamemode. It's pretty dank! + Normally you shouldn't flood your scripts with comments like that. + I do it here to help people like you get the basic tools required to make your own mods similar to this one. + If you write your own code, only comment what can't be easily inferred from reading the code alone. + Consider this an interactive tutorial of sorts. + + Let's start with the goal of this mod; the conception. + If you play on mobile, the only way you get to run is if you press and hold any other action button like jump or punch. + Basically, all action buttons do two things at once unless a gamemode disables one of those actions. + Playing on a gamepad or keyboard gives you the luxury of a dedicated run button, which gives you much more control + over your movement. This basically forces mobile players that are running to: + - Punch and risk being open to attacks. + - Kill all your momentum by jumping. + - Using the bomb to run, but only after using that same button to throw an already held bomb. + - Using an inconvenient out of the way grab button to avoid all of that hassle. + It's a mess. Get a gamepad. + This mod exists as an alternative to those who can't play on a gamepad, but don't want + to be inconvenienced by running quirks if they JUST WANT TO PLAY. + + The naive implementation of this would be to just running all the time, but here's the catch: + Running makes turning less tight, which is the compromise for being really fast. + If you want to have tighter turns, you'd release the run button for a split second, turn and press it again. + Much easier and more convenient to do if you're on a gamepad. + The goal of this mod is to replicate this behavior and making it automatic. + My aim is to get the player moving as fast as possible without making it significantly harder to control. + This is supposed to help mobile players, not handicap them. + I can imagine the sweet relief of not being forced to babysit an action button just for running fast. + Actually it should help gamepad users too, since holding your trigger can be exhausting + or even impossible for those with physical disabilities. + + For your information, I started writing this mod THREE times. + Each time with the goal of trying out different ways of achieving my goals. + I used the code and failures of the previous scripts to make the next one better. + What you're seeing here is the final iteration; the finished product. + Don't expect your code to look like this the first time, especially if you're trying something ballsy. + You will fail, but don't be afraid to experiment. + Only through experimentation you can forge a failure into a success. +""" + +# ba_meta export plugin +class AutoRun(ba.Plugin): + + # During my research and prototyping I figured I'd have to do some linear algebgra. + # I didn't want to use libraries, since this is supposed to be a standalone mod. + # Because of this I made certain functions from scratch that are easily accessible. + # If you are curious over the details, look these up on the Internet. + # I'll only briefly cover their purpose in the context of the mod. + + # Here's the dot product function. + # To keep it short, it returns the difference in angle between two vectors. + # We're gonna use that knowledge to check how tight our turn is. + # I'll touch on that later. + def dot(vector_a, vector_b): + return vector_a[0] * vector_b[0] + vector_a[1] * vector_b[1] + + # This clamping function will make sure a certain value won't go above or below a certain threshold. + # self.node.run attribute expects a value between 0-1, so this is one way of enforcing this. + def clamp(num, min_value, max_value): + num = max(min(num, max_value), min_value) + return num + + # A vector can be of any length, but we need them to be of length 1. + # This vector normalization function changes the magnitude of a vector without changing its direction. + def normalize(vector): + length = math.hypot(vector[0], vector[1]) # Pythagoras says hi + # Sometimes we'll get a [0,0] vector and dividing by 0 is iffy. + # Let's leave the vector unchanged if that's the case. + if length > 0: + return [vector[0] / length, vector[1] / length] + else: + return vector + + # We use a decorator to add extra code to existing code, increasing mod compatibility. + # We're gonna use decorators ALOT in this mod. + # Here I'm defining a new spaz init function that'll be replaced. + def new_init(func): + def wrapper(*args, **kwargs): + + # Here's where we execute the original game's code, so it's not lost. + # We want to add our code at the end of the existing code, so our code goes under that. + func(*args, **kwargs) + + # We define some variables that we need to keep track of. + # For future reference, if you see args[0] anywhere, that is "self" in the original function. + args[0].autorun_timer: ba.Timer | None = None + args[0].autorun_override = False + + # We wanna do our auto run calculations when the player moves their analog stick to make it responsive. + # However doing this ONLY tracks changes in analog stick position and some bugs come up because of that. + # For example moving via dpad on a gamepad can sometimes not execute the run at all. + # To keep the behavior predictable, we also want to update our auto run functionality with a periodic timer. + # We could ignore the update on analog stick movement, but then it feels terrible to play. We need both. + # Update on analog movement for responsive controls, timer to foolproof everything else. + + # To make our timer, we want to have access to our function responsible for doing the auto run logic. + # The issue is that timers only work when a function is created within the context of the game. + # Timer throws a tantrum if it references the run_update function, but NOT if that function is an intermediary. + def spaz_autorun_update(): + AutoRun.run_update(args[0]) + + # We don't want this logic to be ran on bots, only players. + # Check if we have a player assigned to that spaz. If we do, let's make our timer. + if args[0].source_player: + # And here's our timer. + # It loops indefinitely thanks to the 'repeat' argument that is set to True. + # Notice how it's the capital T Timer instead of the small letter. + # That's important, because big T returns a timer object we can manipulate. + # We need it assigned to a variable, because we have to delete it once it stops being relevant. + args[0].autorun_timer = ba.Timer(0.1, spaz_autorun_update, timetype=TimeType.SIM, repeat=True) + + return wrapper + # Let's replace the original function with our modified version. + bastd.actor.spaz.Spaz.__init__ = new_init(bastd.actor.spaz.Spaz.__init__) + + # This is the bulk of our mod. Our run_update function. + # The goal here is to change the self.node.run attribute of our character. + # This attribute handles running behavior based on how far we pushed the running trigger. + # 0 means not running and 1 means run trigger fully pressed. + # On mobile it's always 0 and 1, but on gamepad you can have values between them + # For example you can do a jog instead of a sprint. + # We activate this function periodically via a timer and every time the player moves their analog stick. + # The idea is to make it 1 when the player is running forward and make it 0 + # when the player makes the tightest turn possible. + # We also want to account for how far the analog stick is pushed. + def run_update(self) -> None: + # Let's not run this code if our character does not exist or the player decides to run "manually". + if not self.node or self.autorun_override: + return + + # Let's read our player's analog stick. + # Notice how the vertical direction is inverted (there's a minus in front of the variable). + # We want the directions to corespond to the game world. + vertical = -self.node.move_up_down + horizontal = self.node.move_left_right + movement_vector = [horizontal, vertical] + + # Get our character's facing direction + facing_direction = (self.node.position[0] - self.node.position_forward[0], + self.node.position[2] - self.node.position_forward[2]) + # We want our character's facing direction to be a normalized vector (magnitude of 1). + facing_direction = AutoRun.normalize(facing_direction) + + # We don't want to run our code if the player has their analog stick in a neutral position. + if movement_vector == [0.0, 0.0]: + return + + # Get the difference between our current facing direction and where we plan on moving towards. + # Check the dot function higher up in the script for details. + dot = AutoRun.dot(facing_direction, AutoRun.normalize(movement_vector)) + if dot > 0.0: + # Our dot value ranges from -1 to 1. + # We want it from 0 to 1. + # 0 being 180 degree turn, 1 being running exactly straight. + dot = (dot + 1) / 2 + + # Let's read how far our player pushed his stick. 1 being full tilt, 0 being neutral. + run_power = math.hypot(movement_vector[0], movement_vector[1]) # Heres our homie Pythagoras once again + + # I noticed the player starts running too fast if the stick is pushed half-way. + # I changed the linear scale to be exponential. + # easings.net is a great website that shows you different ways of converting a linear curve to some other kind. + # Here I used the EaseInQuad easing, which is just raising the value to the power of 2. + # This should make half-way pushes less severe. + run_power = pow(run_power, 2) + + # Just in case let's clamp our value from 0 to 1. + run_power = AutoRun.clamp(run_power, 0.0, 1.0) + + # Here we combine our dot result with how far we pushed our stick to get the final running value. + # Clamping from 0 to 1 for good measure. + self.node.run = AutoRun.clamp(run_power * dot, 0.0, 1.0) + + # This function is called every time we want to run or touch a running trigger. + # We have our auto run stuff, but we also want for our mod to play nice with the current running behavior. + # We also want this to work with my Quickturn mod. + def new_onrun(func): + def wrapper(*args, **kwargs): + # When we hold an action button or press our running trigger at any point, our mod should stop interfering. + # This won't work if your gamepad has borked triggers though. + args[0].autorun_override = args[1] + # Here's our original unchanged function + func(*args, **kwargs) + return wrapper + # We replace the character running function with our modified version. + bastd.actor.spaz.Spaz.on_run = new_onrun(bastd.actor.spaz.Spaz.on_run) + + # There's two function that are called when our player pushes the analog stick - two for each axis. + # Here's for the vertical axis. + def new_updown(func): + def wrapper(*args, **kwargs): + # Original function + func(*args, **kwargs) + # If we're not holding the run button and we're a player, run our auto run behavior. + if not args[0].autorun_override and args[0].source_player: + AutoRun.run_update(args[0]) + return wrapper + # You get the idea. + bastd.actor.spaz.Spaz.on_move_up_down = new_updown(bastd.actor.spaz.Spaz.on_move_up_down) + + # Let's do the same for our horizontal axis. + # Second verse same as the first. + def new_leftright(func): + def wrapper(*args, **kwargs): + func(*args, **kwargs) + if not args[0].autorun_override and args[0].source_player: + AutoRun.run_update(args[0]) + return wrapper + bastd.actor.spaz.Spaz.on_move_left_right = new_leftright(bastd.actor.spaz.Spaz.on_move_left_right) + + # There's one downside to the looping timer - it runs constantly even if the player is dead. + # We don't want to waste computational power on something like that. + # Let's kill our timer when the player dies. + def new_handlemessage(func): + def wrapper(*args, **kwargs): + # Only react to the death message. + if isinstance(args[1], ba.DieMessage): + # Kill the timer. + args[0].autorun_timer = None + # Original function. + func(*args, **kwargs) + return wrapper + bastd.actor.spaz.Spaz.handlemessage = new_handlemessage(bastd.actor.spaz.Spaz.handlemessage) From 5e0280df5b611fa9dec95840abe49da98fdfb6b4 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 1 Jan 2023 21:02:14 +0100 Subject: [PATCH 13/82] Update utilities.json --- plugins/utilities.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8f801af..7951c69 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -614,5 +614,19 @@ } } } + "autorun": { + "description": "Run without holding any buttons. Made for beginners or players on mobile.\nKeeps your character maneuverable. Start running as usual to override.", + "external_url": "", + "authors": [ + { + "name": "TheMikirog", + "email": "", + "discord": "TheMikirog#1984" + } + ], + "versions": { + "1.0.0": null + } + } } } \ No newline at end of file From 23314581cc60d17a18a2d3712451606225474595 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Sun, 1 Jan 2023 20:03:15 +0000 Subject: [PATCH 14/82] [ci] auto-format --- plugins/utilities/autorun.py | 57 ++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/plugins/utilities/autorun.py b/plugins/utilities/autorun.py index b920610..263b1b4 100644 --- a/plugins/utilities/autorun.py +++ b/plugins/utilities/autorun.py @@ -26,7 +26,7 @@ from bastd.actor.spaz import Spaz if TYPE_CHECKING: pass - + """ This mod is much more "technical" than my other mods. I highly recommend checking out the code of this mod once you have a good understanding of programming. @@ -70,6 +70,8 @@ if TYPE_CHECKING: """ # ba_meta export plugin + + class AutoRun(ba.Plugin): # During my research and prototyping I figured I'd have to do some linear algebgra. @@ -77,7 +79,7 @@ class AutoRun(ba.Plugin): # Because of this I made certain functions from scratch that are easily accessible. # If you are curious over the details, look these up on the Internet. # I'll only briefly cover their purpose in the context of the mod. - + # Here's the dot product function. # To keep it short, it returns the difference in angle between two vectors. # We're gonna use that knowledge to check how tight our turn is. @@ -90,11 +92,11 @@ class AutoRun(ba.Plugin): def clamp(num, min_value, max_value): num = max(min(num, max_value), min_value) return num - + # A vector can be of any length, but we need them to be of length 1. # This vector normalization function changes the magnitude of a vector without changing its direction. def normalize(vector): - length = math.hypot(vector[0], vector[1]) # Pythagoras says hi + length = math.hypot(vector[0], vector[1]) # Pythagoras says hi # Sometimes we'll get a [0,0] vector and dividing by 0 is iffy. # Let's leave the vector unchanged if that's the case. if length > 0: @@ -107,29 +109,29 @@ class AutoRun(ba.Plugin): # Here I'm defining a new spaz init function that'll be replaced. def new_init(func): def wrapper(*args, **kwargs): - + # Here's where we execute the original game's code, so it's not lost. # We want to add our code at the end of the existing code, so our code goes under that. func(*args, **kwargs) - + # We define some variables that we need to keep track of. # For future reference, if you see args[0] anywhere, that is "self" in the original function. args[0].autorun_timer: ba.Timer | None = None args[0].autorun_override = False - + # We wanna do our auto run calculations when the player moves their analog stick to make it responsive. # However doing this ONLY tracks changes in analog stick position and some bugs come up because of that. # For example moving via dpad on a gamepad can sometimes not execute the run at all. # To keep the behavior predictable, we also want to update our auto run functionality with a periodic timer. # We could ignore the update on analog stick movement, but then it feels terrible to play. We need both. # Update on analog movement for responsive controls, timer to foolproof everything else. - + # To make our timer, we want to have access to our function responsible for doing the auto run logic. # The issue is that timers only work when a function is created within the context of the game. # Timer throws a tantrum if it references the run_update function, but NOT if that function is an intermediary. def spaz_autorun_update(): AutoRun.run_update(args[0]) - + # We don't want this logic to be ran on bots, only players. # Check if we have a player assigned to that spaz. If we do, let's make our timer. if args[0].source_player: @@ -138,8 +140,9 @@ class AutoRun(ba.Plugin): # Notice how it's the capital T Timer instead of the small letter. # That's important, because big T returns a timer object we can manipulate. # We need it assigned to a variable, because we have to delete it once it stops being relevant. - args[0].autorun_timer = ba.Timer(0.1, spaz_autorun_update, timetype=TimeType.SIM, repeat=True) - + args[0].autorun_timer = ba.Timer( + 0.1, spaz_autorun_update, timetype=TimeType.SIM, repeat=True) + return wrapper # Let's replace the original function with our modified version. bastd.actor.spaz.Spaz.__init__ = new_init(bastd.actor.spaz.Spaz.__init__) @@ -151,31 +154,31 @@ class AutoRun(ba.Plugin): # On mobile it's always 0 and 1, but on gamepad you can have values between them # For example you can do a jog instead of a sprint. # We activate this function periodically via a timer and every time the player moves their analog stick. - # The idea is to make it 1 when the player is running forward and make it 0 + # The idea is to make it 1 when the player is running forward and make it 0 # when the player makes the tightest turn possible. # We also want to account for how far the analog stick is pushed. def run_update(self) -> None: # Let's not run this code if our character does not exist or the player decides to run "manually". if not self.node or self.autorun_override: return - + # Let's read our player's analog stick. # Notice how the vertical direction is inverted (there's a minus in front of the variable). # We want the directions to corespond to the game world. vertical = -self.node.move_up_down horizontal = self.node.move_left_right movement_vector = [horizontal, vertical] - + # Get our character's facing direction - facing_direction = (self.node.position[0] - self.node.position_forward[0], + facing_direction = (self.node.position[0] - self.node.position_forward[0], self.node.position[2] - self.node.position_forward[2]) # We want our character's facing direction to be a normalized vector (magnitude of 1). facing_direction = AutoRun.normalize(facing_direction) - + # We don't want to run our code if the player has their analog stick in a neutral position. if movement_vector == [0.0, 0.0]: return - + # Get the difference between our current facing direction and where we plan on moving towards. # Check the dot function higher up in the script for details. dot = AutoRun.dot(facing_direction, AutoRun.normalize(movement_vector)) @@ -184,20 +187,21 @@ class AutoRun(ba.Plugin): # We want it from 0 to 1. # 0 being 180 degree turn, 1 being running exactly straight. dot = (dot + 1) / 2 - + # Let's read how far our player pushed his stick. 1 being full tilt, 0 being neutral. - run_power = math.hypot(movement_vector[0], movement_vector[1]) # Heres our homie Pythagoras once again - + # Heres our homie Pythagoras once again + run_power = math.hypot(movement_vector[0], movement_vector[1]) + # I noticed the player starts running too fast if the stick is pushed half-way. # I changed the linear scale to be exponential. # easings.net is a great website that shows you different ways of converting a linear curve to some other kind. # Here I used the EaseInQuad easing, which is just raising the value to the power of 2. # This should make half-way pushes less severe. run_power = pow(run_power, 2) - + # Just in case let's clamp our value from 0 to 1. run_power = AutoRun.clamp(run_power, 0.0, 1.0) - + # Here we combine our dot result with how far we pushed our stick to get the final running value. # Clamping from 0 to 1 for good measure. self.node.run = AutoRun.clamp(run_power * dot, 0.0, 1.0) @@ -215,7 +219,7 @@ class AutoRun(ba.Plugin): return wrapper # We replace the character running function with our modified version. bastd.actor.spaz.Spaz.on_run = new_onrun(bastd.actor.spaz.Spaz.on_run) - + # There's two function that are called when our player pushes the analog stick - two for each axis. # Here's for the vertical axis. def new_updown(func): @@ -228,7 +232,7 @@ class AutoRun(ba.Plugin): return wrapper # You get the idea. bastd.actor.spaz.Spaz.on_move_up_down = new_updown(bastd.actor.spaz.Spaz.on_move_up_down) - + # Let's do the same for our horizontal axis. # Second verse same as the first. def new_leftright(func): @@ -237,8 +241,9 @@ class AutoRun(ba.Plugin): if not args[0].autorun_override and args[0].source_player: AutoRun.run_update(args[0]) return wrapper - bastd.actor.spaz.Spaz.on_move_left_right = new_leftright(bastd.actor.spaz.Spaz.on_move_left_right) - + bastd.actor.spaz.Spaz.on_move_left_right = new_leftright( + bastd.actor.spaz.Spaz.on_move_left_right) + # There's one downside to the looping timer - it runs constantly even if the player is dead. # We don't want to waste computational power on something like that. # Let's kill our timer when the player dies. From cb2d9525c8796b99175f88f8ec65a1c0dc88602b Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 2 Jan 2023 02:55:48 +0530 Subject: [PATCH 15/82] Add a missing comma --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 7951c69..281fdfb 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -613,7 +613,7 @@ "md5sum": "a04c30c11a43443fe192fe70ad528f22" } } - } + }, "autorun": { "description": "Run without holding any buttons. Made for beginners or players on mobile.\nKeeps your character maneuverable. Start running as usual to override.", "external_url": "", From 3c0066e8ec48ce1dfb7746877df8985e6dd8c812 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 1 Jan 2023 21:26:30 +0000 Subject: [PATCH 16/82] [ci] apply-version-metadata --- plugins/utilities.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 281fdfb..a16085d 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -625,7 +625,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "cb2d952", + "released_on": "01-01-2023", + "md5sum": "22f54996dc55008267d09bf48a2cffe3" + } } } } From 5bcacf251a65049fbdd88818024ebbafa4c7a84b Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Wed, 4 Jan 2023 22:22:37 +0100 Subject: [PATCH 17/82] Update utilities.json --- plugins/utilities.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index a16085d..3b525ae 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -632,6 +632,20 @@ "md5sum": "22f54996dc55008267d09bf48a2cffe3" } } + }, + "tnt_respawn_text": { + "description": "Shows when a TNT box is about to respawn with non-intrusive text.", + "external_url": "", + "authors": [ + { + "name": "TheMikirog", + "email": "", + "discord": "TheMikirog#1984" + } + ], + "versions": { + "1.0.0": null + } } } -} \ No newline at end of file +} From 101b95175af5c8be1f55e128d14fec56b9ebffb4 Mon Sep 17 00:00:00 2001 From: TheMikirog Date: Wed, 4 Jan 2023 22:23:08 +0100 Subject: [PATCH 18/82] Create tnt_respawn_text --- plugins/utilities/tnt_respawn_text | 212 +++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 plugins/utilities/tnt_respawn_text diff --git a/plugins/utilities/tnt_respawn_text b/plugins/utilities/tnt_respawn_text new file mode 100644 index 0000000..bbcdc99 --- /dev/null +++ b/plugins/utilities/tnt_respawn_text @@ -0,0 +1,212 @@ +# ba_meta require api 7 + +""" + TNT Respawn Text by TheMikirog + Version 1 + + Shows when a TNT box is about to respawn with non-intrusive text. + + Heavily commented for easy modding learning! + + No Rights Reserved +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +# Let's import everything we need and nothing more. +import ba +import bastd +import math +import random +from bastd.actor.bomb import Bomb + +if TYPE_CHECKING: + pass + +""" + Turns out TNT respawning got changed during the 1.5 update. + At first I planned to make an accurate timer text that just counts down seconds to respawn. + However, to prevent timer stacking, Eric decided to update the timer every 1.1s seconds instead of the standard 1.0s. + This makes it a pain to mod, so instead I had to make some compromises and go for a percentage charge instead. + + The goal here is to make it easier to intuit when the box respawns, so you can still play around it. + Percentage until respawn is still more helpful than absolutely nothing. + I wanted to keep the original TNT box's respawn design here, so I didn't touch the timer. + I prefer adding onto existing behavior than editing existing code. + This mod is supposed to be a quality of life thing after all. +""" + + +# ba_meta export plugin +class TNTRespawnText(ba.Plugin): + + # This clamping function will make sure a certain value can't go above or below a certain threshold. + # We're gonna need this functionality in just a bit. + def clamp(num, min_value, max_value): + num = max(min(num, max_value), min_value) + return num + + # This function gets called every time the TNT dies. Doesn't matter how. + # Explosions, getting thrown out of bounds, stuff. + # I want the text appearing animation to start as soon as the TNT box blows up. + def on_tnt_exploded(self): + self.tnt_has_callback = False + self._respawn_text.color = (1.0, 1.0, 1.0) + ba.animate( + self._respawn_text, + 'opacity', + { + 0: 0.0, + self._respawn_time * 0.5: 0.175, + self._respawn_time: 0.4 + }, + ) + + # We're gonna use the magic of decorators to expand the original code with new stuff. + # This even works with other mods too! Don't replace functions, use decorators! + # Anyway we're gonna access the TNTSpawner class' init function. + def new_init(func): + def wrapper(*args, **kwargs): + + # The update function is not only called by a timer, but also manually + # during the original init function's execution. + # This means the code expects a variable that doesn't exist. + # Let's make it prematurely. + # args[0] is "self" in the original game code. + args[0]._respawn_text = None + + # This is where the original game's code is executed. + func(*args, **kwargs) + + # For each TNT we make we want to add a callback. + # It's basically a flag that tells the TNT to call a function. + # We don't want to add several of the same flag at once. + # We set this to True every time we add a callback. + # We check for this variable before adding a new one. + args[0].tnt_has_callback = True + + # Let's make the text. + # We tap into the spawner position in order to decide where the text should be. + respawn_text_position = (args[0]._position[0], + args[0]._position[1] - 0.4, + args[0]._position[2]) + args[0]._respawn_text = ba.newnode( + 'text', + attrs={ + 'text': "", # we'll set the text later + 'in_world': True, + 'position': respawn_text_position, + 'shadow': 1.0, + 'flatness': 1.0, + 'color': (1.0, 1.0, 1.0), + 'opacity': 0.0, + 'scale': 0.0225, + 'h_align': 'center', + 'v_align': 'center', + }, + ) + # Here we add our callback. + # Timers don't like calling functions that are outside of the game's "universe". + # If we call the function directly, we get a PyCallable error. + # We make a dummy function to avoid this. + def tnt_callback(): + TNTRespawnText.on_tnt_exploded(args[0]) + + # One disadvantage of the documentation is that it doesn't tell you all functions related to the node system. + # To learn about all possible atttributes and functions you just gotta explore the code and experiment. + # This add_death_action function of the node system is used in the original game + # to let the player know if the node got removed. + # For bombs that would be explosions or when they go out of bounds. + # This is used to increase the owner's bomb count by one. + # Here however we'll use this function to manipulate our text logic. + # We want to animate our text the moment the TNT box dies. + args[0]._tnt.node.add_death_action(tnt_callback) + return wrapper + # Let's replace the original init function with our modified version. + bastd.actor.bomb.TNTSpawner.__init__ = new_init(bastd.actor.bomb.TNTSpawner.__init__) + + # Our modified update function. + # This gets called every 1.1s. Check the TNTSpawner class in the game's code for details. + def new_update(func): + def wrapper(*args, **kwargs): + + # Check if our TNT box is still kickin'. + tnt_alive = args[0]._tnt is not None and args[0]._tnt.node + + func(*args, **kwargs) # original code + + # The first time this code executes, nothing happens. + # However once our text node is created properly, let's do some work. + if args[0]._respawn_text: + + # Let's make a value that will represent percentage. + # 0 means timer started and 100 means ready. + value = args[0]._wait_time / args[0]._respawn_time + + # It's annoying when the number jumps from 99% to 100% and it's delayed. + # Let's make sure this happens less often. + # I turned a linear curve into an exponential one. + value = math.pow(value - 0.001, 2) + + # Let's turn the value into a percentage. + value = math.floor(value * 100) + + # Let's make sure it's actually between 0 and 100. + value = TNTRespawnText.clamp(value, 0, 100) + + # Let's finish it off with a percentage symbol and preso! + args[0]._respawn_text.text = str(value)+"%" + + # When the timer ticks, we do different things depending on the time and the state of our TNT box. + if not tnt_alive: + # Code goes here if we don't have a TNT box and we reached 100%. + if args[0]._tnt is None or args[0]._wait_time >= args[0]._respawn_time and args[0]._respawn_text: + # Animate the text "bounce" to draw attention + ba.animate( + args[0]._respawn_text, + 'scale', + { + 0: args[0]._respawn_text.scale * 1.2, + 0.3: args[0]._respawn_text.scale * 1.05, + 0.6: args[0]._respawn_text.scale * 1.025, + 1.1: args[0]._respawn_text.scale + }, + ) + # Fade the text away + ba.animate( + args[0]._respawn_text, + 'opacity', + { + 0: args[0]._respawn_text.opacity, + 1.1: 0.0 + }, + ) + # Make sure it says 100%, because our value we calculated earlier might not be accurate at that point. + args[0]._respawn_text.text = "100%" + + # Make our text orange. + args[0]._respawn_text.color = (1.0, 0.75, 0.5) + + # Make some sparks to draw the eye. + ba.emitfx( + position=args[0]._position, + count=int(5.0 + random.random() * 10), + scale=0.8, + spread=1.25, + chunk_type='spark', + ) + # What if we still have our TNT box? + else: + # If the TNT box is fresly spawned spawned earlier in the function, chances are it doesn't have a callback. + # If it has, ignore. Otherwise let's add it. + # Cloning code that already exists in init is not very clean, but that'll do. + if args[0].tnt_has_callback: return + def tnt_callback(): + TNTRespawnText.on_tnt_exploded(args[0]) + args[0]._tnt.node.add_death_action(tnt_callback) + return wrapper + + # Let's replace the original update function with our modified version. + bastd.actor.bomb.TNTSpawner._update = new_update(bastd.actor.bomb.TNTSpawner._update) From 83da21895d4b56880843cf1a8dab26d1c4783703 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sat, 14 Jan 2023 20:05:06 +0530 Subject: [PATCH 19/82] Suffix with .py extension --- plugins/utilities/{tnt_respawn_text => tnt_respawn_text.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/utilities/{tnt_respawn_text => tnt_respawn_text.py} (100%) diff --git a/plugins/utilities/tnt_respawn_text b/plugins/utilities/tnt_respawn_text.py similarity index 100% rename from plugins/utilities/tnt_respawn_text rename to plugins/utilities/tnt_respawn_text.py From 05ffa9fd0ce869570396e2bed51655e92338f606 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 14 Jan 2023 14:35:39 +0000 Subject: [PATCH 20/82] [ci] auto-format --- plugins/utilities/tnt_respawn_text.py | 59 ++++++++++++++------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/plugins/utilities/tnt_respawn_text.py b/plugins/utilities/tnt_respawn_text.py index bbcdc99..5005109 100644 --- a/plugins/utilities/tnt_respawn_text.py +++ b/plugins/utilities/tnt_respawn_text.py @@ -24,7 +24,7 @@ from bastd.actor.bomb import Bomb if TYPE_CHECKING: pass - + """ Turns out TNT respawning got changed during the 1.5 update. At first I planned to make an accurate timer text that just counts down seconds to respawn. @@ -69,24 +69,24 @@ class TNTRespawnText(ba.Plugin): # Anyway we're gonna access the TNTSpawner class' init function. def new_init(func): def wrapper(*args, **kwargs): - + # The update function is not only called by a timer, but also manually # during the original init function's execution. # This means the code expects a variable that doesn't exist. # Let's make it prematurely. # args[0] is "self" in the original game code. args[0]._respawn_text = None - + # This is where the original game's code is executed. func(*args, **kwargs) - + # For each TNT we make we want to add a callback. # It's basically a flag that tells the TNT to call a function. # We don't want to add several of the same flag at once. # We set this to True every time we add a callback. # We check for this variable before adding a new one. args[0].tnt_has_callback = True - + # Let's make the text. # We tap into the spawner position in order to decide where the text should be. respawn_text_position = (args[0]._position[0], @@ -95,7 +95,7 @@ class TNTRespawnText(ba.Plugin): args[0]._respawn_text = ba.newnode( 'text', attrs={ - 'text': "", # we'll set the text later + 'text': "", # we'll set the text later 'in_world': True, 'position': respawn_text_position, 'shadow': 1.0, @@ -111,12 +111,13 @@ class TNTRespawnText(ba.Plugin): # Timers don't like calling functions that are outside of the game's "universe". # If we call the function directly, we get a PyCallable error. # We make a dummy function to avoid this. + def tnt_callback(): TNTRespawnText.on_tnt_exploded(args[0]) - + # One disadvantage of the documentation is that it doesn't tell you all functions related to the node system. # To learn about all possible atttributes and functions you just gotta explore the code and experiment. - # This add_death_action function of the node system is used in the original game + # This add_death_action function of the node system is used in the original game # to let the player know if the node got removed. # For bombs that would be explosions or when they go out of bounds. # This is used to increase the owner's bomb count by one. @@ -131,34 +132,34 @@ class TNTRespawnText(ba.Plugin): # This gets called every 1.1s. Check the TNTSpawner class in the game's code for details. def new_update(func): def wrapper(*args, **kwargs): - + # Check if our TNT box is still kickin'. tnt_alive = args[0]._tnt is not None and args[0]._tnt.node - - func(*args, **kwargs) # original code - + + func(*args, **kwargs) # original code + # The first time this code executes, nothing happens. # However once our text node is created properly, let's do some work. if args[0]._respawn_text: - + # Let's make a value that will represent percentage. # 0 means timer started and 100 means ready. value = args[0]._wait_time / args[0]._respawn_time - + # It's annoying when the number jumps from 99% to 100% and it's delayed. # Let's make sure this happens less often. # I turned a linear curve into an exponential one. value = math.pow(value - 0.001, 2) - + # Let's turn the value into a percentage. value = math.floor(value * 100) - + # Let's make sure it's actually between 0 and 100. value = TNTRespawnText.clamp(value, 0, 100) - + # Let's finish it off with a percentage symbol and preso! args[0]._respawn_text.text = str(value)+"%" - + # When the timer ticks, we do different things depending on the time and the state of our TNT box. if not tnt_alive: # Code goes here if we don't have a TNT box and we reached 100%. @@ -185,28 +186,30 @@ class TNTRespawnText(ba.Plugin): ) # Make sure it says 100%, because our value we calculated earlier might not be accurate at that point. args[0]._respawn_text.text = "100%" - + # Make our text orange. args[0]._respawn_text.color = (1.0, 0.75, 0.5) - + # Make some sparks to draw the eye. ba.emitfx( - position=args[0]._position, - count=int(5.0 + random.random() * 10), - scale=0.8, - spread=1.25, - chunk_type='spark', - ) + position=args[0]._position, + count=int(5.0 + random.random() * 10), + scale=0.8, + spread=1.25, + chunk_type='spark', + ) # What if we still have our TNT box? else: # If the TNT box is fresly spawned spawned earlier in the function, chances are it doesn't have a callback. # If it has, ignore. Otherwise let's add it. # Cloning code that already exists in init is not very clean, but that'll do. - if args[0].tnt_has_callback: return + if args[0].tnt_has_callback: + return + def tnt_callback(): TNTRespawnText.on_tnt_exploded(args[0]) args[0]._tnt.node.add_death_action(tnt_callback) return wrapper - + # Let's replace the original update function with our modified version. bastd.actor.bomb.TNTSpawner._update = new_update(bastd.actor.bomb.TNTSpawner._update) From 852fa8fb46943f25db6b5648b9bf362d7ffa5c1d Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sat, 14 Jan 2023 14:35:41 +0000 Subject: [PATCH 21/82] [ci] apply-version-metadata --- plugins/utilities.json | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3b525ae..fee7b87 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -633,7 +633,7 @@ } } }, - "tnt_respawn_text": { + "tnt_respawn_text": { "description": "Shows when a TNT box is about to respawn with non-intrusive text.", "external_url": "", "authors": [ @@ -644,8 +644,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "05ffa9f", + "released_on": "14-01-2023", + "md5sum": "cc1738b0326c9679453bdf1489ded483" + } } } } -} +} \ No newline at end of file From 7a8e9d3155a6d4571503fa6cb19e1e22884a2ceb Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Wed, 21 Dec 2022 13:32:02 +0530 Subject: [PATCH 22/82] Add partition function Added the partition function to 'PluginWindow' class. This function inserts new line breaks, for a specific character offset count. --- plugin_manager.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugin_manager.py b/plugin_manager.py index 51051ad..6521b16 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -787,6 +787,23 @@ class PluginWindow(popup.PopupWindow): self.scale_origin = origin_widget.get_screen_space_center() loop = asyncio.get_event_loop() loop.create_task(self.draw_ui()) + + def partition(string, minimum_character_offset=40): + string_length = len(string) + + partitioned_string = "" + partitioned_string_length = len(partitioned_string) + + while partitioned_string_length != string_length: + next_empty_space = string[partitioned_string_length + minimum_character_offset:].find(" ") + next_word_end_position = partitioned_string_length + minimum_character_offset + max(0, next_empty_space) + partitioned_string += string[partitioned_string_length:next_word_end_position] + if next_empty_space != -1: + # Insert a line break here, there's still more partitioning to do. + partitioned_string += "\n" + partitioned_string_length = len(partitioned_string) + + return partitioned_string async def draw_ui(self): # print(ba.app.plugins.active_plugins) From 5caa5bdf2fced8b48013dc79cacc3a972bbfdecd Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Wed, 21 Dec 2022 08:39:02 +0000 Subject: [PATCH 23/82] [ci] auto-format --- plugin_manager.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 6521b16..db7fef6 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -787,7 +787,7 @@ class PluginWindow(popup.PopupWindow): self.scale_origin = origin_widget.get_screen_space_center() loop = asyncio.get_event_loop() loop.create_task(self.draw_ui()) - + def partition(string, minimum_character_offset=40): string_length = len(string) @@ -795,8 +795,10 @@ class PluginWindow(popup.PopupWindow): partitioned_string_length = len(partitioned_string) while partitioned_string_length != string_length: - next_empty_space = string[partitioned_string_length + minimum_character_offset:].find(" ") - next_word_end_position = partitioned_string_length + minimum_character_offset + max(0, next_empty_space) + next_empty_space = string[partitioned_string_length + + minimum_character_offset:].find(" ") + next_word_end_position = partitioned_string_length + \ + minimum_character_offset + max(0, next_empty_space) partitioned_string += string[partitioned_string_length:next_word_end_position] if next_empty_space != -1: # Insert a line break here, there's still more partitioning to do. From 2632086557964a2e7f778c574499ccfeb24c9c08 Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Wed, 21 Dec 2022 14:44:38 +0530 Subject: [PATCH 24/82] Remove line break characters. --- plugins/utilities.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index fee7b87..d2db80c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -482,7 +482,7 @@ } }, "pro_unlocker": { - "description": "Unlocks some pro-only features - custom colors, playlist maker, etc.\n(Please support the game developer if you can!)", + "description": "Unlocks some pro-only features - custom colors, playlist maker, etc. (Please support the game developer if you can!)", "external_url": "", "authors": [ { @@ -558,7 +558,7 @@ } }, "bomb_radius_visualizer": { - "description": "With this cutting edge technology, you precisely know\nhow close to the bomb you can tread.\nSupports modified blast radius values!", + "description": "With this cutting edge technology, you precisely know how close to the bomb you can tread. Supports modified blast radius values!", "external_url": "", "authors": [ { @@ -653,4 +653,4 @@ } } } -} \ No newline at end of file +} From de6a1b86cb1f93017fe9fa2548631ea37160f162 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Wed, 21 Dec 2022 09:15:09 +0000 Subject: [PATCH 25/82] [ci] apply-version-metadata --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index d2db80c..57a58b0 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -653,4 +653,4 @@ } } } -} +} \ No newline at end of file From a0bb69ddd7e814662f49c2d9f384511e6e17a402 Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Thu, 22 Dec 2022 17:06:27 +0530 Subject: [PATCH 26/82] Update for get_description function Changed the partition function to get_description function and moved inside the draw_ui to make it working. --- plugin_manager.py | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index db7fef6..8854954 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -788,27 +788,29 @@ class PluginWindow(popup.PopupWindow): loop = asyncio.get_event_loop() loop.create_task(self.draw_ui()) - def partition(string, minimum_character_offset=40): - string_length = len(string) - - partitioned_string = "" - partitioned_string_length = len(partitioned_string) - - while partitioned_string_length != string_length: - next_empty_space = string[partitioned_string_length + - minimum_character_offset:].find(" ") - next_word_end_position = partitioned_string_length + \ - minimum_character_offset + max(0, next_empty_space) - partitioned_string += string[partitioned_string_length:next_word_end_position] - if next_empty_space != -1: - # Insert a line break here, there's still more partitioning to do. - partitioned_string += "\n" - partitioned_string_length = len(partitioned_string) - - return partitioned_string - async def draw_ui(self): # print(ba.app.plugins.active_plugins) + + def get_description(minimum_character_offset=40): + string = self.plugin.info["description"] + string_length = len(string) + + partitioned_string = "" + partitioned_string_length = len(partitioned_string) + + while partitioned_string_length != string_length: + next_empty_space = string[partitioned_string_length + + minimum_character_offset:].find(" ") + next_word_end_position = partitioned_string_length + \ + minimum_character_offset + max(0, next_empty_space) + partitioned_string += string[partitioned_string_length:next_word_end_position] + if next_empty_space != -1: + # Insert a line break here, there's still more partitioning to do. + partitioned_string += "\n" + partitioned_string_length = len(partitioned_string) + + return partitioned_string + play_sound() b_text_color = (0.75, 0.7, 0.8) s = 1.1 if _uiscale is ba.UIScale.SMALL else 1.27 if ba.UIScale.MEDIUM else 1.57 @@ -856,7 +858,7 @@ class PluginWindow(popup.PopupWindow): ba.textwidget(parent=self._root_widget, position=(width * 0.49, pos), size=(0, 0), h_align='center', v_align='center', - text=self.plugin.info["description"], + text=get_description(),#self.plugin.info["description"], scale=text_scale * 0.6, color=color, maxwidth=width * 0.95) b1_color = None From 23b4866435eeeaed5173e0eccac6bf0816c85a21 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Thu, 22 Dec 2022 11:36:54 +0000 Subject: [PATCH 27/82] [ci] auto-format --- plugin_manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 8854954..246c29e 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -790,7 +790,7 @@ class PluginWindow(popup.PopupWindow): async def draw_ui(self): # print(ba.app.plugins.active_plugins) - + def get_description(minimum_character_offset=40): string = self.plugin.info["description"] string_length = len(string) @@ -810,7 +810,7 @@ class PluginWindow(popup.PopupWindow): partitioned_string_length = len(partitioned_string) return partitioned_string - + play_sound() b_text_color = (0.75, 0.7, 0.8) s = 1.1 if _uiscale is ba.UIScale.SMALL else 1.27 if ba.UIScale.MEDIUM else 1.57 @@ -858,7 +858,7 @@ class PluginWindow(popup.PopupWindow): ba.textwidget(parent=self._root_widget, position=(width * 0.49, pos), size=(0, 0), h_align='center', v_align='center', - text=get_description(),#self.plugin.info["description"], + text=get_description(), # self.plugin.info["description"], scale=text_scale * 0.6, color=color, maxwidth=width * 0.95) b1_color = None From e783e2bfa3b048681f19c9aa41dc9af53520182c Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 18 Jan 2023 18:54:16 +0530 Subject: [PATCH 28/82] get_description as a class method --- plugin_manager.py | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 246c29e..11539bc 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -788,28 +788,33 @@ class PluginWindow(popup.PopupWindow): loop = asyncio.get_event_loop() loop.create_task(self.draw_ui()) - async def draw_ui(self): - # print(ba.app.plugins.active_plugins) - def get_description(minimum_character_offset=40): - string = self.plugin.info["description"] - string_length = len(string) + def get_description(self, minimum_character_offset=40): + """ + Splits the loong plugin description into multiple lines. + """ + string = self.plugin.info["description"] + string_length = len(string) - partitioned_string = "" + partitioned_string = "" + partitioned_string_length = len(partitioned_string) + + while partitioned_string_length != string_length: + next_empty_space = string[partitioned_string_length + + minimum_character_offset:].find(" ") + next_word_end_position = partitioned_string_length + \ + minimum_character_offset + max(0, next_empty_space) + partitioned_string += string[partitioned_string_length:next_word_end_position] + if next_empty_space != -1: + # Insert a line break here, there's still more partitioning to do. + partitioned_string += "\n" partitioned_string_length = len(partitioned_string) - while partitioned_string_length != string_length: - next_empty_space = string[partitioned_string_length + - minimum_character_offset:].find(" ") - next_word_end_position = partitioned_string_length + \ - minimum_character_offset + max(0, next_empty_space) - partitioned_string += string[partitioned_string_length:next_word_end_position] - if next_empty_space != -1: - # Insert a line break here, there's still more partitioning to do. - partitioned_string += "\n" - partitioned_string_length = len(partitioned_string) + return partitioned_string - return partitioned_string + + async def draw_ui(self): + # print(ba.app.plugins.active_plugins) play_sound() b_text_color = (0.75, 0.7, 0.8) @@ -858,7 +863,7 @@ class PluginWindow(popup.PopupWindow): ba.textwidget(parent=self._root_widget, position=(width * 0.49, pos), size=(0, 0), h_align='center', v_align='center', - text=get_description(), # self.plugin.info["description"], + text=self.get_description(), scale=text_scale * 0.6, color=color, maxwidth=width * 0.95) b1_color = None From 02b461d9215bf8164ff2f63f8ff59e05ab6b1c40 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 18 Jan 2023 18:54:58 +0530 Subject: [PATCH 29/82] Remove explicit line break in plugin description --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 57a58b0..63ac428 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -615,7 +615,7 @@ } }, "autorun": { - "description": "Run without holding any buttons. Made for beginners or players on mobile.\nKeeps your character maneuverable. Start running as usual to override.", + "description": "Run without holding any buttons. Made for beginners or players on mobile. Keeps your character maneuverable. Start running as usual to override.", "external_url": "", "authors": [ { @@ -653,4 +653,4 @@ } } } -} \ No newline at end of file +} From f00a899a4ee53df660316c7c1b76f40800d99743 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 18 Jan 2023 13:25:52 +0000 Subject: [PATCH 30/82] [ci] auto-format --- plugin_manager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 11539bc..5c00c25 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -788,7 +788,6 @@ class PluginWindow(popup.PopupWindow): loop = asyncio.get_event_loop() loop.create_task(self.draw_ui()) - def get_description(self, minimum_character_offset=40): """ Splits the loong plugin description into multiple lines. @@ -812,7 +811,6 @@ class PluginWindow(popup.PopupWindow): return partitioned_string - async def draw_ui(self): # print(ba.app.plugins.active_plugins) From f9b4e3beaa6e52ee629cd9edc584a44248685c0c Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 18 Jan 2023 13:25:54 +0000 Subject: [PATCH 31/82] [ci] apply-version-metadata --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 63ac428..ad3ad27 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -653,4 +653,4 @@ } } } -} +} \ No newline at end of file From 2672a5a4b01246a85cd4539a2a2d44b9b5fa7d02 Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 18 Jan 2023 19:02:12 +0530 Subject: [PATCH 32/82] Bump to v0.2.2 --- CHANGELOG.md | 5 +++++ index.json | 3 ++- plugin_manager.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f87732c..d0c4781 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.2.2 (18-01-2022) + +- Auto add new line breaks in long plugin descriptions. +- Fixed an issue where pressing back on the main plugin manager window would play the sound twice. + ### 0.2.1 (17-12-2022) - Add Google DNS as a fallback for Jio ISP DNS blocking resolution of raw.githubusercontent.com domain. diff --git a/index.json b/index.json index ae7beed..a0bafaa 100644 --- a/index.json +++ b/index.json @@ -1,6 +1,7 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { + "0.2.2": null, "0.2.1": { "api_version": 7, "commit_sha": "8ac1032", @@ -62,4 +63,4 @@ "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "https://github.com/{repository}/{content_type}/{tag}/category.json" -} \ No newline at end of file +} diff --git a/plugin_manager.py b/plugin_manager.py index c29f7f6..1650138 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _env = _ba.env() _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.2.1" +PLUGIN_MANAGER_VERSION = "0.2.2" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" From c7ffa61d7328d8aeba0aa15c6b14bdaa94b4a7fd Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 18 Jan 2023 13:32:47 +0000 Subject: [PATCH 33/82] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index a0bafaa..7ed3695 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.2.2": null, + "0.2.2": { + "api_version": 7, + "commit_sha": "2672a5a", + "released_on": "18-01-2023", + "md5sum": "2ef9761e4a02057cd93db3d280427f12" + }, "0.2.1": { "api_version": 7, "commit_sha": "8ac1032", @@ -63,4 +68,4 @@ "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "https://github.com/{repository}/{content_type}/{tag}/category.json" -} +} \ No newline at end of file From 21a81a67d129e32c682d51f70cd25d5c017415fe Mon Sep 17 00:00:00 2001 From: Rikko Date: Wed, 18 Jan 2023 19:28:19 +0530 Subject: [PATCH 34/82] ee --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0c4781..0a46809 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## Plugin Manager (dd-mm-yyyy) -### 0.2.2 (18-01-2022) +### 0.2.2 (18-01-2023) - Auto add new line breaks in long plugin descriptions. - Fixed an issue where pressing back on the main plugin manager window would play the sound twice. From 3221b3a56711f54be8183e675a245f3137957655 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 22 Jan 2023 15:34:19 +0530 Subject: [PATCH 35/82] Allow invisible models --- plugins/utilities.json | 16 +++++++++++++++- plugins/utilities/allow_invisible_models.py | 15 +++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 plugins/utilities/allow_invisible_models.py diff --git a/plugins/utilities.json b/plugins/utilities.json index ad3ad27..3dde59e 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -651,6 +651,20 @@ "md5sum": "cc1738b0326c9679453bdf1489ded483" } } + }, + "allow_invisible_models": { + "description": "Changing model to None will make it invisible instead of raising an exception.", + "external_url": "", + "authors": [ + { + "name": "Rikko", + "email": "rikkolovescats@proton.me", + "discord": "Rikko#7383" + } + ], + "versions": { + "1.0.0": null + } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/allow_invisible_models.py b/plugins/utilities/allow_invisible_models.py new file mode 100644 index 0000000..b2d1403 --- /dev/null +++ b/plugins/utilities/allow_invisible_models.py @@ -0,0 +1,15 @@ +# ba_meta require api 7 +import ba + +original_getmodel = ba.getmodel + + +def get_model_gracefully(model): + if model is not None: + return original_getmodel(model) + + +# ba_meta export plugin +class Main(ba.Plugin): + def on_app_running(self): + ba.getmodel = get_model_gracefully From 7e8e61d07730f1ac93d4cd8568846b0fa96cc6cf Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 22 Jan 2023 10:05:08 +0000 Subject: [PATCH 36/82] [ci] apply-version-metadata --- plugins/utilities.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 3dde59e..c1a86a6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -663,8 +663,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "3221b3a", + "released_on": "22-01-2023", + "md5sum": "24913c665d05c3056c8ba390fe88155e" + } } } } -} +} \ No newline at end of file From 1b387980780c89e22f78a41f507b0924b11a0abf Mon Sep 17 00:00:00 2001 From: Rikko Date: Mon, 23 Jan 2023 14:44:41 +0530 Subject: [PATCH 37/82] Mention about known 3rd party plugin sources --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index c2a3c31..a07a3e5 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,14 @@ That's it! Now you can make a [pull request](../../compare) with both the update repository in your plugin manager by adding `rikkolovescats/sahilp-plugins` as a custom source through the category selection popup window in-game. + #### Known 3rd Party Plugin Sources + + If you maintain or know of a 3rd party plugin source, let us know and we'll add it below so people can know about it. It + will also help us to notify the maintainers of any future breaking changes in plugin manager that could affect 3rd party + plugin sources. + + https://github.com/rikkolovescats/sahilp-plugins + ## Tests From 5b94d959894d1bc77d7d5e66cde5cbcc9f648946 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 26 Jan 2023 00:48:16 +0530 Subject: [PATCH 38/82] Test upcoming API 7->8 --- plugins/utilities.json | 16 +++++++++++++++- plugins/utilities/hello_api_8.py | 7 +++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 plugins/utilities/hello_api_8.py diff --git a/plugins/utilities.json b/plugins/utilities.json index c1a86a6..6ca1180 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -670,6 +670,20 @@ "md5sum": "24913c665d05c3056c8ba390fe88155e" } } + }, + "hello_api_8": { + "description": "I shouldn't be visible to API 7 game clients", + "external_url": "", + "authors": [ + { + "name": "Rikko", + "email": "rikkolovescats@proton.me", + "discord": "Rikko#7383" + } + ], + "versions": { + "1.0.0": null + } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/hello_api_8.py b/plugins/utilities/hello_api_8.py new file mode 100644 index 0000000..7ccac78 --- /dev/null +++ b/plugins/utilities/hello_api_8.py @@ -0,0 +1,7 @@ +# ba_meta require api 8 +import ba + +# ba_meta export plugin +class Main(ba.Plugin): + def on_app_running(self): + ba.screenmessage("Wohoo! I'm an API 8 plugin!") From 204499e4db8e3285610d626d1a4bb406f022b81c Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 25 Jan 2023 19:20:18 +0000 Subject: [PATCH 39/82] [ci] auto-format --- plugins/utilities/hello_api_8.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/utilities/hello_api_8.py b/plugins/utilities/hello_api_8.py index 7ccac78..909a5df 100644 --- a/plugins/utilities/hello_api_8.py +++ b/plugins/utilities/hello_api_8.py @@ -2,6 +2,8 @@ import ba # ba_meta export plugin + + class Main(ba.Plugin): def on_app_running(self): ba.screenmessage("Wohoo! I'm an API 8 plugin!") From e8d9e9e264a9304981c4414e2752cebc40142d2c Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Wed, 25 Jan 2023 19:20:19 +0000 Subject: [PATCH 40/82] [ci] apply-version-metadata --- plugins/utilities.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 6ca1180..00be224 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -682,8 +682,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 8, + "commit_sha": "204499e", + "released_on": "25-01-2023", + "md5sum": "b694717a3fc0ef3d1d3a66ed399adbae" + } } } } -} +} \ No newline at end of file From fb23c496a46ffdead4fea93765b7943ca0684002 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 26 Jan 2023 18:19:36 +0530 Subject: [PATCH 41/82] API 7 --- plugins/utilities.json | 13 ++++--------- .../{hello_api_8.py => hello_api_experiment.py} | 4 ++-- 2 files changed, 6 insertions(+), 11 deletions(-) rename plugins/utilities/{hello_api_8.py => hello_api_experiment.py} (52%) diff --git a/plugins/utilities.json b/plugins/utilities.json index 00be224..8e50073 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -671,8 +671,8 @@ } } }, - "hello_api_8": { - "description": "I shouldn't be visible to API 7 game clients", + "hello_api_experiment": { + "description": "I shouldn't be visible to on clients with different API version", "external_url": "", "authors": [ { @@ -682,13 +682,8 @@ } ], "versions": { - "1.0.0": { - "api_version": 8, - "commit_sha": "204499e", - "released_on": "25-01-2023", - "md5sum": "b694717a3fc0ef3d1d3a66ed399adbae" - } + "1.0.0": null } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/hello_api_8.py b/plugins/utilities/hello_api_experiment.py similarity index 52% rename from plugins/utilities/hello_api_8.py rename to plugins/utilities/hello_api_experiment.py index 909a5df..16b4030 100644 --- a/plugins/utilities/hello_api_8.py +++ b/plugins/utilities/hello_api_experiment.py @@ -1,4 +1,4 @@ -# ba_meta require api 8 +# ba_meta require api 7 import ba # ba_meta export plugin @@ -6,4 +6,4 @@ import ba class Main(ba.Plugin): def on_app_running(self): - ba.screenmessage("Wohoo! I'm an API 8 plugin!") + ba.screenmessage("Wohoo! I'm an API 7 plugin!") From f2e674ce2040fac3a01bc934f450a3827e7d4972 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 26 Jan 2023 12:50:43 +0000 Subject: [PATCH 42/82] [ci] apply-version-metadata --- plugins/utilities.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8e50073..8cf4c61 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -682,8 +682,13 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "fb23c49", + "released_on": "26-01-2023", + "md5sum": "3a3c88996aaab26de8eab530cebebb44" + } } } } -} +} \ No newline at end of file From 24830a896a194adb9fe66cd69d880b0e32a39ad1 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 26 Jan 2023 18:29:13 +0530 Subject: [PATCH 43/82] API 8 --- plugins/utilities.json | 3 ++- plugins/utilities/hello_api_experiment.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 8cf4c61..e7be458 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -682,6 +682,7 @@ } ], "versions": { + "2.0.0": null, "1.0.0": { "api_version": 7, "commit_sha": "fb23c49", @@ -691,4 +692,4 @@ } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/hello_api_experiment.py b/plugins/utilities/hello_api_experiment.py index 16b4030..909a5df 100644 --- a/plugins/utilities/hello_api_experiment.py +++ b/plugins/utilities/hello_api_experiment.py @@ -1,4 +1,4 @@ -# ba_meta require api 7 +# ba_meta require api 8 import ba # ba_meta export plugin @@ -6,4 +6,4 @@ import ba class Main(ba.Plugin): def on_app_running(self): - ba.screenmessage("Wohoo! I'm an API 7 plugin!") + ba.screenmessage("Wohoo! I'm an API 8 plugin!") From 1cd681703eb1f5e2879f207d1fb605d5bead465b Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 26 Jan 2023 12:59:49 +0000 Subject: [PATCH 44/82] [ci] apply-version-metadata --- plugins/utilities.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index e7be458..bb7270c 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -682,7 +682,12 @@ } ], "versions": { - "2.0.0": null, + "2.0.0": { + "api_version": 8, + "commit_sha": "24830a8", + "released_on": "26-01-2023", + "md5sum": "b694717a3fc0ef3d1d3a66ed399adbae" + }, "1.0.0": { "api_version": 7, "commit_sha": "fb23c49", @@ -692,4 +697,4 @@ } } } -} +} \ No newline at end of file From d1445b03476addb6c32503b3163f301c3c459f52 Mon Sep 17 00:00:00 2001 From: Rikko Date: Thu, 26 Jan 2023 18:37:58 +0530 Subject: [PATCH 45/82] Remove experimental plugin --- plugins/utilities.json | 27 +---------------------- plugins/utilities/hello_api_experiment.py | 9 -------- 2 files changed, 1 insertion(+), 35 deletions(-) delete mode 100644 plugins/utilities/hello_api_experiment.py diff --git a/plugins/utilities.json b/plugins/utilities.json index bb7270c..5df193a 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -670,31 +670,6 @@ "md5sum": "24913c665d05c3056c8ba390fe88155e" } } - }, - "hello_api_experiment": { - "description": "I shouldn't be visible to on clients with different API version", - "external_url": "", - "authors": [ - { - "name": "Rikko", - "email": "rikkolovescats@proton.me", - "discord": "Rikko#7383" - } - ], - "versions": { - "2.0.0": { - "api_version": 8, - "commit_sha": "24830a8", - "released_on": "26-01-2023", - "md5sum": "b694717a3fc0ef3d1d3a66ed399adbae" - }, - "1.0.0": { - "api_version": 7, - "commit_sha": "fb23c49", - "released_on": "26-01-2023", - "md5sum": "3a3c88996aaab26de8eab530cebebb44" - } - } } } -} \ No newline at end of file +} diff --git a/plugins/utilities/hello_api_experiment.py b/plugins/utilities/hello_api_experiment.py deleted file mode 100644 index 909a5df..0000000 --- a/plugins/utilities/hello_api_experiment.py +++ /dev/null @@ -1,9 +0,0 @@ -# ba_meta require api 8 -import ba - -# ba_meta export plugin - - -class Main(ba.Plugin): - def on_app_running(self): - ba.screenmessage("Wohoo! I'm an API 8 plugin!") From ff1bf838f915083840aad212271686a4883365d5 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Thu, 26 Jan 2023 13:08:47 +0000 Subject: [PATCH 46/82] [ci] apply-version-metadata --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 5df193a..c1a86a6 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -672,4 +672,4 @@ } } } -} +} \ No newline at end of file From ac26f010aa32834f58e4b35a6b75e14daa3f9eda Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Mon, 30 Jan 2023 22:51:39 +0530 Subject: [PATCH 47/82] UI changes for tutorial button UI has been added for the tutorial button along with the URL reference. Still need to update for non-existent URL logic and texture. --- plugin_manager.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/plugin_manager.py b/plugin_manager.py index 1650138..ccd35f6 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -960,6 +960,35 @@ class PluginWindow(popup.PopupWindow): color=(1, 1, 1, 1), rotate=25, scale=0.45) + + ## Below snippet handles the tutorial button in the plugin window + open_pos_x = (10 if _uiscale is ba.UIScale.SMALL else + 50 if _uiscale is ba.UIScale.MEDIUM else 50) + open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else + 110 if _uiscale is ba.UIScale.MEDIUM else 120) + open_button = ba.buttonwidget(parent=self._root_widget, + autoselect=True, + position=(open_pos_x, open_pos_y), + size=(40, 40), + button_type="square", + label="", + # color=ba.app.ui.title_color, + color=(0.6, 0.53, 0.63), + on_activate_call=lambda: ba.open_url(self.plugin.info["external_url"])) + ba.imagewidget(parent=self._root_widget, + position=(open_pos_x, open_pos_y), + size=(40, 40), + color=(0.8, 0.95, 1), + texture=ba.gettexture("file"), + draw_controller=open_button) + ba.textwidget(parent=self._root_widget, + position=(open_pos_x - 3, open_pos_y + 12), + text="Tutorial", + size=(10, 10), + draw_controller=open_button, + color=(1, 1, 1, 1), + rotate=25, + scale=0.45) if to_draw_button4: settings_pos_x = (60 if _uiscale is ba.UIScale.SMALL else From faf2b8a0b8ccd1b81d3cae03c30d4aadbf19f1ba Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Tue, 31 Jan 2023 15:39:13 +0530 Subject: [PATCH 48/82] Final tutorial button Changed the texture to "frameInset" and the button will only appear only if the external_url is not empty. --- plugin_manager.py | 56 ++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index ccd35f6..67fe530 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -962,33 +962,35 @@ class PluginWindow(popup.PopupWindow): scale=0.45) ## Below snippet handles the tutorial button in the plugin window - open_pos_x = (10 if _uiscale is ba.UIScale.SMALL else - 50 if _uiscale is ba.UIScale.MEDIUM else 50) - open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else - 110 if _uiscale is ba.UIScale.MEDIUM else 120) - open_button = ba.buttonwidget(parent=self._root_widget, - autoselect=True, - position=(open_pos_x, open_pos_y), - size=(40, 40), - button_type="square", - label="", - # color=ba.app.ui.title_color, - color=(0.6, 0.53, 0.63), - on_activate_call=lambda: ba.open_url(self.plugin.info["external_url"])) - ba.imagewidget(parent=self._root_widget, - position=(open_pos_x, open_pos_y), - size=(40, 40), - color=(0.8, 0.95, 1), - texture=ba.gettexture("file"), - draw_controller=open_button) - ba.textwidget(parent=self._root_widget, - position=(open_pos_x - 3, open_pos_y + 12), - text="Tutorial", - size=(10, 10), - draw_controller=open_button, - color=(1, 1, 1, 1), - rotate=25, - scale=0.45) + tutorial_url = self.plugin.info["external_url"] + if tutorial_url: + open_pos_x = (10 if _uiscale is ba.UIScale.SMALL else + 70 if _uiscale is ba.UIScale.MEDIUM else 60) + open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else + 110 if _uiscale is ba.UIScale.MEDIUM else 120) + open_button = ba.buttonwidget(parent=self._root_widget, + autoselect=True, + position=(open_pos_x, open_pos_y), + size=(40, 40), + button_type="square", + label="", + # color=ba.app.ui.title_color, + color=(0.6, 0.53, 0.63), + on_activate_call=lambda: ba.open_url(self.plugin.info["external_url"])) + ba.imagewidget(parent=self._root_widget, + position=(open_pos_x, open_pos_y), + size=(40, 40), + color=(0.8, 0.95, 1), + texture=ba.gettexture("frameInset"), + draw_controller=open_button) + ba.textwidget(parent=self._root_widget, + position=(open_pos_x - 3, open_pos_y + 12), + text="Tutorial", + size=(10, 10), + draw_controller=open_button, + color=(1, 1, 1, 1), + rotate=25, + scale=0.45) if to_draw_button4: settings_pos_x = (60 if _uiscale is ba.UIScale.SMALL else From ee2715d3ecac9fd033f82651258f2caa1367f0ac Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Tue, 31 Jan 2023 15:41:31 +0530 Subject: [PATCH 49/82] Bump the plugin manager version Changed the plugin manager minor version to reflect in the existing consoles as an updated version. --- plugin_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index 67fe530..e789d07 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _env = _ba.env() _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.2.2" +PLUGIN_MANAGER_VERSION = "0.2.3" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" From 5d773946bb17ce0eb82b0a320436b386cb7645b3 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Tue, 31 Jan 2023 10:16:15 +0000 Subject: [PATCH 50/82] [ci] auto-format --- plugin_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index e789d07..412575c 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -960,8 +960,8 @@ class PluginWindow(popup.PopupWindow): color=(1, 1, 1, 1), rotate=25, scale=0.45) - - ## Below snippet handles the tutorial button in the plugin window + + # Below snippet handles the tutorial button in the plugin window tutorial_url = self.plugin.info["external_url"] if tutorial_url: open_pos_x = (10 if _uiscale is ba.UIScale.SMALL else From 2e78a54c682fb163fd5e3e516985bf9160eede0c Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Tue, 31 Jan 2023 19:32:46 +0530 Subject: [PATCH 51/82] Update Changelog.md Edited the changelog to display the 0.2.3 description. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a46809..26bf651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.2.3 (31-01-2023) + +- Displays a tutorial button, whenever there is a external_url is present in the plugin data. + ### 0.2.2 (18-01-2023) - Auto add new line breaks in long plugin descriptions. From 8f61bce3a5030fac5a900f324c0b1ecd1f042b3c Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Tue, 31 Jan 2023 19:33:59 +0530 Subject: [PATCH 52/82] typo in the changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26bf651..6088c33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### 0.2.3 (31-01-2023) -- Displays a tutorial button, whenever there is a external_url is present in the plugin data. +- Displays a tutorial button, whenever there is a "external_url" present in the plugin data. ### 0.2.2 (18-01-2023) From 3d13058adba6af60153472f596c57499593cd2ec Mon Sep 17 00:00:00 2001 From: Sravan Date: Tue, 31 Jan 2023 20:58:30 +0530 Subject: [PATCH 53/82] Changed the tutorial button position As the previous UI button was replacing the settings button in some plugins. Changed the UI position. --- plugin_manager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index e789d07..5fdcbe7 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -960,12 +960,12 @@ class PluginWindow(popup.PopupWindow): color=(1, 1, 1, 1), rotate=25, scale=0.45) - - ## Below snippet handles the tutorial button in the plugin window + + # Below snippet handles the tutorial button in the plugin window tutorial_url = self.plugin.info["external_url"] if tutorial_url: - open_pos_x = (10 if _uiscale is ba.UIScale.SMALL else - 70 if _uiscale is ba.UIScale.MEDIUM else 60) + open_pos_x = (350 if _uiscale is ba.UIScale.SMALL else + 410 if _uiscale is ba.UIScale.MEDIUM else 400) open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else 110 if _uiscale is ba.UIScale.MEDIUM else 120) open_button = ba.buttonwidget(parent=self._root_widget, From 2720ce82120092dc76de83284ad88d0ff8814246 Mon Sep 17 00:00:00 2001 From: Sravan Date: Tue, 31 Jan 2023 21:00:19 +0530 Subject: [PATCH 54/82] changelog updated Updated the changelog to 0.2.3 change about the tutorial button --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a46809..d809d66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.2.3 (31-01-2023) + +- Displays a tutorial button in the plugin window, whenever there is a supported url present in the plugin data. + ### 0.2.2 (18-01-2023) - Auto add new line breaks in long plugin descriptions. From fe4d41177a01d1fe47e80f700292e4f93b46933f Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 7 Feb 2023 21:55:25 +0530 Subject: [PATCH 55/82] Added confirmation window --- plugin_manager.py | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 1650138..435a0f1 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1,7 +1,7 @@ # ba_meta require api 7 import ba import _ba -from bastd.ui import popup +from bastd.ui import popup, confirm import urllib.request import http.client @@ -813,7 +813,6 @@ class PluginWindow(popup.PopupWindow): async def draw_ui(self): # print(ba.app.plugins.active_plugins) - play_sound() b_text_color = (0.75, 0.7, 0.8) s = 1.1 if _uiscale is ba.UIScale.SMALL else 1.27 if ba.UIScale.MEDIUM else 1.57 @@ -960,7 +959,44 @@ class PluginWindow(popup.PopupWindow): color=(1, 1, 1, 1), rotate=25, scale=0.45) - + + # Below snippet handles the tutorial button in the plugin window + tutorial_url = self.plugin.info["external_url"] + if tutorial_url: + def tutorial_confirm_window(): + text="This will take you to \n\""+self.plugin.info["external_url"] + "\"" + tutorial_confirm_window = confirm.ConfirmWindow( + text=text, + action=lambda: ba.open_url(self.plugin.info["external_url"]), + ) + open_pos_x = (350 if _uiscale is ba.UIScale.SMALL else + 410 if _uiscale is ba.UIScale.MEDIUM else 400) + open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else + 110 if _uiscale is ba.UIScale.MEDIUM else 120) + open_button = ba.buttonwidget(parent=self._root_widget, + autoselect=True, + position=(open_pos_x, open_pos_y), + size=(40, 40), + button_type="square", + label="", + # color=ba.app.ui.title_color, + color=(0.6, 0.53, 0.63), + on_activate_call=tutorial_confirm_window) + ba.imagewidget(parent=self._root_widget, + position=(open_pos_x, open_pos_y), + size=(40, 40), + color=(0.8, 0.95, 1), + texture=ba.gettexture("frameInset"), + draw_controller=open_button) + ba.textwidget(parent=self._root_widget, + position=(open_pos_x - 3, open_pos_y + 12), + text="Tutorial", + size=(10, 10), + draw_controller=open_button, + color=(1, 1, 1, 1), + rotate=25, + scale=0.45) + if to_draw_button4: settings_pos_x = (60 if _uiscale is ba.UIScale.SMALL else 60 if _uiscale is ba.UIScale.MEDIUM else 60) From d13591e4738e0bdeefdfd7e56c7023b3500ba04b Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 7 Feb 2023 22:02:32 +0530 Subject: [PATCH 56/82] updated version --- index.json | 1 + plugin_manager.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 7ed3695..c2ba40e 100644 --- a/index.json +++ b/index.json @@ -1,6 +1,7 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { + "0.2.3": null, "0.2.2": { "api_version": 7, "commit_sha": "2672a5a", diff --git a/plugin_manager.py b/plugin_manager.py index 435a0f1..9efe976 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _env = _ba.env() _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.2.2" +PLUGIN_MANAGER_VERSION = "0.2.3" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" From 7efede369967c5713da329872e0770e46c32eacd Mon Sep 17 00:00:00 2001 From: Loup <90267658+Loup-Garou911XD@users.noreply.github.com> Date: Tue, 7 Feb 2023 23:12:23 +0530 Subject: [PATCH 57/82] Attempt at fixing conflict --- plugin_manager.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 9efe976..b97ae1a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -813,6 +813,7 @@ class PluginWindow(popup.PopupWindow): async def draw_ui(self): # print(ba.app.plugins.active_plugins) + play_sound() b_text_color = (0.75, 0.7, 0.8) s = 1.1 if _uiscale is ba.UIScale.SMALL else 1.27 if ba.UIScale.MEDIUM else 1.57 @@ -959,8 +960,8 @@ class PluginWindow(popup.PopupWindow): color=(1, 1, 1, 1), rotate=25, scale=0.45) - - # Below snippet handles the tutorial button in the plugin window + + # Below snippet handles the tutorial button in the plugin window tutorial_url = self.plugin.info["external_url"] if tutorial_url: def tutorial_confirm_window(): @@ -996,7 +997,7 @@ class PluginWindow(popup.PopupWindow): color=(1, 1, 1, 1), rotate=25, scale=0.45) - + if to_draw_button4: settings_pos_x = (60 if _uiscale is ba.UIScale.SMALL else 60 if _uiscale is ba.UIScale.MEDIUM else 60) From 6e457dae843e2e5205708f595ece100f91428834 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Wed, 8 Feb 2023 14:16:49 +0000 Subject: [PATCH 58/82] [ci] auto-format --- plugin_manager.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index fde5299..6fd149e 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -961,16 +961,15 @@ class PluginWindow(popup.PopupWindow): rotate=25, scale=0.45) - - # Below snippet handles the tutorial button in the plugin window + # Below snippet handles the tutorial button in the plugin window tutorial_url = self.plugin.info["external_url"] if tutorial_url: def tutorial_confirm_window(): - text="This will take you to \n\""+self.plugin.info["external_url"] + "\"" + text = "This will take you to \n\""+self.plugin.info["external_url"] + "\"" tutorial_confirm_window = confirm.ConfirmWindow( - text=text, - action=lambda: ba.open_url(self.plugin.info["external_url"]), - ) + text=text, + action=lambda: ba.open_url(self.plugin.info["external_url"]), + ) open_pos_x = (350 if _uiscale is ba.UIScale.SMALL else 410 if _uiscale is ba.UIScale.MEDIUM else 400) open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else From da000c3e3edacee3268bf56b46833093e223c870 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Wed, 8 Feb 2023 14:16:51 +0000 Subject: [PATCH 59/82] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index c2ba40e..a4c3e4b 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.2.3": null, + "0.2.3": { + "api_version": 7, + "commit_sha": "6e457da", + "released_on": "08-02-2023", + "md5sum": "a29c540dcaf533bcf039d3bf80704719" + }, "0.2.2": { "api_version": 7, "commit_sha": "2672a5a", From cb5df36b6d2511d78592ec56e3c049f600e8ce16 Mon Sep 17 00:00:00 2001 From: Sravan Kumar <42110198+kingsamurai123@users.noreply.github.com> Date: Sun, 12 Feb 2023 14:42:57 +0000 Subject: [PATCH 60/82] Bump the plugin manager version to 0.3.0 --- CHANGELOG.md | 2 +- index.json | 7 +------ plugin_manager.py | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d809d66..74d9aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## Plugin Manager (dd-mm-yyyy) -### 0.2.3 (31-01-2023) +### 0.3.0 (31-01-2023) - Displays a tutorial button in the plugin window, whenever there is a supported url present in the plugin data. diff --git a/index.json b/index.json index a4c3e4b..604f315 100644 --- a/index.json +++ b/index.json @@ -1,12 +1,7 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.2.3": { - "api_version": 7, - "commit_sha": "6e457da", - "released_on": "08-02-2023", - "md5sum": "a29c540dcaf533bcf039d3bf80704719" - }, + "0.3.0": null, "0.2.2": { "api_version": 7, "commit_sha": "2672a5a", diff --git a/plugin_manager.py b/plugin_manager.py index 6fd149e..7225598 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _env = _ba.env() _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.2.3" +PLUGIN_MANAGER_VERSION = "0.3.0" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" From 15f7a2e04e394e5da3a127818a1415ee0012e282 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Sun, 12 Feb 2023 14:46:45 +0000 Subject: [PATCH 61/82] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 604f315..35df60c 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.3.0": null, + "0.3.0": { + "api_version": 7, + "commit_sha": "cb5df36", + "released_on": "12-02-2023", + "md5sum": "d149fedf64b002c97fbb883ae5629d49" + }, "0.2.2": { "api_version": 7, "commit_sha": "2672a5a", From 820900d57464bab2e2a6c433f8fae3d9354ba18e Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 12 Feb 2023 21:54:07 +0530 Subject: [PATCH 62/82] Update 0.3.0 release date to when PR got merged --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74d9aa4..2900fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## Plugin Manager (dd-mm-yyyy) -### 0.3.0 (31-01-2023) +### 0.3.0 (12-02-2023) - Displays a tutorial button in the plugin window, whenever there is a supported url present in the plugin data. From 71479e5b5ea10796e66f611cbc3be7b8c9fafa05 Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 4 Mar 2023 13:01:48 +0530 Subject: [PATCH 63/82] Resize the window and buttons Resized the plugin window popup and also moved the buttons to limit the overlapping with the description. --- plugin_manager.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 7225598..2d9e419 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -816,9 +816,9 @@ class PluginWindow(popup.PopupWindow): play_sound() b_text_color = (0.75, 0.7, 0.8) - s = 1.1 if _uiscale is ba.UIScale.SMALL else 1.27 if ba.UIScale.MEDIUM else 1.57 + s = 1.25 if _uiscale is ba.UIScale.SMALL else 1.39 if ba.UIScale.MEDIUM else 1.67 width = 360 * s - height = 100 + 100 * s + height = 120 + 100 * s color = (1, 1, 1) text_scale = 0.7 * s self._transition_out = 'out_scale' @@ -933,10 +933,10 @@ class PluginWindow(popup.PopupWindow): ba.containerwidget(edit=self._root_widget, on_cancel_call=self._ok) - open_pos_x = (300 if _uiscale is ba.UIScale.SMALL else - 360 if _uiscale is ba.UIScale.MEDIUM else 350) - open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else - 110 if _uiscale is ba.UIScale.MEDIUM else 120) + open_pos_x = (350 if _uiscale is ba.UIScale.SMALL else + 410 if _uiscale is ba.UIScale.MEDIUM else 400) + open_pos_y = (125 if _uiscale is ba.UIScale.SMALL else + 135 if _uiscale is ba.UIScale.MEDIUM else 140) open_button = ba.buttonwidget(parent=self._root_widget, autoselect=True, position=(open_pos_x, open_pos_y), @@ -970,8 +970,8 @@ class PluginWindow(popup.PopupWindow): text=text, action=lambda: ba.open_url(self.plugin.info["external_url"]), ) - open_pos_x = (350 if _uiscale is ba.UIScale.SMALL else - 410 if _uiscale is ba.UIScale.MEDIUM else 400) + open_pos_x = (400 if _uiscale is ba.UIScale.SMALL else + 460 if _uiscale is ba.UIScale.MEDIUM else 450) open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else 110 if _uiscale is ba.UIScale.MEDIUM else 120) open_button = ba.buttonwidget(parent=self._root_widget, From 5623b018239e3d6ecca13706328c92f4c3f60ff7 Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 4 Mar 2023 13:05:16 +0530 Subject: [PATCH 64/82] Add changelog for 0.3.1 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2900fd8..9da6511 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.3.1 (04-03-2023) + +- Resize the plugin window to limit the overlapping of plugin description. + ### 0.3.0 (12-02-2023) - Displays a tutorial button in the plugin window, whenever there is a supported url present in the plugin data. From 2ff6d498344e023078e2943c97c6f34d1c64bedb Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 4 Mar 2023 13:28:23 +0530 Subject: [PATCH 65/82] Changed the version in PM and index Added the version change in PluginManager.py and index.json --- index.json | 1 + plugin_manager.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 35df60c..2eca77d 100644 --- a/index.json +++ b/index.json @@ -1,6 +1,7 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { + "0.3.1": null, "0.3.0": { "api_version": 7, "commit_sha": "cb5df36", diff --git a/plugin_manager.py b/plugin_manager.py index 2d9e419..e5de46a 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _env = _ba.env() _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.3.0" +PLUGIN_MANAGER_VERSION = "0.3.1" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" From c72879e91aedb8090527e9525a95c3e65c6344a9 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Sat, 4 Mar 2023 08:01:19 +0000 Subject: [PATCH 66/82] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 2eca77d..9987a70 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.3.1": null, + "0.3.1": { + "api_version": 7, + "commit_sha": "2ff6d49", + "released_on": "04-03-2023", + "md5sum": "48817d0411a6d1d98ed6cd971f0aa0e6" + }, "0.3.0": { "api_version": 7, "commit_sha": "cb5df36", From cedd1b150133cf86306b04d417c76bbcddfdeca2 Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 4 Mar 2023 15:40:01 +0530 Subject: [PATCH 67/82] Increase plugin window width Increased the plugin window size and moved the buttons to the left. --- plugin_manager.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index e5de46a..68d77c2 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -817,7 +817,7 @@ class PluginWindow(popup.PopupWindow): play_sound() b_text_color = (0.75, 0.7, 0.8) s = 1.25 if _uiscale is ba.UIScale.SMALL else 1.39 if ba.UIScale.MEDIUM else 1.67 - width = 360 * s + width = 400 * s height = 120 + 100 * s color = (1, 1, 1) text_scale = 0.7 * s @@ -933,8 +933,8 @@ class PluginWindow(popup.PopupWindow): ba.containerwidget(edit=self._root_widget, on_cancel_call=self._ok) - open_pos_x = (350 if _uiscale is ba.UIScale.SMALL else - 410 if _uiscale is ba.UIScale.MEDIUM else 400) + open_pos_x = (390 if _uiscale is ba.UIScale.SMALL else + 450 if _uiscale is ba.UIScale.MEDIUM else 440) open_pos_y = (125 if _uiscale is ba.UIScale.SMALL else 135 if _uiscale is ba.UIScale.MEDIUM else 140) open_button = ba.buttonwidget(parent=self._root_widget, @@ -970,8 +970,8 @@ class PluginWindow(popup.PopupWindow): text=text, action=lambda: ba.open_url(self.plugin.info["external_url"]), ) - open_pos_x = (400 if _uiscale is ba.UIScale.SMALL else - 460 if _uiscale is ba.UIScale.MEDIUM else 450) + open_pos_x = (440 if _uiscale is ba.UIScale.SMALL else + 500 if _uiscale is ba.UIScale.MEDIUM else 490) open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else 110 if _uiscale is ba.UIScale.MEDIUM else 120) open_button = ba.buttonwidget(parent=self._root_widget, From 43dcb2ef5df0535aa907c14a91769e2f0fed026d Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 4 Mar 2023 15:44:17 +0530 Subject: [PATCH 68/82] reset the hash --- index.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/index.json b/index.json index 9987a70..2eca77d 100644 --- a/index.json +++ b/index.json @@ -1,12 +1,7 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.3.1": { - "api_version": 7, - "commit_sha": "2ff6d49", - "released_on": "04-03-2023", - "md5sum": "48817d0411a6d1d98ed6cd971f0aa0e6" - }, + "0.3.1": null, "0.3.0": { "api_version": 7, "commit_sha": "cb5df36", From 2460e007de925b9bc9f5f8b0078ac931abe281cb Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Sat, 4 Mar 2023 10:15:06 +0000 Subject: [PATCH 69/82] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 2eca77d..f88daf7 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.3.1": null, + "0.3.1": { + "api_version": 7, + "commit_sha": "43dcb2e", + "released_on": "04-03-2023", + "md5sum": "fde604cd3789dfbeca74bc8e8d685fd8" + }, "0.3.0": { "api_version": 7, "commit_sha": "cb5df36", From 0b856baf34e22b92e4f2cf2d285c5f08b8088173 Mon Sep 17 00:00:00 2001 From: Sravan Date: Sat, 4 Mar 2023 18:15:08 +0530 Subject: [PATCH 70/82] Y-axis typo --- index.json | 7 +------ plugin_manager.py | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/index.json b/index.json index f88daf7..2eca77d 100644 --- a/index.json +++ b/index.json @@ -1,12 +1,7 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.3.1": { - "api_version": 7, - "commit_sha": "43dcb2e", - "released_on": "04-03-2023", - "md5sum": "fde604cd3789dfbeca74bc8e8d685fd8" - }, + "0.3.1": null, "0.3.0": { "api_version": 7, "commit_sha": "cb5df36", diff --git a/plugin_manager.py b/plugin_manager.py index 68d77c2..2c4664d 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -935,8 +935,8 @@ class PluginWindow(popup.PopupWindow): open_pos_x = (390 if _uiscale is ba.UIScale.SMALL else 450 if _uiscale is ba.UIScale.MEDIUM else 440) - open_pos_y = (125 if _uiscale is ba.UIScale.SMALL else - 135 if _uiscale is ba.UIScale.MEDIUM else 140) + open_pos_y = (100 if _uiscale is ba.UIScale.SMALL else + 110 if _uiscale is ba.UIScale.MEDIUM else 120) open_button = ba.buttonwidget(parent=self._root_widget, autoselect=True, position=(open_pos_x, open_pos_y), From 71e5d3a0b5dcb72f0ad5d342e64bdc79a78dbcd7 Mon Sep 17 00:00:00 2001 From: kingsamurai123 Date: Sat, 4 Mar 2023 12:47:12 +0000 Subject: [PATCH 71/82] [ci] apply-version-metadata --- index.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/index.json b/index.json index 2eca77d..8805e0f 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.3.1": null, + "0.3.1": { + "api_version": 7, + "commit_sha": "0b856ba", + "released_on": "04-03-2023", + "md5sum": "52fdce0f242b1bc52a1cbf2e7d78d230" + }, "0.3.0": { "api_version": 7, "commit_sha": "cb5df36", From 176e19b9d0c3252b34ec397947e66468cc112093 Mon Sep 17 00:00:00 2001 From: SEBASTIAN2059 Date: Sat, 29 Apr 2023 12:04:57 -0500 Subject: [PATCH 72/82] hot bomb minigame --- plugins/minigames.json | 19 + plugins/minigames/hot_bomb.py | 1646 +++++++++++++++++++++++++++++++++ 2 files changed, 1665 insertions(+) create mode 100644 plugins/minigames/hot_bomb.py diff --git a/plugins/minigames.json b/plugins/minigames.json index b1fb800..bca9635 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -249,6 +249,25 @@ "md5sum": "ec3980f3f3a5da96c27f4cbd61f98550" } } + }, + "hot_bomb": { + "description": "Get the bomb to explode on the enemy team to win.", + "external_url": "", + "authors": [ + { + "name": "SEBASTIAN2059", + "email": "", + "discord": "SEBASTIAN2059#5751" + }, + { + "name": "zPanxo", + "email": "", + "discord": "zPanxo#7201" + } + ], + "versions": { + "1.0.0": null + } } } } \ No newline at end of file diff --git a/plugins/minigames/hot_bomb.py b/plugins/minigames/hot_bomb.py new file mode 100644 index 0000000..a918e35 --- /dev/null +++ b/plugins/minigames/hot_bomb.py @@ -0,0 +1,1646 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Hot Bomb game by SEBASTIAN2059 and zPanxo""" + +# ba_meta require api 7 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import random + +import ba,_ba +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard +from bastd.actor.powerupbox import PowerupBoxFactory +from bastd.gameutils import SharedObjects +from ba._messages import StandMessage +from bastd.actor.bomb import Bomb +from bastd.actor.spaz import PickupMessage, BombDiedMessage + +if TYPE_CHECKING: + from typing import Any, Sequence, Dict, Type, List, Optional, Union + +class BallDiedMessage: + """Inform something that a ball has died.""" + + def __init__(self, ball: Ball): + self.ball = ball + +class ExplodeHitMessage: + """Tell an object it was hit by an explosion.""" + +class Ball(ba.Actor): + """A lovely bomb mortal""" + + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0),timer: int = 5,d_time=0.2,color=(1,1,1)): + super().__init__() + shared = SharedObjects.get() + activity = self.getactivity() + + self.explosion_material = ba.Material() + self.explosion_material.add_actions( + conditions=( + 'they_have_material', shared.object_material + ), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', ExplodeHitMessage()), + ), + ) + + ba.playsound(ba.getsound('scamper01'),volume=0.4) + # Spawn just above the provided point. + self._spawn_pos = (position[0], position[1] + 1.0, position[2]) + self.last_players_to_touch: Dict[int, Player] = {} + self.scored = False + assert activity is not None + assert isinstance(activity, HotBombGame) + pmats = [shared.object_material, activity.ball_material] + self.node = ba.newnode('prop', + delegate=self, + attrs={ + 'model': activity.ball_model, + 'color_texture': activity.ball_tex, + 'body': activity.ball_body, + 'body_scale': 1.0 if activity.ball_body == 'sphere' else 0.8, + 'density':1.0 if activity.ball_body == 'sphere' else 1.2, + 'reflection': 'soft', + 'reflection_scale': [0.2], + 'shadow_size': 0.5, + 'is_area_of_interest': True, + 'position': self._spawn_pos, + 'materials': pmats + } + ) + self._animate = None + self.scale = 1.0 if activity.ball_body == 'sphere' else 0.8 + + self.color_l = (1,1,1) + self.light = ba.newnode('light', + owner=self.node, + attrs={ + 'color':color, + 'volume_intensity_scale': 0.4, + 'intensity':0.5, + 'radius':0.10 + } + ) + self.node.connectattr('position', self.light,'position') + self.animate_light = None + + self._particles = ba.Timer(0.1,call=ba.WeakCall(self.particles),repeat=True) + self._sound_effect = ba.Timer(4,call=ba.WeakCall(self.sound_effect),repeat=True) + + self.d_time = d_time + + if timer is not None: + timer = int(timer) + self._timer = timer + self._counter: Optional[ba.Node] + if self._timer is not None: + self._count = self._timer + self._tick_timer = ba.Timer(1.0, + call=ba.WeakCall(self._tick), + repeat=True) + m = ba.newnode('math', owner=self.node, attrs={'input1': (0, 0.6, 0), 'operation': 'add'}) + self.node.connectattr('position', m, 'input2') + self._counter = ba.newnode( + 'text', + owner=self.node, + attrs={ + 'text':str(timer), + 'in_world':True, + 'shadow':1.0, + 'flatness':0.7, + 'color':(1,1,1), + 'scale':0.013, + 'h_align':'center' + } + ) + m.connectattr('output', self._counter, 'position') + else: + self._counter = None + + def particles(self): + if self.node: + ba.emitfx( + position=self.node.position, + velocity=(0,3,0), + count=9, + scale=2.5, + spread=0.2, + chunk_type='sweat' + ) + + def sound_effect(self): + if self.node: + ba.playsound(ba.getsound('scamper01'),volume=0.4) + + + def explode(self,color=(3,1,0)) -> None: + sound = random.choice(['explosion01','explosion02','explosion03','explosion04','explosion05']) + ba.playsound(ba.getsound(sound),volume=1) + ba.emitfx(position=self.node.position, + velocity=(0,10,0), + count=100, + scale=1.0, + spread=1.0, + chunk_type='spark') + explosion = ba.newnode( + 'explosion', + attrs={ + 'position': self.node.position, + 'velocity': (0,0,0), + 'radius': 2.0, + 'big': False, + 'color':color + } + ) + ba.timer(1.0,explosion.delete) + if color == (5,1,0): + color = (1,0,0) + self.activity._handle_score(1) + else: + color=(0,0,1) + self.activity._handle_score(0) + + scorch = ba.newnode( + 'scorch', + attrs={ + 'position': self.node.position, + 'size': 1.0, + 'big': True, + 'color':color, + 'presence':1 + } + ) + + # Set our position a bit lower so we throw more things upward. + rmats = (self.explosion_material,) + self.region = ba.newnode( + 'region', + delegate=self, + attrs={ + 'position': (self.node.position[0], self.node.position[1] - 0.1, self.node.position[2]), + 'scale': (2.0, 2.0, 2.0), + 'type': 'sphere', + 'materials': rmats + }, + ) + ba.timer(0.05, self.region.delete) + + def _tick(self) -> None: + c = self.color_l + c2 = (2.5,1.5,0) + if c[2] != 0: + c2 = (0,2,3) + if self.node: + if self._count == 1: + pos = self.node.position + color = (5,1,0) if pos[0] < 0 else (0,1,5) + self.explode(color=color) + return + if self._count > 0: + self._count -= 1 + assert self._counter + self._counter.text = str(self._count) + ba.playsound(ba.getsound('tick')) + if self._count == 1: + self._animate = ba.animate( + self.node, + 'model_scale', + { + 0:self.node.model_scale, + 0.1:1.5, + 0.2:self.scale + }, + loop=True + ) + self.animate_light = ba.animate_array( + self.light, + 'color', + 3, + { + 0:c, + 0.1:c2, + 0.2:c + }, + loop=True + ) + else: + self._animate = ba.animate( + self.node, + 'model_scale', + { + 0:self.node.model_scale, + 0.5:1.5, + 1.0:self.scale + }, + loop=True + ) + self.animate_light = ba.animate_array( + self.light, + 'color', + 3, + { + 0:c, + 0.2:c2, + 0.5:c, + 1.0:c + }, + loop=True + ) + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.DieMessage): + if not self.node: return + self.node.delete() + activity = self._activity() + if activity and not msg.immediate: + activity.handlemessage(BallDiedMessage(self)) + + # If we go out of bounds, move back to where we started. + elif isinstance(msg, ba.OutOfBoundsMessage): + assert self.node + self.node.position = self._spawn_pos + + elif isinstance(msg, ba.PickedUpMessage): + d = self.d_time + def damage(): + if (msg is not None and msg.node.exists() + and msg.node.getdelegate(PlayerSpaz).hitpoints > 0): + spaz = msg.node.getdelegate(PlayerSpaz) + spaz.node.color = (spaz.node.color[0]-0.1,spaz.node.color[1]-0.1,spaz.node.color[2]-0.1) + if spaz.node.hold_node != self.node: + self.handlemessage(ba.DroppedMessage(spaz.node)) + if spaz.hitpoints > 10000: + ba.playsound(ba.getsound('fuse01'),volume=0.3) + spaz.hitpoints -= 10000 + spaz._last_hit_time = None + spaz._num_time_shit = 0 + spaz.node.hurt = 1.0 - float(spaz.hitpoints) / spaz.hitpoints_max + else: + spaz.handlemessage(ba.DieMessage()) + ba.emitfx( + position=msg.node.position, + velocity=(0, 3, 0), + count=20 if d == 0.2 else 25 if d == 0.1 else 30 if d == 0.05 else 15, + scale=1.0, + spread=0.2, + chunk_type='sweat') + else: + self.damage_timer = None + + self.damage_timer = ba.Timer(self.d_time, damage, repeat=True) + + elif isinstance(msg, ba.DroppedMessage): + from ba import _math + spaz = msg.node.getdelegate(PlayerSpaz) + self.damage_timer = None + + elif isinstance(msg, ba.HitMessage): + assert self.node + assert msg.force_direction is not None + self.node.handlemessage( + 'impulse', msg.pos[0], msg.pos[1], msg.pos[2], msg.velocity[0], + msg.velocity[1], msg.velocity[2], 1.0 * msg.magnitude, + 1.0 * msg.velocity_magnitude, msg.radius, 0, + msg.force_direction[0], msg.force_direction[1], + msg.force_direction[2]) + + # If this hit came from a player, log them as the last to touch us. + s_player = msg.get_source_player(Player) + if s_player is not None: + activity = self._activity() + if activity: + if s_player in activity.players: + self.last_players_to_touch[s_player.team.id] = s_player + + elif isinstance(msg, ExplodeHitMessage): + node = ba.getcollision().opposingnode + if not self.node: return + nodepos = self.region.position + mag = 2000.0 + + node.handlemessage( + ba.HitMessage( + pos=nodepos, + velocity=(0, 0, 0), + magnitude=mag, + hit_type='explosion', + hit_subtype='normal', + radius=2.0 + ) + ) + self.handlemessage(ba.DieMessage()) + else: + super().handlemessage(msg) + +###HUMAN### +class NewPlayerSpaz(PlayerSpaz): + + move_mult = 1.0 + reload = True + extra_jump = True + ###calls + + def impulse(self): + self.reload = False + p = self.node + self.node.handlemessage( + "impulse", + p.position[0], p.position[1]+40, p.position[2], + 0, 0, 0, + 160, 0, 0, 0, + 0, 205, 0) + ba.timer(0.4,self.refresh) + + def refresh(self): + self.reload = True + + def drop_bomb(self) -> Optional[Bomb]: + + if (self.land_mine_count <= 0 and self.bomb_count <= 0) or self.frozen: + return None + assert self.node + pos = self.node.position_forward + vel = self.node.velocity + + if self.land_mine_count > 0: + dropping_bomb = False + self.set_land_mine_count(self.land_mine_count - 1) + bomb_type = 'land_mine' + else: + dropping_bomb = True + bomb_type = self.bomb_type + + if bomb_type == 'banana': + ba.playsound(ba.getsound('penguinHit1'),volume=0.3) + bomb = NewBomb(position=(pos[0], pos[1] + 0.7, pos[2]), + velocity=(vel[0], vel[1], vel[2]), + bomb_type = bomb_type, + radius = 1.0, + source_player=self.source_player, + owner=self.node) + else: + bomb = Bomb(position=(pos[0], pos[1] - 0.0, pos[2]), + velocity=(vel[0], vel[1], vel[2]), + bomb_type=bomb_type, + blast_radius=self.blast_radius, + source_player=self.source_player, + owner=self.node).autoretain() + + + assert bomb.node + if dropping_bomb: + self.bomb_count -= 1 + bomb.node.add_death_action( + ba.WeakCall(self.handlemessage, BombDiedMessage())) + self._pick_up(bomb.node) + + try: + for clb in self._dropped_bomb_callbacks: + clb(self, bomb) + except Exception: + return + + return bomb + + def on_jump_press(self) -> None: + if not self.node: + return + self.node.jump_pressed = True + self._turbo_filter_add_press('jump') + + if self.reload and self.extra_jump: + self.impulse() + + def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, PickupMessage): + if not self.node: + return None + try: + collision = ba.getcollision() + opposingnode = collision.opposingnode + opposingbody = collision.opposingbody + except ba.NotFoundError: + return True + if opposingnode.getnodetype() == 'spaz': + player = opposingnode.getdelegate(PlayerSpaz,True).getplayer(Player, True) + if player.actor.shield: + return None + super().handlemessage(msg) + return super().handlemessage(msg) + + +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + self.score = 0 + + +lang = ba.app.lang.language +if lang == 'Spanish': + name = 'Hot Bomb' + description = 'Consigue explotar la bomba en\nel equipo enemigo para ganar.' + join_description = 'Deshazte de la bomba cuanto antes.' + join_description_l = 'Deshazte de la bomba cuanto antes.' + view_description = 'Estalla la bomba en el equipo rival' + view_description_l = 'Estalla ${ARG1} veces la bomba en el equipo rival' + bomb_timer = 'Temporizador' + space_wall = 'Espacio Debajo de la Red' + num_bones = 'Huesos Distractores' + b_count = ['Nada','Pocos','Muchos'] + shield = 'Inmortalidad' + bomb = 'Habilitar Bananas' + boxing_gloves = 'Equipar Guantes de Boxeo' + difficulty = 'Dificultad' + difficulty_o = ['Fácil','Difícil','Chernobyl'] + wall_color = 'Color de la Red' + w_c = ['Verde','Rojo','Naranja','Amarillo','Celeste','Azul','Rosa','Gris'] + ball_body = 'Tipo de Hot Bomb' + body = ['Esfera','Cubo'] + +else: + name = 'Hot Bomb' + description = 'Get the bomb to explode on\nthe enemy team to win.' + join_description = 'Get rid of the bomb as soon as possible.' + join_description_l = 'Get rid of the bomb as soon as possible.' + view_description = 'Explode the bomb in the enemy team' + view_description_l = 'Explode the bomb ${ARG1} times in the enemy team' + bomb_timer = 'Timer' + space_wall = 'Space Under the Mesh' + num_bones = 'Distractor Bones' + b_count = ['None','Few','Many'] + shield = 'Immortality' + bomb = 'Enable Bananas' + difficulty = 'Difficulty' + difficulty_o = ['Easy','Hard','Chernobyl'] + wall_color = 'Mesh Color' + w_c = ['Green','Red','Orange','Yellow','Light blue','Blue','Ping','Gray'] + ball_body = 'Type of Hot Bomb' + body = ['Sphere','Box'] + + +# ba_meta export game +class HotBombGame(ba.TeamGameActivity[Player, Team]): + """New game.""" + + name = name + description = description + available_settings = [ + ba.IntSetting( + 'Score to Win', + min_value=1, + default=5, + increment=1, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 3.0), + ], + default=0.5, + + ), + ba.FloatChoiceSetting( + difficulty, + choices=[ + (difficulty_o[0], 0.15), + (difficulty_o[1], 0.04), + (difficulty_o[2], 0.01), + ], + default=0.15, + + ), + ba.IntChoiceSetting( + bomb_timer, + choices=[(str(choice)+'s',choice) for choice in range(2,11)], + default=5, + + ), + ba.IntChoiceSetting( + num_bones, + choices=[ + (b_count[0], 0), + (b_count[1], 2), + (b_count[2], 5), + ], + default=2, + + ), + ba.IntChoiceSetting( + ball_body, + choices=[(b, body.index(b)) for b in body], + default=0, + ), + ba.IntChoiceSetting( + wall_color, + choices=[(color,w_c.index(color)) for color in w_c], + default=0, + + ), + ba.BoolSetting('Epic Mode', default=False), + ba.BoolSetting(space_wall, default=True), + ba.BoolSetting(bomb, default=True), + ba.BoolSetting(shield, default=False), + + ] + default_music = ba.MusicType.HOCKEY + + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.DualTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ['Football Stadium'] + + def __init__(self, settings: dict): + super().__init__(settings) + self._bomb_timer = int(settings[bomb_timer]) + self._space_under_wall = bool(settings[space_wall]) + self._num_bones = int(settings[num_bones]) + self._shield = bool(settings[shield]) + self._bomb = bool(settings[bomb]) + self.damage_time = float(settings[difficulty]) + self._epic_mode = bool(settings['Epic Mode']) + self._wall_color = int(settings[wall_color]) + self._ball_body = int(settings[ball_body]) + + self.bodys = ['sphere','crate'] + self.models = ['bombSticky','powerupSimple'] + + shared = SharedObjects.get() + self._scoreboard = Scoreboard() + self._cheer_sound = ba.getsound('cheer') + self._chant_sound = ba.getsound('crowdChant') + self._foghorn_sound = ba.getsound('foghorn') + self._swipsound = ba.getsound('swip') + self._whistle_sound = ba.getsound('refWhistle') + self.ball_model = ba.getmodel(self.models[self._ball_body]) + self.ball_body = self.bodys[self._ball_body] + self.ball_tex = ba.gettexture('powerupCurse') + self._ball_sound = ba.getsound('splatter') + + self.last_point = None + self.colors = [(0.25,0.5,0.25), (1, 0.15, 0.15), (1, 0.5, 0), (1, 1, 0), + (0.2, 1, 1), (0.1, 0.1, 1), (1, 0.3, 0.5),(0.5, 0.5, 0.5)] + # + self.slow_motion = self._epic_mode + + self.ball_material = ba.Material() + self.ball_material.add_actions(actions=(('modify_part_collision', + 'friction', 0.5))) + self.ball_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', True)) + self.ball_material.add_actions( + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.ball_material.add_actions( + conditions=( + 'they_have_material',shared.footing_material + ), + actions=( + 'impact_sound',self._ball_sound, 0.2, 4 + ) + ) + + # Keep track of which player last touched the ball + self.ball_material.add_actions( + conditions=( + 'they_have_material', shared.player_material + ), + actions=( + ('call', 'at_connect',self._handle_ball_player_collide), + ) + ) + + # We want the ball to kill powerups; not get stopped by them + self.ball_material.add_actions( + conditions=( + 'they_have_material',PowerupBoxFactory.get().powerup_material), + actions=( + ('modify_part_collision', 'physical', False), + ('message', 'their_node', 'at_connect', ba.DieMessage()) + ) + ) + + self._score_region_material = ba.Material() + self._score_region_material.add_actions( + conditions=( + 'they_have_material', self.ball_material + ), + actions=( + ('modify_part_collision', 'collide',True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score) + ) + ) + ##### + self._check_region_material = ba.Material() + self._check_region_material.add_actions( + conditions=( + 'they_have_material', self.ball_material + ), + actions=( + ('modify_part_collision', 'collide',True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._reset_count) + ) + ) + + self._reaction_material = ba.Material() + self._reaction_material.add_actions( + conditions=( + 'they_have_material', shared.player_material + ), + actions=( + ('modify_part_collision', 'collide',True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._reaction) + ) + ) + + self._reaction_material.add_actions( + conditions=( + 'they_have_material', HealthFactory.get().health_material + ), + actions=( + ('modify_part_collision', 'collide',True), + ('modify_part_collision', 'physical', True) + ) + ) + + self._collide=ba.Material() + self._collide.add_actions( + conditions=( + ('they_are_different_node_than_us', ), + 'and', + ('they_have_material', shared.player_material), + ), + actions=( + ('modify_part_collision', 'collide', True) + ) + ) + + self._wall_material=ba.Material() + self._wall_material.add_actions( + conditions=( + 'we_are_older_than', 1 + ), + actions=( + ('modify_part_collision', 'collide', True) + ) + ) + + self.ice_material = ba.Material() + self.ice_material.add_actions( + actions=( + 'modify_part_collision','friction',0.05 + ) + ) + + self._ball_spawn_pos: Optional[Sequence[float]] = None + self._ball: Optional[Ball] = None + self._score_to_win = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + + def get_instance_description(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return join_description + return join_description_l, self._score_to_win + + def get_instance_description_short(self) -> Union[str, Sequence]: + if self._score_to_win == 1: + return view_description + return view_description_l, self._score_to_win + + def on_begin(self) -> None: + super().on_begin() + self.setup_standard_time_limit(self._time_limit) + self._ball_spawn_pos = (random.choice([-5,5]),4,0) + ba.timer(5,self._spawn_ball) + ba.timer(0.1,self.update_ball,repeat=True) + self.add_game_complements() + self.add_map_complements() + self._update_scoreboard() + ba.playsound(self._chant_sound) + + def _reaction(self): + node: ba.Node = ba.getcollision().opposingnode + ba.playsound(ba.getsound('hiss'),volume=0.75) + + node.handlemessage( + "impulse", + node.position[0],node.position[1],node.position[2], + -node.velocity[0]*2,-node.velocity[1],-node.velocity[2], + 100,100,0,0, + -node.velocity[0],-node.velocity[1],-node.velocity[2] + ) + + ba.emitfx( + position=node.position, + count=20, + scale=1.5, + spread=0.5, + chunk_type='sweat' + ) + + def add_game_complements(self): + HealthBox( + position=(-1,3.5,-5+random.random()*10) + ) + HealthBox( + position=(1,3.5,-5+random.random()*10) + ) + ### + g = 0 + while g < self._num_bones: + b = 0 + Torso( + position=(-6+random.random()*12,3.5,-5+random.random()*10) + ) + while b < 6: + Bone( + position=(-6+random.random()*12,2,-5+random.random()*10), + style=b + ) + b += 1 + g += 1 + ######################## + self.wall_color = self.colors[self._wall_color] + part_of_wall = ba.newnode( + 'locator', + attrs={ + 'shape':'box', + 'position':(-7.169,0.5,0.5), + 'color':self.wall_color, + 'opacity':1, + 'drawShadow':False, + 'draw_beauty':True, + 'additive':False, + 'size':[14.7,2,16] + } + ) + part_of_wall2 = ba.newnode( + 'locator', + attrs={ + 'shape':'box', + 'position':(0,-13.51,0.5) if self._space_under_wall else (0,-35.540,0.5), + 'color':self.wall_color, + 'opacity':1, + 'drawShadow':False, + 'draw_beauty':True, + 'additive':False, + 'size':[0.3,30,13] if self._space_under_wall else [0.3,75,13] + } + ) + wall = ba.newnode( + 'region', + attrs={ + 'position': (0,1.11,0.5) if self._space_under_wall else (0,0.75,0.5), + 'scale': (0.3,0.75,13) if self._space_under_wall else (0.3,1.5,13), + 'type': 'box', + 'materials': (self._wall_material,self._reaction_material) + } + ) + # RESET REGION + pos = (0,5.3,0) + ba.newnode( + 'region', + attrs={ + 'position': pos, + 'scale': (0.001,15,12), + 'type': 'box', + 'materials': [self._check_region_material,self._reaction_material] + } + ) + + ba.newnode( + 'region', + attrs={ + 'position': pos, + 'scale': (0.3,15,12), + 'type': 'box', + 'materials': [self._collide] + } + ) + + def add_map_complements(self): + #TEXT + text = ba.newnode('text', + attrs={'position':(0,2.5,-6), + 'text':'Hot Bomb by\nSEBASTIAN2059 and zPanxo', + 'in_world':True, + 'shadow':1.0, + 'flatness':0.7, + 'color':(1.91,1.31,0.59), + 'opacity':0.25-0.15, + 'scale':0.013+0.007, + 'h_align':'center'}) + walls_data = { + 'w1':[ + (11,5.5,0), + (4.5,11,13) + ], + 'w2':[ + (-11,5.5,0), + (4.5,11,13) + ], + 'w3':[ + (0,5.5,-6.1), + (19,11,1) + ], + 'w4':[ + (0,5.5,6.5), + (19,11,1) + ], + } + for i in walls_data: + w = ba.newnode( + 'region', + attrs={ + 'position': walls_data[i][0], + 'scale': walls_data[i][1], + 'type': 'box', + 'materials': (self._wall_material,) + } + ) + + for i in [-5,-2.5,0,2.5,5]: + pos = (11,6.5,0) + Box( + position=(pos[0]-0.5,pos[1]-5.5,pos[2]+i), + texture='powerupPunch' + ) + Box( + position=(pos[0]-0.5,pos[1]-3,pos[2]+i), + texture='powerupPunch' + ) + Box( + position=(pos[0]-0.5,pos[1]-0.5,pos[2]+i), + texture='powerupPunch' + ) + pos = (-11,6.5,0) + Box( + position=(pos[0]+0.5,pos[1]-5.5,pos[2]+i), + texture='powerupIceBombs' + ) + Box( + position=(pos[0]+0.5,pos[1]-3,pos[2]+i), + texture='powerupIceBombs' + ) + Box( + position=(pos[0]+0.5,pos[1]-0.5,pos[2]+i), + texture='powerupIceBombs' + ) + + def spawn_player(self, player: Player) -> ba.Actor: + position = self.get_position(player) + name = player.getname() + display_color = _ba.safecolor(player.color, target_intensity=0.75) + actor = NewPlayerSpaz( + color=player.color, + highlight=player.highlight, + character=player.character, + player=player + ) + player.actor = actor + + player.actor.node.name = name + player.actor.node.name_color = display_color + player.actor.bomb_type_default = 'banana' + player.actor.bomb_type = 'banana' + + actor.connect_controls_to_player(enable_punch=True, + enable_bomb=self._bomb, + enable_pickup=True) + actor.node.hockey = True + actor.hitpoints_max = 100000 + actor.hitpoints = 100000 + actor.equip_boxing_gloves() + if self._shield: + actor.equip_shields() + actor.shield.color = (0,0,0) + actor.shield.radius = 0.1 + actor.shield_hitpoints = actor.shield_hitpoints_max = 100000 + + #Move to the stand position and add a flash of light. + actor.handlemessage( + StandMessage( + position, + random.uniform(0, 360))) + ba.playsound(ba.getsound('spawn'),volume=0.6) + return actor + + def on_team_join(self, team: Team) -> None: + self._update_scoreboard() + + def _handle_ball_player_collide(self) -> None: + collision = ba.getcollision() + try: + ball = collision.sourcenode.getdelegate(Ball, True) + player = collision.opposingnode.getdelegate(PlayerSpaz,True).getplayer(Player, True) + except ba.NotFoundError: + return + + ball.last_players_to_touch[player.team.id] = player + + def _kill_ball(self) -> None: + self._ball = None + + def _reset_count(self) -> None: + """reset counter of ball.""" + + assert self._ball is not None + + if self._ball.scored: + return + + ba.playsound(ba.getsound('laser')) + self._ball._count = self._bomb_timer + self._ball._counter.text = str(self._bomb_timer) + self._ball._tick_timer = ba.Timer( + 1.0, + call=ba.WeakCall(self._ball._tick), + repeat=True + ) + self._ball._animate = ba.animate( + self._ball.node, + 'model_scale', + { + 0:self._ball.node.model_scale, + 0.1:self._ball.scale + } + ) + if self._ball.light.color[0] == 0: + self._ball.light.color = (2,0,0) + else: + self._ball.light.color = (0,0,3) + + def update_ball(self): + if not self._ball: return + if not self._ball.node: return + gnode = ba.getactivity().globalsnode + + if self._ball.node.position[0] > 0: + self._ball.node.color_texture = ba.gettexture('powerupIceBombs') + ba.animate_array(gnode,'vignette_outer',3,{1.0:(0.4, 0.4, 0.9)}) + self._ball.color_l = (0,0,3.5) + self._ball._counter.color = (0,0,5) + else: + self._ball.node.color_texture = ba.gettexture('powerupPunch') + ba.animate_array(gnode,'vignette_outer',3,{1.0:(0.6,0.45,0.45)}) + self._ball.color_l = (2.5,0,0) + self._ball._counter.color = (1.2,0,0) + + def _handle_score(self,index=0) -> None: + """A point has been scored.""" + + assert self._ball is not None + + for team in self.teams: + if team.id == index: + scoring_team = team + team.score += 1 + if index == 0: + self.last_point = 0 + else: + self.last_point = 1 + + # Tell all players to celebrate. + for player in team.players: + if player.actor: + player.actor.handlemessage(ba.CelebrateMessage(2.0)) + + # If we've got the player from the scoring team that last + # touched us, give them points. + if (scoring_team.id in self._ball.last_players_to_touch + and self._ball.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._ball.last_players_to_touch[scoring_team.id], + 100, + big_message=True) + + # End game if we won. + if team.score >= self._score_to_win: + self.end_game() + + elif team.id != index: + + # Tell all players to celebrate. + for player in team.players: + if player.actor: + player.actor.handlemessage(ba.DieMessage()) + + ba.playsound(self._foghorn_sound) + ba.playsound(self._cheer_sound) + + ba.cameraflash(duration=10.0) + self._update_scoreboard() + + def end_game(self) -> None: + results = ba.GameResults() + for team in self.teams: + results.set_team_score(team, team.score) + self.end(results=results) + + def _update_scoreboard(self) -> None: + winscore = self._score_to_win + for team in self.teams: + self._scoreboard.set_team_value(team, team.score, winscore) + + def handlemessage(self, msg: Any) -> Any: + + # Respawn dead players if they're still in the game. + if isinstance(msg, ba.PlayerDiedMessage): + + player = msg.getplayer(Player) + spaz = player.actor + spaz.node.color = (-1,-1,-1) + spaz.node.color_mask_texture = ba.gettexture('bonesColorMask') + spaz.node.color_texture = ba.gettexture('bonesColor') + spaz.node.head_model = ba.getmodel('bonesHead') + spaz.node.hand_model = ba.getmodel('bonesHand') + spaz.node.torso_model = ba.getmodel('bonesTorso') + spaz.node.pelvis_model = ba.getmodel('bonesPelvis') + spaz.node.upper_arm_model = ba.getmodel('bonesUpperArm') + spaz.node.forearm_model = ba.getmodel('bonesForeArm') + spaz.node.upper_leg_model = ba.getmodel('bonesUpperLeg') + spaz.node.lower_leg_model = ba.getmodel('bonesLowerLeg') + spaz.node.toes_model = ba.getmodel('bonesToes') + spaz.node.style = 'bones' + # Augment standard behavior... + super().handlemessage(msg) + self.respawn_player(msg.getplayer(Player)) + + # Respawn dead balls. + elif isinstance(msg, BallDiedMessage): + if not self.has_ended(): + try: + if self._ball._count == 1: + ba.timer(3.0, self._spawn_ball) + except Exception: + return + else: + super().handlemessage(msg) + + def _flash_ball_spawn(self,pos,color=(1,0,0)) -> None: + light = ba.newnode('light', + attrs={ + 'position': pos, + 'height_attenuated': False, + 'color': color + }) + ba.animate(light, 'intensity', {0.0: 0, 0.25: 0.2, 0.5: 0}, loop=True) + ba.timer(1.0, light.delete) + + def _spawn_ball(self) -> None: + timer = self._bomb_timer + ba.playsound(self._swipsound) + ba.playsound(self._whistle_sound) + pos = (random.choice([5,-5]),2,0) + if self.last_point != None: + if self.last_point == 0: + pos = (-5,2,0) + else: + pos = (5,2,0) + + color = (0,0,1*2) if pos[0] == 5 else (1*1.5,0,0) + texture = 'powerupPunch' if pos[0] == -5 else 'powerupIceBombs' + counter_color = (1,0,0) if pos[0] == -5 else (0,0,5) + #self._flash_ball_spawn(pos,color) + self._ball = Ball(position=pos,timer=timer,d_time=self.damage_time,color=color) + self._ball.node.color_texture = ba.gettexture(texture) + self._ball._counter.color = counter_color + + def get_position(self, player: Player) -> ba.Actor: + position = (0,1,0) + team = player.team.id + if team == 0: + position = (random.randint(-7,-3),0.25,random.randint(-5,5)) + angle = 90 + else: + position = (random.randint(3,7),0.25,random.randint(-5,5)) + angle = 270 + return position + + def respawn_player(self, + player: PlayerType, + respawn_time: Optional[float] = None) -> None: + import _ba + from ba._general import Call, WeakCall + + assert player + if respawn_time is None: + respawn_time = 3.0 + + # If this standard setting is present, factor it in. + if 'Respawn Times' in self.settings_raw: + respawn_time *= self.settings_raw['Respawn Times'] + + # We want whole seconds. + assert respawn_time is not None + respawn_time = round(max(1.0, respawn_time), 0) + + if player.actor and not self.has_ended(): + from bastd.actor.respawnicon import RespawnIcon + player.customdata['respawn_timer'] = _ba.Timer( + respawn_time, WeakCall(self.spawn_player_if_exists, player)) + player.customdata['respawn_icon'] = RespawnIcon( + player, respawn_time) + + def spawn_player_if_exists(self, player: PlayerType) -> None: + """ + A utility method which calls self.spawn_player() *only* if the + ba.Player provided still exists; handy for use in timers and whatnot. + + There is no need to override this; just override spawn_player(). + """ + if player: + self.spawn_player(player) + + + def spawn_player_spaz(self, player: PlayerType) -> None: + position = (0,1,0) + angle = None + team = player.team.id + if team == 0: + position = (random.randint(-7,-3),0.25,random.randint(-5,5)) + angle = 90 + else: + position = (random.randint(3,7),0.25,random.randint(-5,5)) + angle = 270 + + return super().spawn_player_spaz(player, position, angle) + +#####New-Bomb##### +class ExplodeMessage: + """Tells an object to explode.""" + +class ImpactMessage: + """Tell an object it touched something.""" + +class NewBomb(ba.Actor): + + def __init__(self, position: Sequence[float] = (0, 1, 0), + velocity: Sequence[float] = (0, 0, 0), + bomb_type: str = '', + radius: float = 2.0, + source_player: ba.Player = None, + owner: ba.Node = None): + + super().__init__() + + shared = SharedObjects.get() + # Material for powerups. + self.bomb_material = ba.Material() + self.explode_material = ba.Material() + + self.bomb_material.add_actions( + conditions=( + ('we_are_older_than', 200), + 'and', + ('they_are_older_than', 200), + 'and', + ('eval_colliding', ), + 'and', + ( + ('they_have_material', shared.footing_material), + 'or', + ('they_have_material', shared.object_material), + ), + ), + actions=('message', 'our_node', 'at_connect', ImpactMessage())) + + self.explode_material.add_actions( + conditions=('they_have_material', + shared.player_material), + actions=(('modify_part_collision', 'collide',True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._touch_player))) + + self._source_player = source_player + self.owner = owner + self.bomb_type = bomb_type + self.radius = radius + + owner_color = self.owner.source_player._team.color + + if self.bomb_type == 'banana': + self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ + 'position': position, + 'velocity': velocity, + 'color_texture': ba.gettexture('powerupBomb'), + 'model': ba.getmodel('penguinTorso'), + 'model_scale':0.7, + 'body_scale':0.7, + 'density':3, + 'reflection': 'soft', + 'reflection_scale': [1.0], + 'shadow_size': 0.3, + 'body': 'sphere', + 'owner': owner, + 'materials': (shared.object_material,self.bomb_material)}) + + ba.animate(self.node,'model_scale',{0:0,0.2:1,0.26:0.7}) + self.light = ba.newnode('light', owner=self.node, attrs={ + 'color':owner_color, + 'volume_intensity_scale': 2.0, + 'intensity':1, + 'radius':0.1}) + self.node.connectattr('position', self.light,'position') + + self.spawn: ba.Timer = ba.Timer( + 10.0,self._check,repeat=True) + + def _impact(self) -> None: + node = ba.getcollision().opposingnode + node_delegate = node.getdelegate(object) + if node: + if (node is self.owner): + return + self.handlemessage(ExplodeMessage()) + + + def _explode(self): + if self.node: + # Set our position a bit lower so we throw more things upward. + + pos = self.node.position + rmats = (self.explode_material,) + self.explode_region = ba.newnode( + 'region', + delegate=self, + attrs={ + 'position': (pos[0], pos[1] - 0.1, pos[2]), + 'scale': (self.radius, self.radius, self.radius), + 'type': 'sphere', + 'materials': rmats + }, + ) + if self.bomb_type == 'banana': + ba.playsound(ba.getsound('stickyImpact'),volume=0.35) + a = ba.emitfx(position=self.node.position, + velocity=(0,1,0), + count=15, + scale=1.0, + spread=0.1, + chunk_type='spark') + scorch = ba.newnode('scorch', + attrs={ + 'position': self.node.position, + 'size': 1.0, + 'big': False, + 'color':(1,1,0) + }) + + ba.animate(scorch,'size',{0:1.0,5:0}) + ba.timer(5,scorch.delete) + + + ba.timer(0.05, self.explode_region.delete) + ba.timer(0.001, ba.WeakCall(self.handlemessage, ba.DieMessage())) + + def _touch_player(self): + node = ba.getcollision().opposingnode + collision = ba.getcollision() + try: + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: + return + + if self.bomb_type == 'banana': + color = player.team.color + owner_team = self.owner.source_player._team + if (node is self.owner): + return + if player.team == owner_team: + return + player.actor.node.handlemessage('knockout', 500.0) + ba.animate_array(player.actor.node,'color',3,{0:color,0.1:(1.5,1,0),0.5:(1.5,1,0),0.6:color}) + + def _check(self) -> None: + """Prevent the cube from annihilating.""" + + def handlemessage(self, msg): + if isinstance(msg, ExplodeMessage): + self._explode() + elif isinstance(msg, ImpactMessage): + self._impact() + elif isinstance(msg, ba.DieMessage): + if self.node: + self.node.delete() + elif isinstance(msg, ba.OutOfBoundsMessage): + if self.node: + self.node.delete() + +######Object##### +class HealthFactory: + """Wraps up media and other resources used by ba.Bombs. + + category: Gameplay Classes + + A single instance of this is shared between all bombs + and can be retrieved via bastd.actor.bomb.get_factory(). + + Attributes: + + health_model + The ba.Model of a standard health. + + health_tex + The ba.Texture for health. + + activate_sound + A ba.Sound for an activating ??. + + health_material + A ba.Material applied to health. + """ + + _STORENAME = ba.storagename() + + @classmethod + def get(cls) -> HealthFactory: + """Get/create a shared EggFactory object.""" + activity = ba.getactivity() + factory = activity.customdata.get(cls._STORENAME) + if factory is None: + factory = HealthFactory() + activity.customdata[cls._STORENAME] = factory + assert isinstance(factory, HealthFactory) + return factory + + + + def __init__(self) -> None: + """Instantiate a BombFactory. + + You shouldn't need to do this; call get_factory() + to get a shared instance. + """ + shared = SharedObjects.get() + + self.health_model = ba.getmodel('egg') + + self.health_tex = ba.gettexture('eggTex1') + + self.health_sound = ba.getsound('activateBeep') + + # Set up our material so new bombs don't collide with objects + # that they are initially overlapping. + self.health_material = ba.Material() + + self.health_material.add_actions( + conditions=( + ( + ('we_are_younger_than', 100), + 'or', + ('they_are_younger_than', 100), + ), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + + # We want pickup materials to always hit us even if we're currently + # not colliding with their node. (generally due to the above rule) + self.health_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=('modify_part_collision', 'use_node_collide', False), + ) + + self.health_material.add_actions(actions=('modify_part_collision', + 'friction', 0.3)) + +class HealthBox(ba.Actor): + + def __init__(self, position: Sequence[float] = (0, 1, 0), + velocity: Sequence[float] = (0, 0, 0), + texture: str = 'powerupHealth'): + super().__init__() + + shared = SharedObjects.get() + factory = HealthFactory.get() + self.healthbox_material = ba.Material() + self.healthbox_material.add_actions( + conditions=( + 'they_are_different_node_than_us', + ), + actions=( + ('modify_part_collision', 'collide', True) + ) + ) + self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ + 'position': position, + 'velocity': velocity, + 'color_texture': ba.gettexture(texture), + 'model': ba.getmodel('powerup'), + 'light_model':ba.getmodel('powerupSimple'), + 'model_scale':1, + 'body': 'crate', + 'body_scale':1, + 'density':1, + 'damping':0, + 'gravity_scale':1, + 'reflection': 'powerup', + 'reflection_scale': [0.5], + 'shadow_size': 0.0, + 'materials': (shared.object_material,self.healthbox_material,factory.health_material)}) + + self.light = ba.newnode('light', owner=self.node, attrs={ + 'color':(1,1,1), + 'volume_intensity_scale': 0.4, + 'intensity':0.7, + 'radius':0.0}) + self.node.connectattr('position', self.light,'position') + + self.spawn: ba.Timer = ba.Timer( + 10.0,self._check,repeat=True) + + def _check(self) -> None: + """Prevent the cube from annihilating.""" + + def handlemessage(self, msg): + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.delete() + + elif isinstance(msg, ba.OutOfBoundsMessage): + if self.node: + self.node.delete() + elif isinstance(msg, ba.HitMessage): + try: + spaz = msg._source_player + spaz.actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) + t_color = spaz.team.color + spaz.actor.node.color = t_color + ba.playsound(ba.getsound('healthPowerup'),volume=0.5) + ba.animate(self.light,'radius',{0:0.0,0.1:0.2,0.7:0}) + except: + pass + + elif isinstance(msg, ba.DroppedMessage): + spaz = msg.node.getdelegate(PlayerSpaz) + self.regen_timer = None + +class Torso(ba.Actor): + + def __init__(self, position: Sequence[float] = (0, 1, 0), + velocity: Sequence[float] = (0, 0, 0), + texture: str = 'bonesColor'): + super().__init__() + + shared = SharedObjects.get() + + self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ + 'position': position, + 'velocity': velocity, + 'color_texture': ba.gettexture(texture), + 'model': ba.getmodel('bonesTorso'), + 'model_scale':1, + 'body': 'sphere', + 'body_scale':0.5, + 'density':6, + 'damping':0, + 'gravity_scale':1, + 'reflection': 'soft', + 'reflection_scale': [0], + 'shadow_size': 0.0, + 'materials': (shared.object_material,)}) + + self.spawn: ba.Timer = ba.Timer( + 10.0,self._check,repeat=True) + + def _check(self) -> None: + """Prevent the cube from annihilating.""" + + def handlemessage(self, msg): + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.delete() + + elif isinstance(msg, ba.OutOfBoundsMessage): + if self.node: + self.node.delete() + +class Bone(ba.Actor): + + def __init__(self, position: Sequence[float] = (0, 1, 0), + velocity: Sequence[float] = (0, 0, 0), + texture: str = 'bonesColor', + style: int = 0): + super().__init__() + + shared = SharedObjects.get() + models = ['bonesUpperArm','bonesUpperLeg','bonesForeArm','bonesPelvis','bonesToes','bonesHand'] + bone = None + model = 0 + for i in models: + if model == style: + bone = models[model] + else: + model += 1 + self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ + 'position': position, + 'velocity': velocity, + 'color_texture': ba.gettexture(texture), + 'model': ba.getmodel(bone), + 'model_scale':1.5, + 'body': 'crate', + 'body_scale':0.6, + 'density':2, + 'damping':0, + 'gravity_scale':1, + 'reflection': 'soft', + 'reflection_scale': [0], + 'shadow_size': 0.0, + 'materials': (shared.object_material,)}) + + self.spawn: ba.Timer = ba.Timer( + 10.0,self._check,repeat=True) + + def _check(self) -> None: + """Prevent the cube from annihilating.""" + + def handlemessage(self, msg): + if isinstance(msg, ba.DieMessage): + if self.node: + self.node.delete() + + elif isinstance(msg, ba.OutOfBoundsMessage): + if self.node: + self.node.delete() + +######Object##### +class Box(ba.Actor): + + def __init__(self, position: Sequence[float] = (0, 1, 0), + velocity: Sequence[float] = (0, 0, 0), + texture: str = 'powerupCurse'): + super().__init__() + + shared = SharedObjects.get() + self.dont_collide=ba.Material() + self.dont_collide.add_actions( + conditions=( + 'they_are_different_node_than_us', + ), + actions=( + ('modify_part_collision', 'collide', False) + ) + ) + + self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ + 'position': position, + 'velocity': velocity, + 'color_texture': ba.gettexture(texture), + 'model': ba.getmodel('powerup'), + 'light_model': ba.getmodel('powerupSimple'), + 'model_scale':4, + 'body': 'box', + 'body_scale':3, + 'density':9999, + 'damping':9999, + 'gravity_scale':0, + 'reflection': 'soft', + 'reflection_scale': [0.25], + 'shadow_size': 0.0, + 'materials': [self.dont_collide,]}) \ No newline at end of file From 095a77331cba4e1aeaf1d1897fad5c3057be9e08 Mon Sep 17 00:00:00 2001 From: SEBASTIAN2059 Date: Sat, 29 Apr 2023 17:16:42 +0000 Subject: [PATCH 73/82] [ci] auto-format --- plugins/minigames/hot_bomb.py | 950 +++++++++++++++++----------------- 1 file changed, 485 insertions(+), 465 deletions(-) diff --git a/plugins/minigames/hot_bomb.py b/plugins/minigames/hot_bomb.py index a918e35..66a81c6 100644 --- a/plugins/minigames/hot_bomb.py +++ b/plugins/minigames/hot_bomb.py @@ -11,7 +11,8 @@ from typing import TYPE_CHECKING import random -import ba,_ba +import ba +import _ba from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard from bastd.actor.powerupbox import PowerupBoxFactory @@ -23,36 +24,39 @@ from bastd.actor.spaz import PickupMessage, BombDiedMessage if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union + class BallDiedMessage: """Inform something that a ball has died.""" def __init__(self, ball: Ball): self.ball = ball + class ExplodeHitMessage: """Tell an object it was hit by an explosion.""" + class Ball(ba.Actor): """A lovely bomb mortal""" - def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0),timer: int = 5,d_time=0.2,color=(1,1,1)): + def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0), timer: int = 5, d_time=0.2, color=(1, 1, 1)): super().__init__() shared = SharedObjects.get() activity = self.getactivity() - + self.explosion_material = ba.Material() self.explosion_material.add_actions( conditions=( 'they_have_material', shared.object_material - ), + ), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('message', 'our_node', 'at_connect', ExplodeHitMessage()), ), ) - - ba.playsound(ba.getsound('scamper01'),volume=0.4) + + ba.playsound(ba.getsound('scamper01'), volume=0.4) # Spawn just above the provided point. self._spawn_pos = (position[0], position[1] + 1.0, position[2]) self.last_players_to_touch: Dict[int, Player] = {} @@ -67,36 +71,36 @@ class Ball(ba.Actor): 'color_texture': activity.ball_tex, 'body': activity.ball_body, 'body_scale': 1.0 if activity.ball_body == 'sphere' else 0.8, - 'density':1.0 if activity.ball_body == 'sphere' else 1.2, + 'density': 1.0 if activity.ball_body == 'sphere' else 1.2, 'reflection': 'soft', 'reflection_scale': [0.2], 'shadow_size': 0.5, 'is_area_of_interest': True, 'position': self._spawn_pos, 'materials': pmats - } - ) - self._animate = None + } + ) + self._animate = None self.scale = 1.0 if activity.ball_body == 'sphere' else 0.8 - - self.color_l = (1,1,1) + + self.color_l = (1, 1, 1) self.light = ba.newnode('light', - owner=self.node, + owner=self.node, attrs={ - 'color':color, + 'color': color, 'volume_intensity_scale': 0.4, - 'intensity':0.5, - 'radius':0.10 - } + 'intensity': 0.5, + 'radius': 0.10 + } ) - self.node.connectattr('position', self.light,'position') + self.node.connectattr('position', self.light, 'position') self.animate_light = None - - self._particles = ba.Timer(0.1,call=ba.WeakCall(self.particles),repeat=True) - self._sound_effect = ba.Timer(4,call=ba.WeakCall(self.sound_effect),repeat=True) + + self._particles = ba.Timer(0.1, call=ba.WeakCall(self.particles), repeat=True) + self._sound_effect = ba.Timer(4, call=ba.WeakCall(self.sound_effect), repeat=True) self.d_time = d_time - + if timer is not None: timer = int(timer) self._timer = timer @@ -106,102 +110,103 @@ class Ball(ba.Actor): self._tick_timer = ba.Timer(1.0, call=ba.WeakCall(self._tick), repeat=True) - m = ba.newnode('math', owner=self.node, attrs={'input1': (0, 0.6, 0), 'operation': 'add'}) + m = ba.newnode('math', owner=self.node, attrs={ + 'input1': (0, 0.6, 0), 'operation': 'add'}) self.node.connectattr('position', m, 'input2') self._counter = ba.newnode( - 'text', - owner=self.node, - attrs={ - 'text':str(timer), - 'in_world':True, - 'shadow':1.0, - 'flatness':0.7, - 'color':(1,1,1), - 'scale':0.013, - 'h_align':'center' - } - ) + 'text', + owner=self.node, + attrs={ + 'text': str(timer), + 'in_world': True, + 'shadow': 1.0, + 'flatness': 0.7, + 'color': (1, 1, 1), + 'scale': 0.013, + 'h_align': 'center' + } + ) m.connectattr('output', self._counter, 'position') else: self._counter = None - + def particles(self): if self.node: ba.emitfx( position=self.node.position, - velocity=(0,3,0), + velocity=(0, 3, 0), count=9, scale=2.5, spread=0.2, chunk_type='sweat' - ) - + ) + def sound_effect(self): if self.node: - ba.playsound(ba.getsound('scamper01'),volume=0.4) - - - def explode(self,color=(3,1,0)) -> None: - sound = random.choice(['explosion01','explosion02','explosion03','explosion04','explosion05']) - ba.playsound(ba.getsound(sound),volume=1) + ba.playsound(ba.getsound('scamper01'), volume=0.4) + + def explode(self, color=(3, 1, 0)) -> None: + sound = random.choice(['explosion01', 'explosion02', + 'explosion03', 'explosion04', 'explosion05']) + ba.playsound(ba.getsound(sound), volume=1) ba.emitfx(position=self.node.position, - velocity=(0,10,0), - count=100, - scale=1.0, - spread=1.0, - chunk_type='spark') + velocity=(0, 10, 0), + count=100, + scale=1.0, + spread=1.0, + chunk_type='spark') explosion = ba.newnode( - 'explosion', - attrs={ - 'position': self.node.position, - 'velocity': (0,0,0), - 'radius': 2.0, - 'big': False, - 'color':color - } - ) - ba.timer(1.0,explosion.delete) - if color == (5,1,0): - color = (1,0,0) + 'explosion', + attrs={ + 'position': self.node.position, + 'velocity': (0, 0, 0), + 'radius': 2.0, + 'big': False, + 'color': color + } + ) + ba.timer(1.0, explosion.delete) + if color == (5, 1, 0): + color = (1, 0, 0) self.activity._handle_score(1) else: - color=(0,0,1) + color = (0, 0, 1) self.activity._handle_score(0) scorch = ba.newnode( - 'scorch', - attrs={ - 'position': self.node.position, - 'size': 1.0, - 'big': True, - 'color':color, - 'presence':1 - } - ) - + 'scorch', + attrs={ + 'position': self.node.position, + 'size': 1.0, + 'big': True, + 'color': color, + 'presence': 1 + } + ) + # Set our position a bit lower so we throw more things upward. rmats = (self.explosion_material,) self.region = ba.newnode( - 'region', - delegate=self, - attrs={ - 'position': (self.node.position[0], self.node.position[1] - 0.1, self.node.position[2]), - 'scale': (2.0, 2.0, 2.0), - 'type': 'sphere', - 'materials': rmats - }, - ) + 'region', + delegate=self, + attrs={ + 'position': (self.node.position[0], self.node.position[1] - 0.1, self.node.position[2]), + 'scale': (2.0, 2.0, 2.0), + 'type': 'sphere', + 'materials': rmats + }, + ) ba.timer(0.05, self.region.delete) - + def _tick(self) -> None: c = self.color_l - c2 = (2.5,1.5,0) + c2 = (2.5, 1.5, 0) if c[2] != 0: - c2 = (0,2,3) + c2 = (0, 2, 3) if self.node: - if self._count == 1: + if self._count == 1: pos = self.node.position - color = (5,1,0) if pos[0] < 0 else (0,1,5) + color = (5, 1, 0) if pos[0] < 0 else (0, 1, 5) self.explode(color=color) return if self._count > 0: @@ -211,53 +216,54 @@ class Ball(ba.Actor): ba.playsound(ba.getsound('tick')) if self._count == 1: self._animate = ba.animate( - self.node, - 'model_scale', - { - 0:self.node.model_scale, - 0.1:1.5, - 0.2:self.scale - }, - loop=True - ) + self.node, + 'model_scale', + { + 0: self.node.model_scale, + 0.1: 1.5, + 0.2: self.scale + }, + loop=True + ) self.animate_light = ba.animate_array( - self.light, - 'color', - 3, - { - 0:c, - 0.1:c2, - 0.2:c - }, - loop=True - ) + self.light, + 'color', + 3, + { + 0: c, + 0.1: c2, + 0.2: c + }, + loop=True + ) else: self._animate = ba.animate( - self.node, - 'model_scale', - { - 0:self.node.model_scale, - 0.5:1.5, - 1.0:self.scale - }, - loop=True - ) + self.node, + 'model_scale', + { + 0: self.node.model_scale, + 0.5: 1.5, + 1.0: self.scale + }, + loop=True + ) self.animate_light = ba.animate_array( - self.light, - 'color', - 3, - { - 0:c, - 0.2:c2, - 0.5:c, - 1.0:c - }, - loop=True - ) + self.light, + 'color', + 3, + { + 0: c, + 0.2: c2, + 0.5: c, + 1.0: c + }, + loop=True + ) def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.DieMessage): - if not self.node: return + if not self.node: + return self.node.delete() activity = self._activity() if activity and not msg.immediate: @@ -270,15 +276,17 @@ class Ball(ba.Actor): elif isinstance(msg, ba.PickedUpMessage): d = self.d_time + def damage(): if (msg is not None and msg.node.exists() and msg.node.getdelegate(PlayerSpaz).hitpoints > 0): spaz = msg.node.getdelegate(PlayerSpaz) - spaz.node.color = (spaz.node.color[0]-0.1,spaz.node.color[1]-0.1,spaz.node.color[2]-0.1) + spaz.node.color = (spaz.node.color[0]-0.1, + spaz.node.color[1]-0.1, spaz.node.color[2]-0.1) if spaz.node.hold_node != self.node: self.handlemessage(ba.DroppedMessage(spaz.node)) if spaz.hitpoints > 10000: - ba.playsound(ba.getsound('fuse01'),volume=0.3) + ba.playsound(ba.getsound('fuse01'), volume=0.3) spaz.hitpoints -= 10000 spaz._last_hit_time = None spaz._num_time_shit = 0 @@ -319,51 +327,54 @@ class Ball(ba.Actor): if activity: if s_player in activity.players: self.last_players_to_touch[s_player.team.id] = s_player - + elif isinstance(msg, ExplodeHitMessage): node = ba.getcollision().opposingnode - if not self.node: return + if not self.node: + return nodepos = self.region.position mag = 2000.0 - + node.handlemessage( ba.HitMessage( - pos=nodepos, - velocity=(0, 0, 0), - magnitude=mag, - hit_type='explosion', - hit_subtype='normal', - radius=2.0 - ) - ) + pos=nodepos, + velocity=(0, 0, 0), + magnitude=mag, + hit_type='explosion', + hit_subtype='normal', + radius=2.0 + ) + ) self.handlemessage(ba.DieMessage()) else: super().handlemessage(msg) -###HUMAN### +### HUMAN### + + class NewPlayerSpaz(PlayerSpaz): - + move_mult = 1.0 reload = True extra_jump = True - ###calls - + # calls + def impulse(self): self.reload = False p = self.node self.node.handlemessage( - "impulse", - p.position[0], p.position[1]+40, p.position[2], - 0, 0, 0, - 160, 0, 0, 0, - 0, 205, 0) - ba.timer(0.4,self.refresh) - + "impulse", + p.position[0], p.position[1]+40, p.position[2], + 0, 0, 0, + 160, 0, 0, 0, + 0, 205, 0) + ba.timer(0.4, self.refresh) + def refresh(self): self.reload = True - + def drop_bomb(self) -> Optional[Bomb]: - + if (self.land_mine_count <= 0 and self.bomb_count <= 0) or self.frozen: return None assert self.node @@ -377,15 +388,15 @@ class NewPlayerSpaz(PlayerSpaz): else: dropping_bomb = True bomb_type = self.bomb_type - + if bomb_type == 'banana': - ba.playsound(ba.getsound('penguinHit1'),volume=0.3) + ba.playsound(ba.getsound('penguinHit1'), volume=0.3) bomb = NewBomb(position=(pos[0], pos[1] + 0.7, pos[2]), - velocity=(vel[0], vel[1], vel[2]), - bomb_type = bomb_type, - radius = 1.0, - source_player=self.source_player, - owner=self.node) + velocity=(vel[0], vel[1], vel[2]), + bomb_type=bomb_type, + radius=1.0, + source_player=self.source_player, + owner=self.node) else: bomb = Bomb(position=(pos[0], pos[1] - 0.0, pos[2]), velocity=(vel[0], vel[1], vel[2]), @@ -393,7 +404,6 @@ class NewPlayerSpaz(PlayerSpaz): blast_radius=self.blast_radius, source_player=self.source_player, owner=self.node).autoretain() - assert bomb.node if dropping_bomb: @@ -401,24 +411,24 @@ class NewPlayerSpaz(PlayerSpaz): bomb.node.add_death_action( ba.WeakCall(self.handlemessage, BombDiedMessage())) self._pick_up(bomb.node) - + try: for clb in self._dropped_bomb_callbacks: clb(self, bomb) except Exception: return - + return bomb - + def on_jump_press(self) -> None: if not self.node: return self.node.jump_pressed = True self._turbo_filter_add_press('jump') - + if self.reload and self.extra_jump: self.impulse() - + def handlemessage(self, msg: Any) -> Any: if isinstance(msg, PickupMessage): if not self.node: @@ -430,13 +440,13 @@ class NewPlayerSpaz(PlayerSpaz): except ba.NotFoundError: return True if opposingnode.getnodetype() == 'spaz': - player = opposingnode.getdelegate(PlayerSpaz,True).getplayer(Player, True) + player = opposingnode.getdelegate(PlayerSpaz, True).getplayer(Player, True) if player.actor.shield: return None super().handlemessage(msg) return super().handlemessage(msg) - - + + class Player(ba.Player['Team']): """Our player type for this game.""" @@ -459,17 +469,17 @@ if lang == 'Spanish': bomb_timer = 'Temporizador' space_wall = 'Espacio Debajo de la Red' num_bones = 'Huesos Distractores' - b_count = ['Nada','Pocos','Muchos'] + b_count = ['Nada', 'Pocos', 'Muchos'] shield = 'Inmortalidad' bomb = 'Habilitar Bananas' boxing_gloves = 'Equipar Guantes de Boxeo' difficulty = 'Dificultad' - difficulty_o = ['Fácil','Difícil','Chernobyl'] + difficulty_o = ['Fácil', 'Difícil', 'Chernobyl'] wall_color = 'Color de la Red' - w_c = ['Verde','Rojo','Naranja','Amarillo','Celeste','Azul','Rosa','Gris'] + w_c = ['Verde', 'Rojo', 'Naranja', 'Amarillo', 'Celeste', 'Azul', 'Rosa', 'Gris'] ball_body = 'Tipo de Hot Bomb' - body = ['Esfera','Cubo'] - + body = ['Esfera', 'Cubo'] + else: name = 'Hot Bomb' description = 'Get the bomb to explode on\nthe enemy team to win.' @@ -480,16 +490,16 @@ else: bomb_timer = 'Timer' space_wall = 'Space Under the Mesh' num_bones = 'Distractor Bones' - b_count = ['None','Few','Many'] + b_count = ['None', 'Few', 'Many'] shield = 'Immortality' bomb = 'Enable Bananas' difficulty = 'Difficulty' - difficulty_o = ['Easy','Hard','Chernobyl'] + difficulty_o = ['Easy', 'Hard', 'Chernobyl'] wall_color = 'Mesh Color' - w_c = ['Green','Red','Orange','Yellow','Light blue','Blue','Ping','Gray'] + w_c = ['Green', 'Red', 'Orange', 'Yellow', 'Light blue', 'Blue', 'Ping', 'Gray'] ball_body = 'Type of Hot Bomb' - body = ['Sphere','Box'] - + body = ['Sphere', 'Box'] + # ba_meta export game class HotBombGame(ba.TeamGameActivity[Player, Team]): @@ -526,7 +536,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): ('Longer', 3.0), ], default=0.5, - + ), ba.FloatChoiceSetting( difficulty, @@ -536,14 +546,14 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): (difficulty_o[2], 0.01), ], default=0.15, - + ), ba.IntChoiceSetting( bomb_timer, - choices=[(str(choice)+'s',choice) for choice in range(2,11)], + choices=[(str(choice)+'s', choice) for choice in range(2, 11)], default=5, - ), + ), ba.IntChoiceSetting( num_bones, choices=[ @@ -552,7 +562,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): (b_count[2], 5), ], default=2, - + ), ba.IntChoiceSetting( ball_body, @@ -561,7 +571,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): ), ba.IntChoiceSetting( wall_color, - choices=[(color,w_c.index(color)) for color in w_c], + choices=[(color, w_c.index(color)) for color in w_c], default=0, ), @@ -569,7 +579,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): ba.BoolSetting(space_wall, default=True), ba.BoolSetting(bomb, default=True), ba.BoolSetting(shield, default=False), - + ] default_music = ba.MusicType.HOCKEY @@ -584,7 +594,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): def __init__(self, settings: dict): super().__init__(settings) self._bomb_timer = int(settings[bomb_timer]) - self._space_under_wall = bool(settings[space_wall]) + self._space_under_wall = bool(settings[space_wall]) self._num_bones = int(settings[num_bones]) self._shield = bool(settings[shield]) self._bomb = bool(settings[bomb]) @@ -592,10 +602,10 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): self._epic_mode = bool(settings['Epic Mode']) self._wall_color = int(settings[wall_color]) self._ball_body = int(settings[ball_body]) - - self.bodys = ['sphere','crate'] - self.models = ['bombSticky','powerupSimple'] - + + self.bodys = ['sphere', 'crate'] + self.models = ['bombSticky', 'powerupSimple'] + shared = SharedObjects.get() self._scoreboard = Scoreboard() self._cheer_sound = ba.getsound('cheer') @@ -607,13 +617,13 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): self.ball_body = self.bodys[self._ball_body] self.ball_tex = ba.gettexture('powerupCurse') self._ball_sound = ba.getsound('splatter') - + self.last_point = None - self.colors = [(0.25,0.5,0.25), (1, 0.15, 0.15), (1, 0.5, 0), (1, 1, 0), - (0.2, 1, 1), (0.1, 0.1, 1), (1, 0.3, 0.5),(0.5, 0.5, 0.5)] + self.colors = [(0.25, 0.5, 0.25), (1, 0.15, 0.15), (1, 0.5, 0), (1, 1, 0), + (0.2, 1, 1), (0.1, 0.1, 1), (1, 0.3, 0.5), (0.5, 0.5, 0.5)] # self.slow_motion = self._epic_mode - + self.ball_material = ba.Material() self.ball_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) @@ -631,10 +641,10 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): ) self.ball_material.add_actions( conditions=( - 'they_have_material',shared.footing_material + 'they_have_material', shared.footing_material ), actions=( - 'impact_sound',self._ball_sound, 0.2, 4 + 'impact_sound', self._ball_sound, 0.2, 4 ) ) @@ -644,27 +654,27 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): 'they_have_material', shared.player_material ), actions=( - ('call', 'at_connect',self._handle_ball_player_collide), + ('call', 'at_connect', self._handle_ball_player_collide), ) ) # We want the ball to kill powerups; not get stopped by them self.ball_material.add_actions( conditions=( - 'they_have_material',PowerupBoxFactory.get().powerup_material), + 'they_have_material', PowerupBoxFactory.get().powerup_material), actions=( ('modify_part_collision', 'physical', False), ('message', 'their_node', 'at_connect', ba.DieMessage()) ) ) - + self._score_region_material = ba.Material() self._score_region_material.add_actions( conditions=( 'they_have_material', self.ball_material ), actions=( - ('modify_part_collision', 'collide',True), + ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_score) ) @@ -676,35 +686,35 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): 'they_have_material', self.ball_material ), actions=( - ('modify_part_collision', 'collide',True), + ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._reset_count) ) ) - + self._reaction_material = ba.Material() self._reaction_material.add_actions( conditions=( 'they_have_material', shared.player_material ), actions=( - ('modify_part_collision', 'collide',True), + ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._reaction) ) ) - + self._reaction_material.add_actions( conditions=( 'they_have_material', HealthFactory.get().health_material ), actions=( - ('modify_part_collision', 'collide',True), + ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', True) ) ) - - self._collide=ba.Material() + + self._collide = ba.Material() self._collide.add_actions( conditions=( ('they_are_different_node_than_us', ), @@ -715,24 +725,24 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): ('modify_part_collision', 'collide', True) ) ) - - self._wall_material=ba.Material() + + self._wall_material = ba.Material() self._wall_material.add_actions( conditions=( 'we_are_older_than', 1 - ), + ), actions=( ('modify_part_collision', 'collide', True) ) ) - + self.ice_material = ba.Material() self.ice_material.add_actions( actions=( - 'modify_part_collision','friction',0.05 + 'modify_part_collision', 'friction', 0.05 ) ) - + self._ball_spawn_pos: Optional[Sequence[float]] = None self._ball: Optional[Ball] = None self._score_to_win = int(settings['Score to Win']) @@ -751,26 +761,26 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) - self._ball_spawn_pos = (random.choice([-5,5]),4,0) - ba.timer(5,self._spawn_ball) - ba.timer(0.1,self.update_ball,repeat=True) + self._ball_spawn_pos = (random.choice([-5, 5]), 4, 0) + ba.timer(5, self._spawn_ball) + ba.timer(0.1, self.update_ball, repeat=True) self.add_game_complements() self.add_map_complements() self._update_scoreboard() ba.playsound(self._chant_sound) - + def _reaction(self): node: ba.Node = ba.getcollision().opposingnode - ba.playsound(ba.getsound('hiss'),volume=0.75) - + ba.playsound(ba.getsound('hiss'), volume=0.75) + node.handlemessage( "impulse", - node.position[0],node.position[1],node.position[2], - -node.velocity[0]*2,-node.velocity[1],-node.velocity[2], - 100,100,0,0, - -node.velocity[0],-node.velocity[1],-node.velocity[2] + node.position[0], node.position[1], node.position[2], + -node.velocity[0]*2, -node.velocity[1], -node.velocity[2], + 100, 100, 0, 0, + -node.velocity[0], -node.velocity[1], -node.velocity[2] ) - + ba.emitfx( position=node.position, count=20, @@ -781,21 +791,21 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): def add_game_complements(self): HealthBox( - position=(-1,3.5,-5+random.random()*10) + position=(-1, 3.5, -5+random.random()*10) ) HealthBox( - position=(1,3.5,-5+random.random()*10) + position=(1, 3.5, -5+random.random()*10) ) ### g = 0 while g < self._num_bones: b = 0 Torso( - position=(-6+random.random()*12,3.5,-5+random.random()*10) + position=(-6+random.random()*12, 3.5, -5+random.random()*10) ) while b < 6: Bone( - position=(-6+random.random()*12,2,-5+random.random()*10), + position=(-6+random.random()*12, 2, -5+random.random()*10), style=b ) b += 1 @@ -805,88 +815,88 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): part_of_wall = ba.newnode( 'locator', attrs={ - 'shape':'box', - 'position':(-7.169,0.5,0.5), - 'color':self.wall_color, - 'opacity':1, - 'drawShadow':False, - 'draw_beauty':True, - 'additive':False, - 'size':[14.7,2,16] + 'shape': 'box', + 'position': (-7.169, 0.5, 0.5), + 'color': self.wall_color, + 'opacity': 1, + 'drawShadow': False, + 'draw_beauty': True, + 'additive': False, + 'size': [14.7, 2, 16] } ) part_of_wall2 = ba.newnode( - 'locator', - attrs={ - 'shape':'box', - 'position':(0,-13.51,0.5) if self._space_under_wall else (0,-35.540,0.5), - 'color':self.wall_color, - 'opacity':1, - 'drawShadow':False, - 'draw_beauty':True, - 'additive':False, - 'size':[0.3,30,13] if self._space_under_wall else [0.3,75,13] - } - ) + 'locator', + attrs={ + 'shape': 'box', + 'position': (0, -13.51, 0.5) if self._space_under_wall else (0, -35.540, 0.5), + 'color': self.wall_color, + 'opacity': 1, + 'drawShadow': False, + 'draw_beauty': True, + 'additive': False, + 'size': [0.3, 30, 13] if self._space_under_wall else [0.3, 75, 13] + } + ) wall = ba.newnode( 'region', attrs={ - 'position': (0,1.11,0.5) if self._space_under_wall else (0,0.75,0.5), - 'scale': (0.3,0.75,13) if self._space_under_wall else (0.3,1.5,13), + 'position': (0, 1.11, 0.5) if self._space_under_wall else (0, 0.75, 0.5), + 'scale': (0.3, 0.75, 13) if self._space_under_wall else (0.3, 1.5, 13), 'type': 'box', - 'materials': (self._wall_material,self._reaction_material) + 'materials': (self._wall_material, self._reaction_material) } ) # RESET REGION - pos = (0,5.3,0) + pos = (0, 5.3, 0) ba.newnode( 'region', attrs={ 'position': pos, - 'scale': (0.001,15,12), + 'scale': (0.001, 15, 12), 'type': 'box', - 'materials': [self._check_region_material,self._reaction_material] + 'materials': [self._check_region_material, self._reaction_material] } ) - + ba.newnode( 'region', attrs={ 'position': pos, - 'scale': (0.3,15,12), + 'scale': (0.3, 15, 12), 'type': 'box', 'materials': [self._collide] } ) - + def add_map_complements(self): - #TEXT + # TEXT text = ba.newnode('text', - attrs={'position':(0,2.5,-6), - 'text':'Hot Bomb by\nSEBASTIAN2059 and zPanxo', - 'in_world':True, - 'shadow':1.0, - 'flatness':0.7, - 'color':(1.91,1.31,0.59), - 'opacity':0.25-0.15, - 'scale':0.013+0.007, - 'h_align':'center'}) + attrs={'position': (0, 2.5, -6), + 'text': 'Hot Bomb by\nSEBASTIAN2059 and zPanxo', + 'in_world': True, + 'shadow': 1.0, + 'flatness': 0.7, + 'color': (1.91, 1.31, 0.59), + 'opacity': 0.25-0.15, + 'scale': 0.013+0.007, + 'h_align': 'center'}) walls_data = { - 'w1':[ - (11,5.5,0), - (4.5,11,13) - ], - 'w2':[ - (-11,5.5,0), - (4.5,11,13) + 'w1': [ + (11, 5.5, 0), + (4.5, 11, 13) ], - 'w3':[ - (0,5.5,-6.1), - (19,11,1) + 'w2': [ + (-11, 5.5, 0), + (4.5, 11, 13) ], - 'w4':[ - (0,5.5,6.5), - (19,11,1) + 'w3': [ + (0, 5.5, -6.1), + (19, 11, 1) + ], + 'w4': [ + (0, 5.5, 6.5), + (19, 11, 1) ], } for i in walls_data: @@ -900,72 +910,72 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): } ) - for i in [-5,-2.5,0,2.5,5]: - pos = (11,6.5,0) + for i in [-5, -2.5, 0, 2.5, 5]: + pos = (11, 6.5, 0) Box( - position=(pos[0]-0.5,pos[1]-5.5,pos[2]+i), + position=(pos[0]-0.5, pos[1]-5.5, pos[2]+i), texture='powerupPunch' ) Box( - position=(pos[0]-0.5,pos[1]-3,pos[2]+i), + position=(pos[0]-0.5, pos[1]-3, pos[2]+i), texture='powerupPunch' ) Box( - position=(pos[0]-0.5,pos[1]-0.5,pos[2]+i), + position=(pos[0]-0.5, pos[1]-0.5, pos[2]+i), texture='powerupPunch' ) - pos = (-11,6.5,0) + pos = (-11, 6.5, 0) Box( - position=(pos[0]+0.5,pos[1]-5.5,pos[2]+i), + position=(pos[0]+0.5, pos[1]-5.5, pos[2]+i), texture='powerupIceBombs' ) Box( - position=(pos[0]+0.5,pos[1]-3,pos[2]+i), + position=(pos[0]+0.5, pos[1]-3, pos[2]+i), texture='powerupIceBombs' ) Box( - position=(pos[0]+0.5,pos[1]-0.5,pos[2]+i), + position=(pos[0]+0.5, pos[1]-0.5, pos[2]+i), texture='powerupIceBombs' ) - + def spawn_player(self, player: Player) -> ba.Actor: position = self.get_position(player) name = player.getname() display_color = _ba.safecolor(player.color, target_intensity=0.75) actor = NewPlayerSpaz( - color=player.color, - highlight=player.highlight, - character=player.character, - player=player - ) + color=player.color, + highlight=player.highlight, + character=player.character, + player=player + ) player.actor = actor - + player.actor.node.name = name player.actor.node.name_color = display_color player.actor.bomb_type_default = 'banana' player.actor.bomb_type = 'banana' - + actor.connect_controls_to_player(enable_punch=True, - enable_bomb=self._bomb, - enable_pickup=True) + enable_bomb=self._bomb, + enable_pickup=True) actor.node.hockey = True actor.hitpoints_max = 100000 actor.hitpoints = 100000 actor.equip_boxing_gloves() if self._shield: actor.equip_shields() - actor.shield.color = (0,0,0) + actor.shield.color = (0, 0, 0) actor.shield.radius = 0.1 actor.shield_hitpoints = actor.shield_hitpoints_max = 100000 - - #Move to the stand position and add a flash of light. + + # Move to the stand position and add a flash of light. actor.handlemessage( StandMessage( position, random.uniform(0, 360))) - ba.playsound(ba.getsound('spawn'),volume=0.6) + ba.playsound(ba.getsound('spawn'), volume=0.6) return actor - + def on_team_join(self, team: Team) -> None: self._update_scoreboard() @@ -973,7 +983,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): collision = ba.getcollision() try: ball = collision.sourcenode.getdelegate(Ball, True) - player = collision.opposingnode.getdelegate(PlayerSpaz,True).getplayer(Player, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer(Player, True) except ba.NotFoundError: return @@ -981,15 +991,15 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): def _kill_ball(self) -> None: self._ball = None - + def _reset_count(self) -> None: """reset counter of ball.""" assert self._ball is not None - + if self._ball.scored: return - + ba.playsound(ba.getsound('laser')) self._ball._count = self._bomb_timer self._ball._counter.text = str(self._bomb_timer) @@ -999,39 +1009,41 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): repeat=True ) self._ball._animate = ba.animate( - self._ball.node, - 'model_scale', - { - 0:self._ball.node.model_scale, - 0.1:self._ball.scale - } - ) + self._ball.node, + 'model_scale', + { + 0: self._ball.node.model_scale, + 0.1: self._ball.scale + } + ) if self._ball.light.color[0] == 0: - self._ball.light.color = (2,0,0) + self._ball.light.color = (2, 0, 0) else: - self._ball.light.color = (0,0,3) - + self._ball.light.color = (0, 0, 3) + def update_ball(self): - if not self._ball: return - if not self._ball.node: return + if not self._ball: + return + if not self._ball.node: + return gnode = ba.getactivity().globalsnode - + if self._ball.node.position[0] > 0: self._ball.node.color_texture = ba.gettexture('powerupIceBombs') - ba.animate_array(gnode,'vignette_outer',3,{1.0:(0.4, 0.4, 0.9)}) - self._ball.color_l = (0,0,3.5) - self._ball._counter.color = (0,0,5) + ba.animate_array(gnode, 'vignette_outer', 3, {1.0: (0.4, 0.4, 0.9)}) + self._ball.color_l = (0, 0, 3.5) + self._ball._counter.color = (0, 0, 5) else: self._ball.node.color_texture = ba.gettexture('powerupPunch') - ba.animate_array(gnode,'vignette_outer',3,{1.0:(0.6,0.45,0.45)}) - self._ball.color_l = (2.5,0,0) - self._ball._counter.color = (1.2,0,0) + ba.animate_array(gnode, 'vignette_outer', 3, {1.0: (0.6, 0.45, 0.45)}) + self._ball.color_l = (2.5, 0, 0) + self._ball._counter.color = (1.2, 0, 0) - def _handle_score(self,index=0) -> None: + def _handle_score(self, index=0) -> None: """A point has been scored.""" assert self._ball is not None - + for team in self.teams: if team.id == index: scoring_team = team @@ -1058,14 +1070,14 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): # End game if we won. if team.score >= self._score_to_win: self.end_game() - + elif team.id != index: # Tell all players to celebrate. for player in team.players: if player.actor: player.actor.handlemessage(ba.DieMessage()) - + ba.playsound(self._foghorn_sound) ba.playsound(self._cheer_sound) @@ -1087,10 +1099,10 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): # Respawn dead players if they're still in the game. if isinstance(msg, ba.PlayerDiedMessage): - + player = msg.getplayer(Player) spaz = player.actor - spaz.node.color = (-1,-1,-1) + spaz.node.color = (-1, -1, -1) spaz.node.color_mask_texture = ba.gettexture('bonesColorMask') spaz.node.color_texture = ba.gettexture('bonesColor') spaz.node.head_model = ba.getmodel('bonesHead') @@ -1118,7 +1130,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): else: super().handlemessage(msg) - def _flash_ball_spawn(self,pos,color=(1,0,0)) -> None: + def _flash_ball_spawn(self, pos, color=(1, 0, 0)) -> None: light = ba.newnode('light', attrs={ 'position': pos, @@ -1132,38 +1144,38 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): timer = self._bomb_timer ba.playsound(self._swipsound) ba.playsound(self._whistle_sound) - pos = (random.choice([5,-5]),2,0) + pos = (random.choice([5, -5]), 2, 0) if self.last_point != None: if self.last_point == 0: - pos = (-5,2,0) + pos = (-5, 2, 0) else: - pos = (5,2,0) - - color = (0,0,1*2) if pos[0] == 5 else (1*1.5,0,0) + pos = (5, 2, 0) + + color = (0, 0, 1*2) if pos[0] == 5 else (1*1.5, 0, 0) texture = 'powerupPunch' if pos[0] == -5 else 'powerupIceBombs' - counter_color = (1,0,0) if pos[0] == -5 else (0,0,5) - #self._flash_ball_spawn(pos,color) - self._ball = Ball(position=pos,timer=timer,d_time=self.damage_time,color=color) + counter_color = (1, 0, 0) if pos[0] == -5 else (0, 0, 5) + # self._flash_ball_spawn(pos,color) + self._ball = Ball(position=pos, timer=timer, d_time=self.damage_time, color=color) self._ball.node.color_texture = ba.gettexture(texture) self._ball._counter.color = counter_color - + def get_position(self, player: Player) -> ba.Actor: - position = (0,1,0) + position = (0, 1, 0) team = player.team.id if team == 0: - position = (random.randint(-7,-3),0.25,random.randint(-5,5)) + position = (random.randint(-7, -3), 0.25, random.randint(-5, 5)) angle = 90 else: - position = (random.randint(3,7),0.25,random.randint(-5,5)) + position = (random.randint(3, 7), 0.25, random.randint(-5, 5)) angle = 270 return position - + def respawn_player(self, player: PlayerType, respawn_time: Optional[float] = None) -> None: import _ba from ba._general import Call, WeakCall - + assert player if respawn_time is None: respawn_time = 3.0 @@ -1182,7 +1194,7 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): respawn_time, WeakCall(self.spawn_player_if_exists, player)) player.customdata['respawn_icon'] = RespawnIcon( player, respawn_time) - + def spawn_player_if_exists(self, player: PlayerType) -> None: """ A utility method which calls self.spawn_player() *only* if the @@ -1193,43 +1205,46 @@ class HotBombGame(ba.TeamGameActivity[Player, Team]): if player: self.spawn_player(player) - def spawn_player_spaz(self, player: PlayerType) -> None: - position = (0,1,0) + position = (0, 1, 0) angle = None team = player.team.id if team == 0: - position = (random.randint(-7,-3),0.25,random.randint(-5,5)) + position = (random.randint(-7, -3), 0.25, random.randint(-5, 5)) angle = 90 else: - position = (random.randint(3,7),0.25,random.randint(-5,5)) + position = (random.randint(3, 7), 0.25, random.randint(-5, 5)) angle = 270 - + return super().spawn_player_spaz(player, position, angle) -#####New-Bomb##### +##### New-Bomb##### + + class ExplodeMessage: """Tells an object to explode.""" - + + class ImpactMessage: """Tell an object it touched something.""" + class NewBomb(ba.Actor): - + def __init__(self, position: Sequence[float] = (0, 1, 0), velocity: Sequence[float] = (0, 0, 0), bomb_type: str = '', radius: float = 2.0, source_player: ba.Player = None, owner: ba.Node = None): - + super().__init__() - + shared = SharedObjects.get() # Material for powerups. self.bomb_material = ba.Material() self.explode_material = ba.Material() - + self.bomb_material.add_actions( conditions=( ('we_are_older_than', 200), @@ -1245,48 +1260,48 @@ class NewBomb(ba.Actor): ), ), actions=('message', 'our_node', 'at_connect', ImpactMessage())) - + self.explode_material.add_actions( conditions=('they_have_material', shared.player_material), - actions=(('modify_part_collision', 'collide',True), + actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._touch_player))) - + self._source_player = source_player self.owner = owner self.bomb_type = bomb_type self.radius = radius - + owner_color = self.owner.source_player._team.color - + if self.bomb_type == 'banana': self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ 'position': position, 'velocity': velocity, 'color_texture': ba.gettexture('powerupBomb'), 'model': ba.getmodel('penguinTorso'), - 'model_scale':0.7, - 'body_scale':0.7, - 'density':3, + 'model_scale': 0.7, + 'body_scale': 0.7, + 'density': 3, 'reflection': 'soft', 'reflection_scale': [1.0], 'shadow_size': 0.3, 'body': 'sphere', 'owner': owner, - 'materials': (shared.object_material,self.bomb_material)}) - - ba.animate(self.node,'model_scale',{0:0,0.2:1,0.26:0.7}) + 'materials': (shared.object_material, self.bomb_material)}) + + ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1, 0.26: 0.7}) self.light = ba.newnode('light', owner=self.node, attrs={ - 'color':owner_color, - 'volume_intensity_scale': 2.0, - 'intensity':1, - 'radius':0.1}) - self.node.connectattr('position', self.light,'position') - + 'color': owner_color, + 'volume_intensity_scale': 2.0, + 'intensity': 1, + 'radius': 0.1}) + self.node.connectattr('position', self.light, 'position') + self.spawn: ba.Timer = ba.Timer( - 10.0,self._check,repeat=True) - + 10.0, self._check, repeat=True) + def _impact(self) -> None: node = ba.getcollision().opposingnode node_delegate = node.getdelegate(object) @@ -1294,12 +1309,11 @@ class NewBomb(ba.Actor): if (node is self.owner): return self.handlemessage(ExplodeMessage()) - - + def _explode(self): if self.node: # Set our position a bit lower so we throw more things upward. - + pos = self.node.position rmats = (self.explode_material,) self.explode_region = ba.newnode( @@ -1313,28 +1327,27 @@ class NewBomb(ba.Actor): }, ) if self.bomb_type == 'banana': - ba.playsound(ba.getsound('stickyImpact'),volume=0.35) + ba.playsound(ba.getsound('stickyImpact'), volume=0.35) a = ba.emitfx(position=self.node.position, - velocity=(0,1,0), - count=15, - scale=1.0, - spread=0.1, - chunk_type='spark') + velocity=(0, 1, 0), + count=15, + scale=1.0, + spread=0.1, + chunk_type='spark') scorch = ba.newnode('scorch', - attrs={ - 'position': self.node.position, - 'size': 1.0, - 'big': False, - 'color':(1,1,0) - }) - - ba.animate(scorch,'size',{0:1.0,5:0}) - ba.timer(5,scorch.delete) - + attrs={ + 'position': self.node.position, + 'size': 1.0, + 'big': False, + 'color': (1, 1, 0) + }) + + ba.animate(scorch, 'size', {0: 1.0, 5: 0}) + ba.timer(5, scorch.delete) ba.timer(0.05, self.explode_region.delete) ba.timer(0.001, ba.WeakCall(self.handlemessage, ba.DieMessage())) - + def _touch_player(self): node = ba.getcollision().opposingnode collision = ba.getcollision() @@ -1344,7 +1357,7 @@ class NewBomb(ba.Actor): Player, True) except ba.NotFoundError: return - + if self.bomb_type == 'banana': color = player.team.color owner_team = self.owner.source_player._team @@ -1353,8 +1366,9 @@ class NewBomb(ba.Actor): if player.team == owner_team: return player.actor.node.handlemessage('knockout', 500.0) - ba.animate_array(player.actor.node,'color',3,{0:color,0.1:(1.5,1,0),0.5:(1.5,1,0),0.6:color}) - + ba.animate_array(player.actor.node, 'color', 3, { + 0: color, 0.1: (1.5, 1, 0), 0.5: (1.5, 1, 0), 0.6: color}) + def _check(self) -> None: """Prevent the cube from annihilating.""" @@ -1369,8 +1383,10 @@ class NewBomb(ba.Actor): elif isinstance(msg, ba.OutOfBoundsMessage): if self.node: self.node.delete() - -######Object##### + +###### Object##### + + class HealthFactory: """Wraps up media and other resources used by ba.Bombs. @@ -1383,7 +1399,7 @@ class HealthFactory: health_model The ba.Model of a standard health. - + health_tex The ba.Texture for health. @@ -1406,9 +1422,7 @@ class HealthFactory: activity.customdata[cls._STORENAME] = factory assert isinstance(factory, HealthFactory) return factory - - - + def __init__(self) -> None: """Instantiate a BombFactory. @@ -1416,13 +1430,13 @@ class HealthFactory: to get a shared instance. """ shared = SharedObjects.get() - + self.health_model = ba.getmodel('egg') - + self.health_tex = ba.gettexture('eggTex1') - + self.health_sound = ba.getsound('activateBeep') - + # Set up our material so new bombs don't collide with objects # that they are initially overlapping. self.health_material = ba.Material() @@ -1448,21 +1462,22 @@ class HealthFactory: ) self.health_material.add_actions(actions=('modify_part_collision', - 'friction', 0.3)) + 'friction', 0.3)) + class HealthBox(ba.Actor): - + def __init__(self, position: Sequence[float] = (0, 1, 0), velocity: Sequence[float] = (0, 0, 0), texture: str = 'powerupHealth'): super().__init__() - + shared = SharedObjects.get() factory = HealthFactory.get() self.healthbox_material = ba.Material() self.healthbox_material.add_actions( conditions=( - 'they_are_different_node_than_us', + 'they_are_different_node_than_us', ), actions=( ('modify_part_collision', 'collide', True) @@ -1473,27 +1488,27 @@ class HealthBox(ba.Actor): 'velocity': velocity, 'color_texture': ba.gettexture(texture), 'model': ba.getmodel('powerup'), - 'light_model':ba.getmodel('powerupSimple'), - 'model_scale':1, + 'light_model': ba.getmodel('powerupSimple'), + 'model_scale': 1, 'body': 'crate', - 'body_scale':1, - 'density':1, - 'damping':0, - 'gravity_scale':1, + 'body_scale': 1, + 'density': 1, + 'damping': 0, + 'gravity_scale': 1, 'reflection': 'powerup', 'reflection_scale': [0.5], 'shadow_size': 0.0, - 'materials': (shared.object_material,self.healthbox_material,factory.health_material)}) - + 'materials': (shared.object_material, self.healthbox_material, factory.health_material)}) + self.light = ba.newnode('light', owner=self.node, attrs={ - 'color':(1,1,1), - 'volume_intensity_scale': 0.4, - 'intensity':0.7, - 'radius':0.0}) - self.node.connectattr('position', self.light,'position') - + 'color': (1, 1, 1), + 'volume_intensity_scale': 0.4, + 'intensity': 0.7, + 'radius': 0.0}) + self.node.connectattr('position', self.light, 'position') + self.spawn: ba.Timer = ba.Timer( - 10.0,self._check,repeat=True) + 10.0, self._check, repeat=True) def _check(self) -> None: """Prevent the cube from annihilating.""" @@ -1512,8 +1527,8 @@ class HealthBox(ba.Actor): spaz.actor.node.handlemessage(ba.PowerupMessage(poweruptype='health')) t_color = spaz.team.color spaz.actor.node.color = t_color - ba.playsound(ba.getsound('healthPowerup'),volume=0.5) - ba.animate(self.light,'radius',{0:0.0,0.1:0.2,0.7:0}) + ba.playsound(ba.getsound('healthPowerup'), volume=0.5) + ba.animate(self.light, 'radius', {0: 0.0, 0.1: 0.2, 0.7: 0}) except: pass @@ -1521,13 +1536,14 @@ class HealthBox(ba.Actor): spaz = msg.node.getdelegate(PlayerSpaz) self.regen_timer = None + class Torso(ba.Actor): - + def __init__(self, position: Sequence[float] = (0, 1, 0), velocity: Sequence[float] = (0, 0, 0), texture: str = 'bonesColor'): super().__init__() - + shared = SharedObjects.get() self.node: ba.Node = ba.newnode('prop', delegate=self, attrs={ @@ -1535,19 +1551,19 @@ class Torso(ba.Actor): 'velocity': velocity, 'color_texture': ba.gettexture(texture), 'model': ba.getmodel('bonesTorso'), - 'model_scale':1, + 'model_scale': 1, 'body': 'sphere', - 'body_scale':0.5, - 'density':6, - 'damping':0, - 'gravity_scale':1, + 'body_scale': 0.5, + 'density': 6, + 'damping': 0, + 'gravity_scale': 1, 'reflection': 'soft', 'reflection_scale': [0], 'shadow_size': 0.0, 'materials': (shared.object_material,)}) - + self.spawn: ba.Timer = ba.Timer( - 10.0,self._check,repeat=True) + 10.0, self._check, repeat=True) def _check(self) -> None: """Prevent the cube from annihilating.""" @@ -1561,16 +1577,18 @@ class Torso(ba.Actor): if self.node: self.node.delete() + class Bone(ba.Actor): - + def __init__(self, position: Sequence[float] = (0, 1, 0), velocity: Sequence[float] = (0, 0, 0), texture: str = 'bonesColor', style: int = 0): super().__init__() - + shared = SharedObjects.get() - models = ['bonesUpperArm','bonesUpperLeg','bonesForeArm','bonesPelvis','bonesToes','bonesHand'] + models = ['bonesUpperArm', 'bonesUpperLeg', 'bonesForeArm', + 'bonesPelvis', 'bonesToes', 'bonesHand'] bone = None model = 0 for i in models: @@ -1583,19 +1601,19 @@ class Bone(ba.Actor): 'velocity': velocity, 'color_texture': ba.gettexture(texture), 'model': ba.getmodel(bone), - 'model_scale':1.5, + 'model_scale': 1.5, 'body': 'crate', - 'body_scale':0.6, - 'density':2, - 'damping':0, - 'gravity_scale':1, + 'body_scale': 0.6, + 'density': 2, + 'damping': 0, + 'gravity_scale': 1, 'reflection': 'soft', 'reflection_scale': [0], 'shadow_size': 0.0, 'materials': (shared.object_material,)}) - + self.spawn: ba.Timer = ba.Timer( - 10.0,self._check,repeat=True) + 10.0, self._check, repeat=True) def _check(self) -> None: """Prevent the cube from annihilating.""" @@ -1608,20 +1626,22 @@ class Bone(ba.Actor): elif isinstance(msg, ba.OutOfBoundsMessage): if self.node: self.node.delete() - -######Object##### + +###### Object##### + + class Box(ba.Actor): - + def __init__(self, position: Sequence[float] = (0, 1, 0), velocity: Sequence[float] = (0, 0, 0), texture: str = 'powerupCurse'): super().__init__() - + shared = SharedObjects.get() - self.dont_collide=ba.Material() + self.dont_collide = ba.Material() self.dont_collide.add_actions( conditions=( - 'they_are_different_node_than_us', + 'they_are_different_node_than_us', ), actions=( ('modify_part_collision', 'collide', False) @@ -1634,13 +1654,13 @@ class Box(ba.Actor): 'color_texture': ba.gettexture(texture), 'model': ba.getmodel('powerup'), 'light_model': ba.getmodel('powerupSimple'), - 'model_scale':4, + 'model_scale': 4, 'body': 'box', - 'body_scale':3, - 'density':9999, - 'damping':9999, - 'gravity_scale':0, + 'body_scale': 3, + 'density': 9999, + 'damping': 9999, + 'gravity_scale': 0, 'reflection': 'soft', 'reflection_scale': [0.25], 'shadow_size': 0.0, - 'materials': [self.dont_collide,]}) \ No newline at end of file + 'materials': [self.dont_collide,]}) From 113490855f79ab28af5fd88bc1a74fa122080fa5 Mon Sep 17 00:00:00 2001 From: SEBASTIAN2059 Date: Sat, 29 Apr 2023 17:16:44 +0000 Subject: [PATCH 74/82] [ci] apply-version-metadata --- plugins/minigames.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/minigames.json b/plugins/minigames.json index bca9635..4be499f 100644 --- a/plugins/minigames.json +++ b/plugins/minigames.json @@ -266,7 +266,12 @@ } ], "versions": { - "1.0.0": null + "1.0.0": { + "api_version": 7, + "commit_sha": "095a773", + "released_on": "29-04-2023", + "md5sum": "7296a71c9ed796ab1f54c2eb5d843bda" + } } } } From 7f84e4911a104e19dc58c496065372471b0aa7e6 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 30 Apr 2023 03:14:06 +0530 Subject: [PATCH 75/82] Correct an external url --- plugins/utilities.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index c1a86a6..33fab5d 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -209,7 +209,7 @@ }, "colorscheme": { "description": "Create custom UI colorschemes!", - "external_url": "https://www.youtube.com/watch?v=qatwWrBAvjc", + "external_url": "https://www.youtube.com/watch?v=G6824StL4eg", "authors": [ { "name": "Rikko", @@ -672,4 +672,4 @@ } } } -} \ No newline at end of file +} From dbbb0ba32cb655875d7918740512fba5fa44c6a3 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 30 Apr 2023 22:24:56 +0530 Subject: [PATCH 76/82] Fix double sounds --- plugin_manager.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/plugin_manager.py b/plugin_manager.py index 2c4664d..dcd74fc 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -104,10 +104,6 @@ async def async_stream_network_response_to_file(request, file, md5sum=None, retr return content -def play_sound(): - ba.playsound(ba.getsound('swish')) - - def partial_format(string_template, **kwargs): for key, value in kwargs.items(): string_template = string_template.replace("{" + key + "}", value) @@ -814,7 +810,7 @@ class PluginWindow(popup.PopupWindow): async def draw_ui(self): # print(ba.app.plugins.active_plugins) - play_sound() + ba.playsound(ba.getsound('swish')) b_text_color = (0.75, 0.7, 0.8) s = 1.25 if _uiscale is ba.UIScale.SMALL else 1.39 if ba.UIScale.MEDIUM else 1.67 width = 400 * s @@ -827,7 +823,7 @@ class PluginWindow(popup.PopupWindow): self._root_widget = ba.containerwidget(size=(width, height), # parent=_ba.get_special_widget( # 'overlay_stack'), - on_outside_click_call=self._ok, + on_outside_click_call=self._cancel, transition=transition, scale=(2.1 if _uiscale is ba.UIScale.SMALL else 1.5 if _uiscale is ba.UIScale.MEDIUM else 1.0), @@ -931,7 +927,7 @@ class PluginWindow(popup.PopupWindow): text_scale=1, label=button3_label) ba.containerwidget(edit=self._root_widget, - on_cancel_call=self._ok) + on_cancel_call=self._cancel) open_pos_x = (390 if _uiscale is ba.UIScale.SMALL else 450 if _uiscale is ba.UIScale.MEDIUM else 440) @@ -1026,7 +1022,10 @@ class PluginWindow(popup.PopupWindow): # ba.containerwidget(edit=self._root_widget, start_button=button3) def _ok(self) -> None: - play_sound() + ba.containerwidget(edit=self._root_widget, transition='out_scale') + + def _cancel(self) -> None: + ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self._root_widget, transition='out_scale') def button(fn): @@ -1193,7 +1192,6 @@ class PluginManager: class PluginSourcesWindow(popup.PopupWindow): def __init__(self, origin_widget): - play_sound() self.selected_source = None self.scale_origin = origin_widget.get_screen_space_center() @@ -1364,7 +1362,7 @@ class PluginSourcesWindow(popup.PopupWindow): self.draw_sources() def _ok(self) -> None: - play_sound() + ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self._root_widget, transition='out_scale') @@ -1399,7 +1397,7 @@ class PluginCategoryWindow(popup.PopupMenuWindow): PluginSourcesWindow(origin_widget=self.root_widget) def _ok(self) -> None: - play_sound() + ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self.root_widget, transition='out_scale') @@ -1773,7 +1771,6 @@ class PluginManagerWindow(ba.Window): PluginWindow(plugin, self._root_widget, lambda: self.draw_plugin_name(plugin)) def show_categories_window(self): - play_sound() PluginCategoryWindow( self.plugin_manager.categories.keys(), self.selected_category, @@ -1813,7 +1810,6 @@ class PluginManagerWindow(ba.Window): class PluginManagerSettingsWindow(popup.PopupWindow): def __init__(self, plugin_manager, origin_widget): - play_sound() self._plugin_manager = plugin_manager self.scale_origin = origin_widget.get_screen_space_center() self.settings = ba.app.config["Community Plugin Manager"]["Settings"].copy() @@ -2020,7 +2016,7 @@ class PluginManagerSettingsWindow(popup.PopupWindow): self._update_button.delete() def _ok(self) -> None: - play_sound() + ba.playsound(ba.getsound('swish')) ba.containerwidget(edit=self._root_widget, transition='out_scale') From c902cebd6e5fc5fae6813aed4e104fa04495fb61 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 30 Apr 2023 16:56:47 +0000 Subject: [PATCH 77/82] [ci] apply-version-metadata --- plugins/utilities.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/utilities.json b/plugins/utilities.json index 33fab5d..b10844f 100644 --- a/plugins/utilities.json +++ b/plugins/utilities.json @@ -672,4 +672,4 @@ } } } -} +} \ No newline at end of file From c81e3a6af76995ef6d1fbf717d2ae6d12fcaf912 Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 30 Apr 2023 22:33:01 +0530 Subject: [PATCH 78/82] Set current tag dynamically --- plugin_manager.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugin_manager.py b/plugin_manager.py index dcd74fc..e62b967 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -26,6 +26,8 @@ _uiscale = ba.app.ui.uiscale PLUGIN_MANAGER_VERSION = "0.3.1" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" +# Current tag can be changed to "staging" or any other branch in +# plugin manager repo for testing purpose. CURRENT_TAG = "main" INDEX_META = "{repository_url}/{content_type}/{tag}/index.json" HEADERS = { @@ -308,8 +310,11 @@ class Category: async def fetch_metadata(self): if self._metadata is None: + # Let's keep depending on the "main" branch for 3rd party sources + # even if we're using a different branch of plugin manager's repository. + tag = "main" if self.is_3rd_party else CURRENT_TAG request = urllib.request.Request( - self.meta_url.format(content_type="raw", tag=CURRENT_TAG), + self.meta_url.format(content_type="raw", tag=tag), headers=self.request_headers, ) response = await async_send_network_request(request) From 7cf7f7b6d1b66aa7b83c3631c88856a6db0e644c Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 30 Apr 2023 22:45:54 +0530 Subject: [PATCH 79/82] Resolve spaces to underscores when searching for plugins --- plugin_manager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin_manager.py b/plugin_manager.py index e62b967..fec10c8 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -1680,6 +1680,8 @@ class PluginManagerWindow(ba.Window): draw_controller=controller_button) def search_term_filterer(self, plugin, search_term): + # This helps resolve "plugin name" to "plugin_name". + search_term = search_term.replace(" ", "_") if search_term in plugin.name: return True if search_term in plugin.info["description"].lower(): From 789f95f6b1e8713e2511c138a3df853a414d63dd Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 30 Apr 2023 22:46:21 +0530 Subject: [PATCH 80/82] Bump to v0.3.2 --- index.json | 3 ++- plugin_manager.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index 8805e0f..db12a23 100644 --- a/index.json +++ b/index.json @@ -1,6 +1,7 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { + "0.3.2": null, "0.3.1": { "api_version": 7, "commit_sha": "0b856ba", @@ -80,4 +81,4 @@ "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "https://github.com/{repository}/{content_type}/{tag}/category.json" -} \ No newline at end of file +} diff --git a/plugin_manager.py b/plugin_manager.py index fec10c8..dda2d68 100644 --- a/plugin_manager.py +++ b/plugin_manager.py @@ -24,7 +24,7 @@ _env = _ba.env() _uiscale = ba.app.ui.uiscale -PLUGIN_MANAGER_VERSION = "0.3.1" +PLUGIN_MANAGER_VERSION = "0.3.2" REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager" # Current tag can be changed to "staging" or any other branch in # plugin manager repo for testing purpose. From c8a6eb7eac61c7002560e6750f41fd416ddcc755 Mon Sep 17 00:00:00 2001 From: rikkolovescats Date: Sun, 30 Apr 2023 17:16:59 +0000 Subject: [PATCH 81/82] [ci] apply-version-metadata --- index.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/index.json b/index.json index db12a23..3a1b001 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,12 @@ { "plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py", "versions": { - "0.3.2": null, + "0.3.2": { + "api_version": 7, + "commit_sha": "789f95f", + "released_on": "30-04-2023", + "md5sum": "ff679f8411e426e5e4e92a2f958eec02" + }, "0.3.1": { "api_version": 7, "commit_sha": "0b856ba", @@ -81,4 +86,4 @@ "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugins/maps.json" ], "external_source_url": "https://github.com/{repository}/{content_type}/{tag}/category.json" -} +} \ No newline at end of file From a107fe7631ff70191d87c4bfaa046673b8469ffb Mon Sep 17 00:00:00 2001 From: Rikko Date: Sun, 30 Apr 2023 22:54:39 +0530 Subject: [PATCH 82/82] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9da6511..5249304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ## Plugin Manager (dd-mm-yyyy) +### 0.3.2 (30-04-2023) + +- Fix sometimes same sound would repeat twice when pressing a button. +- Low key attempt to experiment with staging branch by changing current tag in `plugin_manager.py`. +- Assume underscores as spaces when searching for plugins in game. + ### 0.3.1 (04-03-2023) - Resize the plugin window to limit the overlapping of plugin description.